Sunday, February 28, 2010

Shatranj – Convert to Control (3 of 3): TemplateBinding, Styles & Triggers

 

So we’ve a background color issue!  Let’s call Snoop to rescue:

SnoopShowsBackgroundSetByStyleCorrectly

Snoop shows that the background of square is – correctly – set to LightBlue by Style!  Still it doesn’t show up on the UI.  That’s simple, because any property not set by Template is replaced by the defaults!

Since I couldn’t figure out how to set the Background on the RadioButton from within ControlTemplate, the best thing I could do was:

<Grid

      Background="{Binding Path=Background,

      RelativeSource={RelativeSource Mode=FindAncestor,

      AncestorType={x:Type Shatranj:BoardSquareView}}}"

>

It worked!  Then:

<Grid Background="{TemplateBinding Background}">

One problem down!  Let’s refactor the code to distinguish between two players.  Their squares must belong to different groups so they can be selected independently.

Let’s refactor the code to distinguish between two players.  Their squares must belong to different groups so they can be selected independently:

    1 <RadioButton x:Class="Shatranj.BoardSquareView" 

    2             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    3             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    4             xmlns:Shatranj="clr-namespace:Shatranj" >

    5 

    6     <RadioButton.Resources>

    7         <Shatranj:ForceToGroupNameConverter x:Key="ForceToGroupNameConverter"/>

 

 

Remember, each BoardSquareView has its DataContext set to a “BoardSquare” object.  BoardSquare object among other things has a CurrentPiece property (of type ChessPiece), which in turn has a property called ‘Force’:

 

 

ChessPieceSquare

 

 

 

ForceToGroupNameCoverter.cs has three pertinent lines:

 

   16             var square = value as BoardSquare;

   17             if(square == null || square.CurrentPiece == null) return "None";

   18             return Enum.GetName(typeof (Army), square.CurrentPiece.Force);

This divides the whole board into three groups.  One with White pieces, one with Black pieces and one another with no pieces (Grouped into ‘None’).

  1. When it’s a player’s turn (playing White/Black), the player should only be able to select one of his/her piece for making the move
  2. This also applies to the opponent
  3. When any of the empty squares are captured by either players, that square is owned by the piece occupying it.

Here’s the final version:

    1 <RadioButton x:Class="Shatranj.BoardSquareView" 

    2             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    3             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    4             xmlns:Shatranj="clr-namespace:Shatranj" >

    5     <RadioButton.Resources>

    6         <Shatranj:ForceToGroupNameConverter x:Key="ForceToGroupNameConverter"/>

    7         <Style TargetType="{x:Type Shatranj:BoardSquareView}">

    8             <Setter Property="IsChecked" Value="false"/>

    9             <Setter Property="Background" Value="{Binding Converter={StaticResource LocationToColorConverter}, Mode=OneWay}"/>

   10             <Setter Property="GroupName" Value="{Binding Converter={StaticResource ForceToGroupNameConverter}}"/>

   11             <Setter Property="Template">

   12                 <Setter.Value>

   13                     <ControlTemplate TargetType="{x:Type Shatranj:BoardSquareView}">

   14                         <ControlTemplate.Resources>

   15                             <Style TargetType="RadioButton">

   16                                 <Setter Property="Background"

   17                                        Value="{Binding Converter={StaticResource LocationToColorConverter}, Mode=OneWay}"/>

   18                             </Style>

   19                             <Shatranj:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />

   20                         </ControlTemplate.Resources>

   21 

   22                         <Grid Background="{TemplateBinding Background}">

   23                                 <Grid.RowDefinitions>

   24                                     <RowDefinition Height="0.200*" />

   25                                     <RowDefinition Height="0.800*" />

   26                                 </Grid.RowDefinitions>

   27                                 <Grid.ColumnDefinitions>

   28                                     <ColumnDefinition />

   29                                 </Grid.ColumnDefinitions>

   30                                 <Border x:Name="Border" Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" />

   31                                 <Viewbox Grid.Row="0" Grid.Column="0"

   32                                         HorizontalAlignment="Right" VerticalAlignment="Stretch">

   33                                     <TextBlock FontSize="12"

   34                                               FontFamily="Consolas"

   35                                               Text="{Binding Path=AlgebraicIdentity, Mode=OneWay}" />

   36                                 </Viewbox>

   37                                 <Viewbox Grid.RowSpan="2" Grid.Row="0"

   38                                         HorizontalAlignment="Center" VerticalAlignment="Center">

   39                                     <TextBlock FontFamily="Chess Cases"

   40                                               Margin="3,3,3,3"

   41                                               Text="{Binding Path=CurrentPiece.AltChar, Mode=OneWay}" />

   42                                 </Viewbox>

   43 

   44                                 <Ellipse MaxHeight="30" MaxWidth="30" MinHeight="10" MinWidth="10"

   45                                         Grid.Row="0" Grid.RowSpan="2"

   46                                         Visibility="{Binding IsHit, Converter={StaticResource BoolToVisibilityConverter}}" >

   47                                     <Ellipse.Fill>

   48                                         <SolidColorBrush Color="Black" Opacity="0.5"/>

   49                                     </Ellipse.Fill>

   50                                 </Ellipse>

   51 

   52                             </Grid>

   53 

   54                         <ControlTemplate.Triggers>

   55                                 <Trigger Property="IsChecked" Value="true">

   56                                     <Setter Property="Background" Value="DarkBlue"/>

   57                                     <Setter Property="Foreground" Value="LightGreen" />

   58                                     <Setter TargetName="Border" Property="BorderBrush" Value="LightGreen"/>

   59                                     <Setter TargetName="Border" Property="BorderThickness" Value="2"/>

   60                                 </Trigger>

   61                                 <Trigger Property="IsMouseOver" Value="true">

   62                                     <Setter Property="Foreground" Value="Red" />

   63                                     <Setter Property="Background" Value="Black"/>

   64                                     <Setter TargetName="Border" Property="BorderBrush" Value="Red"/>

   65                                     <Setter TargetName="Border" Property="BorderThickness" Value="2"/>

   66                                 </Trigger>

   67                         </ControlTemplate.Triggers>

   68                     </ControlTemplate>

   69                 </Setter.Value>

   70             </Setter>

   71         </Style>

   72     </RadioButton.Resources>

   73 </RadioButton>

ShatranjChessBoardWithControlTemplate

 

Yes, WPF is nothing short of revolutionary! 

No comments: