I'm currently creating a connect-4 game in order to learn WPF & XAML. I made the UI but I'm stuck on a problem.
Below you can see an extract of the XAML code concerning the board of the game :
<Grid DockPanel.Dock="Bottom" Background="#FF1506A4" MouseLeftButtonUp="Grid_MouseLeftButtonUp_1">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
... 5 more rows
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
... 6 more columns
</Grid.ColumnDefinitions>
<Ellipse Grid.Row="0" Grid.Column="0" Fill="White" Margin="8"/>
... 41 more ellipses
</Grid>
The board is stored in an array of Token (an enumeration with Empty, Red and Yellow) in the class GameState.
The colors of the Ellipses are provided using the class SolidBrushColor.
My problem is that I don't know how to change the color of the ellipses according to the game model.
I guess I should use data binding but I have to convert colors from the type Token to the type SolidBrushColor before binding the data. I think it could be achieved using some DataObjectProvider objects but it seems over complicated to create 42 DataObjectProvider objects for such a simple task...
So what would be the correct solution according to the best pratices ?
You'll want to use some sort of ViewModel at the backend, and then leverage DataBinding.
Assuming the following (contrived) ViewModel structure that represents a Connect Four board.
BoardViewModel.cs
public class BoardViewModel
{
public BoardViewModel()
{
var rand = new Random();
Squares = Enumerable
.Range(1, 42)
.Select(a => new SquareViewModel() { Token = rand.Next(-1, 2) })
.ToList();
}
public List<SquareViewModel> Squares { get; set; }
}
SquareViewModel.cs
public class SquareViewModel : INotifyPropertyChanged
{
private int _Token;
public int Token
{
get
{
return _Token;
}
set
{
if (_Token.Equals(value)) return;
_Token = value;
RaisePropertyChanged("Token");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property)
{
var handlers = PropertyChanged;
if (handlers != null)
{
var args = new PropertyChangedEventArgs(property);
handlers(this, args);
}
}
}
Then you can use the following XAML to represent your board.
MainWindow.xaml
<Window
x:Class="ConnectFour.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
xmlns:ConnectFour="clr-namespace:ConnectFour"
Title="MainWindow" Height="350" Width="525"
d:DataContext="{d:DesignInstance Type={x:Type ConnectFour:BoardViewModel}, IsDesignTimeCreatable=True}">
<ItemsControl
ItemsSource="{Binding Squares}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Ellipse
Stroke="Magenta">
<Ellipse.Style>
<Style TargetType="Ellipse">
<Style.Triggers>
<DataTrigger Binding="{Binding Token}" Value="0">
<Setter Property="Fill" Value="Black" />
</DataTrigger>
<DataTrigger Binding="{Binding Token}" Value="1">
<Setter Property="Fill" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
</Ellipse>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid IsItemsHost="True" Columns="6" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Window>
The important things to note are:
At run-time, you will want to set the DataContext of your board View to a real instance of the BoardViewModel (or whatever your ViewModel is called), but the basic idea of how to change the colour of the tokens is present.