模仿 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);
}
最后,结果如下所示:
我正在使用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);
}
最后,结果如下所示: