模仿 Photoshop Canvas 大小对话框功能的算法

Algorithm to mimic Canvas Size dialog functionality from Photoshop

我正在使用C#,想知道是否有特殊的算法可以实现下图中的功能。

当您单击一个按钮时,所有其他按钮都必须移动到相邻的(一些不可见的)单元格中,指示您想要进入的方向。

我只能想到使用具有 9 个图像控件的网格并为每个单击的图像创建一个事件,但这对于看似如此简单的东西来说似乎有点过分。

编辑

点击按钮的行为:

按钮 1 -> 将所有单元格向上和向左移动 1 个单元格

按钮 2 -> 将所有单元格向上移动 1 个单元格

按钮 3 -> 将所有单元格向上和向右移动 1 个单元格

按钮 4 -> 将所有单元格向左移动 1 个单元格

按钮 5 -> 没有任何反应

按钮 6 -> 将所有单元格向右移动 1 个单元格

按钮 7 -> 将所有单元格向下和向左移动 1 个单元格

按钮 8 -> 将所有单元格向下移动 1 个单元格

按钮 9 -> 将所有单元格向下和向右移动 1 个单元格

我最近设计了一个 UserControl,它可以处理所需的功能并使您能够 get/set 指示当前位置的方向 属性。我确信代码可以改进得更好一点,但这里是:

DirectionPad.xaml.cs:

using System.Windows;
using System.Windows.Controls;

namespace MyNamespace
{
    public partial class DirectionPad : UserControl
    {
        #region Dependency Properties

        public static DependencyProperty DirectionProperty = DependencyProperty.Register("Direction", typeof(Direction), typeof(DirectionPad), new FrameworkPropertyMetadata(Direction.Origin, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnDirectionChanged));
        public Direction Direction
        {
            get
            {
                return (Direction)GetValue(DirectionProperty);
            }
            set
            {
                SetValue(DirectionProperty, value);
            }
        }
        private static void OnDirectionChanged(DependencyObject Object, DependencyPropertyChangedEventArgs e)
        {
            DirectionPad Pad = Object as DirectionPad;
            Pad.SetPositions(Pad.Direction);
        }

        #endregion

        #region DirectionPad

        public DirectionPad()
        {
            InitializeComponent();
        }

        #endregion

        #region Methods

        public void SetPositions(Direction Direction)
        {
            int StartRow = 0, StartColumn = 0;
            switch (Direction)
            {
                case Direction.NW:
                    StartRow = 0;
                    StartColumn = 0;
                    break;
                case Direction.N:
                    StartRow = 0;
                    StartColumn = 1;
                    break;
                case Direction.NE:
                    StartRow = 0;
                    StartColumn = 2;
                    break;
                case Direction.W:
                    StartRow = 1;
                    StartColumn = 0;
                    break;
                case Direction.Origin:
                    StartRow = 1;
                    StartColumn = 1;
                    break;
                case Direction.E:
                    StartRow = 1;
                    StartColumn = 2;
                    break;
                case Direction.SW:
                    StartRow = 2;
                    StartColumn = 0;
                    break;
                case Direction.S:
                    StartRow = 2;
                    StartColumn = 1;
                    break;
                case Direction.SE:
                    StartRow = 2;
                    StartColumn = 2;
                    break;
                //Direction.Origin
            }
            int i = StartRow, j = StartColumn;
            foreach (UIElement CurrentButton in this.Grid.Children)
            {
                if (!(CurrentButton is Button)) continue;
                if (j < StartColumn + 3)
                {
                    Grid.SetRow(CurrentButton, i);
                    Grid.SetColumn(CurrentButton, j++);
                    if (j == (StartColumn + 3))
                    {
                        j = StartColumn;
                        i++;
                    }
                }
            }
        }

        public void ShiftPositions(Direction Direction, int Row, int Column)
        {
            bool ShiftUp = false, ShiftDown = false, ShiftLeft = false, ShiftRight = false;
            switch (Direction)
            {
                case Direction.NW:
                    if (Column - 1 < 0 || Row - 1 < 0) return;
                    ShiftUp = true;
                    ShiftLeft = true;
                    break;
                case Direction.N:
                    if (Row - 1 < 0) return;
                    ShiftUp = true;
                    break;
                case Direction.NE:
                    if (Column + 1 > 4 || Row - 1 < 0) return;
                    ShiftUp = true;
                    ShiftRight = true;
                    break;
                case Direction.W:
                    if (Column - 1 < 0) return;
                    ShiftLeft = true;
                    break;
                case Direction.E:
                    if (Column + 1 > 4) return;
                    ShiftRight = true;
                    break;
                case Direction.SW:
                    if (Column - 1 < 0 || Row + 1 > 4) return;
                    ShiftDown = true;
                    ShiftLeft = true;
                    break;
                case Direction.S:
                    if (Row + 1 > 4) return;
                    ShiftDown = true;
                    break;
                case Direction.SE:
                    if (Column + 1 > 4 || Row + 1 > 4) return;
                    ShiftDown = true;
                    ShiftRight = true;
                    break;
                //Direction.Origin
                default:
                    return;
            }
            foreach (UIElement CurrentButton in this.Grid.Children)
            {
                if (CurrentButton is Button)
                {
                    int CurrentRow = Grid.GetRow(CurrentButton), CurrentColumn = Grid.GetColumn(CurrentButton);
                    Grid.SetRow(CurrentButton, ShiftUp ? CurrentRow - 1 : ShiftDown ? CurrentRow + 1 : CurrentRow);
                    Grid.SetColumn(CurrentButton, ShiftLeft ? CurrentColumn - 1 : ShiftRight ? CurrentColumn + 1 : CurrentColumn);
                }
            }
            this.UpdateDirection();
        }

