I recently designed a UserControl that handles desired functionality and enables you to get/set a Direction property indicating the current position. I'm sure the code could be refined a little better but here it is:
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>
Direction Enum:
namespace MyNamespace {
public Direction {
N,
NE,
NW,
Origin,
E,
W,
SW,
SE,
S
}
}
ParseEnum Extension:
public static T ParseEnum<T>(this string ToParse)
{
return (T)Enum.Parse(typeof(T), ToParse, true);
}
And finally, the result looks like this:
UniformGrid
). The wrapper element should cut off the shifted part easily. This can even be improved to add translation effect. The disadvantage here is it requires to know the fixed size of the square beforehand. That's of course acceptable, we should not make the square's size dynamic at runtime in this case. – King KingGrid
requires you to declare 3 rowdefinitions and 3 column defintions or some other composite layout (such as use 3 rowdefinitions with each StackPanel or DockPanel in each row, ...). It is of course more complicated. In code behind you even need to set the attached propertyGrid.Row
orGrid.Column
. When usingUniformGrid
, you simply useChildren.Add
to add items in the correct order. – King King