Posting this as an answer because the OP asked for it:
<Window x:Class="MiscSamples.GridRobot"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="GridRobot" Height="500" Width="600">
<DockPanel>
<DockPanel DockPanel.Dock="Top">
<TextBlock Text="Size:" Margin="2" DockPanel.Dock="Left"/>
<TextBox Text="{Binding Size}" IsReadOnly="True" DockPanel.Dock="Left" Margin="2" Width="50"/>
<Slider Maximum="20" Minimum="2" Value="{Binding Size}"/>
</DockPanel>
<StackPanel DockPanel.Dock="Left" Width="100" Margin="2">
<TextBlock Text="Route:" TextAlignment="Center" FontWeight="Bold"/>
<ItemsControl ItemsSource="{Binding Route}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock TextAlignment="Center">
<TextBlock.Text>
<MultiBinding StringFormat="{}{0:D2},{1:D2}">
<Binding Path="Row"/>
<Binding Path="Column"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
<Grid>
<ItemsControl ItemsSource="{Binding Squares}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="{Binding Size}" Columns="{Binding Size}"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderBrush="DarkGray" BorderThickness="1">
<Button Command="{Binding DataContext.GoToCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
CommandParameter="{Binding}">
<Button.Template>
<ControlTemplate>
<Border Background="#05FFFFFF">
<Viewbox>
<TextBlock Text="{Binding PathIndex}"
TextAlignment="Center" VerticalAlignment="Center"/>
</Viewbox>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Canvas>
<!-- I was about to add the Robot Peg here and animate it -->
</Canvas>
</Grid>
</DockPanel>
</Window>
Code Behind:
public partial class GridRobot : Window
{
public GridRobot()
{
InitializeComponent();
DataContext = new GridRobotViewModel();
}
}
View Model:
public class GridRobotViewModel: PropertyChangedBase
{
private int _size;
public int Size
{
get { return _size; }
set
{
_size = value;
OnPropertyChanged("Size");
CreateItems();
}
}
private ObservableCollection<GridItem> _squares;
public ObservableCollection<GridItem> Squares
{
get { return _squares ?? (_squares = new ObservableCollection<GridItem>()); }
}
private ObservableCollection<GridItem> _route;
public ObservableCollection<GridItem> Route
{
get { return _route ?? (_route = new ObservableCollection<GridItem>()); }
}
private void CreateItems()
{
Squares.Clear();
Route.Clear();
for (int i = 0; i < Size; i++)
{
for (int j = 0; j < Size; j++)
{
Squares.Add(new GridItem() {Row = i, Column = j});
}
}
}
private Command<GridItem> _goToCommand;
public Command<GridItem> GoToCommand
{
get { return _goToCommand ?? (_goToCommand = new Command<GridItem>(Goto){IsEnabled = true}); }
}
private void Goto(GridItem item)
{
if (item.PathIndex == null)
{
item.PathIndex = Squares.Max(x => x.PathIndex ?? 0) + 1;
Route.Add(item);
}
}
}
Data Item:
public class GridItem: PropertyChangedBase
{
public int Row { get; set; }
public int Column { get; set; }
private int? _pathIndex;
public int? PathIndex
{
get { return _pathIndex; }
set
{
_pathIndex = value;
OnPropertyChanged("PathIndex");
}
}
}
Support Classes for MVVM:
public class PropertyChangedBase:INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
Application.Current.Dispatcher.BeginInvoke((Action) (() =>
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}));
}
}
public class Command<T>: ICommand
{
public Action<T> Action { get; set; }
public void Execute(object parameter)
{
if (Action != null && parameter is T)
Action((T)parameter);
}
public bool CanExecute(object parameter)
{
return IsEnabled;
}
private bool _isEnabled;
public bool IsEnabled
{
get { return _isEnabled; }
set
{
_isEnabled = value;
if (CanExecuteChanged != null)
CanExecuteChanged(this, EventArgs.Empty);
}
}
public event EventHandler CanExecuteChanged;
public Command(Action<T> action)
{
Action = action;
}
}
Result:
- Just copy and paste my code in a
File -> New Project -> WPF Application
and see the results for yourself.
- You said 10 x 10, but I went a step further and added a Slider to make the grid size customizable.
- Clicking on any cell will make it be queued as part of the Route.
- Fully Resolution Independent.
- I was about to start putting some really nice stuff on it (animations, robot movement represented by an ellipse, Lines for the Path, etc).
- Forget winforms, it's useless.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…