        public void UpdateDirection()
        {
            if (Grid.GetRow(this.OriginButton) == 1)
            {
                if (Grid.GetColumn(this.OriginButton) == 1)
                {
                    this.Direction = Direction.NW;
                }
                else if (Grid.GetColumn(this.OriginButton) == 2)
                {
                    this.Direction = Direction.N;
                }
                else if (Grid.GetColumn(this.OriginButton) == 3)
                {
                    this.Direction = Direction.NE;
                }
            }
            else if (Grid.GetRow(this.OriginButton) == 2)
            {
                if (Grid.GetColumn(this.OriginButton) == 1)
                {
                    this.Direction = Direction.W;
                }
                else if (Grid.GetColumn(this.OriginButton) == 2)
                {
                    this.Direction = Direction.Origin;
                }
                else if (Grid.GetColumn(this.OriginButton) == 3)
                {
                    this.Direction = Direction.E;
                }
            }
            else if (Grid.GetRow(this.OriginButton) == 3)
            {
                if (Grid.GetColumn(this.OriginButton) == 1)
                {
                    this.Direction = Direction.SW;
                }
                else if (Grid.GetColumn(this.OriginButton) == 2)
                {
                    this.Direction = Direction.S;
                }
                else if (Grid.GetColumn(this.OriginButton) == 3)
                {
                    this.Direction = Direction.SE;
                }
            }
        }

        #endregion

        #region Events

        private void _Click(object sender, RoutedEventArgs e)
        {
            FrameworkElement Element = sender as FrameworkElement;
            int Row = Grid.GetRow(Element);
            int Column = Grid.GetColumn(Element);
            string Tag = Element.Tag.ToString();
            this.ShiftPositions(Tag.ParseEnum<Direction>(), Row, Column);
        }

        #endregion
    }
}

DirectionPad.xaml:

<UserControl x:Class="MyNamespace.DirectionPad"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Height="Auto"
        Width="Auto">
    <Grid x:Name="Grid" ClipToBounds="True">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="0"/>
            <ColumnDefinition Width="24"/>
            <ColumnDefinition Width="24"/>
            <ColumnDefinition Width="24"/>
            <ColumnDefinition Width="0"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="0"/>
            <RowDefinition Height="24"/>
            <RowDefinition Height="24"/>
            <RowDefinition Height="24"/>
            <RowDefinition Height="0"/>
        </Grid.RowDefinitions>
        <Button Grid.Row="1" Grid.Column="1" Tag="NW" ToolTip="Top Left" Click="_Click"/>
        <Button Grid.Row="1" Grid.Column="2" Tag="N" ToolTip="Top" Click="_Click"/>
        <Button Grid.Row="1" Grid.Column="3" Tag="NE" ToolTip="Top Right" Click="_Click"/>
        <Button Grid.Row="2" Grid.Column="1" Tag="E" ToolTip="Left" Click="_Click"/>
        <Button Grid.Row="2" Grid.Column="2" Tag="Origin" ToolTip="Origin" Click="_Click"/>
        <Button Grid.Row="2" Grid.Column="3" Tag="W" ToolTip="Right" Click="_Click"/>
        <Button Grid.Row="3" Grid.Column="1" Tag="SW" ToolTip="Bottom Left" Click="_Click"/>
        <Button Grid.Row="3" Grid.Column="2" Tag="S" ToolTip="Bottom" Click="_Click"/>
        <Button Grid.Row="3" Grid.Column="3" Tag="SE" ToolTip="Bottom Right" Click="_Click"/>
    </Grid>
</UserControl>

方向枚举:

namespace MyNamespace {
    public Direction {
        N, 
        NE, 
        NW, 
        Origin, 
        E, 
        W, 
        SW, 
        SE, 
        S
    }
}

ParseEnum 扩展:

public static T ParseEnum<T>(this string ToParse)
{
    return (T)Enum.Parse(typeof(T), ToParse, true);
}

最后,结果如下所示: