Skip to main content

A board game in MVVM Part 3 - The View

This is a continuation of my experience creating a quick board game in silverlight 5
Original Post
Part 1 - The Model
Part 2 - The AI
Play the Game

An important thing to keep in mind when looking at the UI here is that I'm following the MVVM design pattern. I didn't want to be manipulating anything in code-behind. The code-behind for the entire game board here is simply:

  1. namespace Viking
  2. {
  3.     using System.Windows.Controls;
  4.  
  5.     public partial class MainPage : UserControl
  6.     {
  7.         public MainPage()
  8.         {
  9.             InitializeComponent();
  10.         }
  11.     }
  12. }

That's IT! Nothing else. Seriously. If you haven't worked with Silverlight and MVVM much this might seem surprising. The View is entirely XAML and binding.

To start, I added my xaml namespaces. I'm using the Silverlight Toolkit and I've got my model and a couple other things separated into a separate Silverlight Library. The purpose of the separate DLL is in case I ever want to redo this project in 3D, that way I can reuse my code.

  1. <UserControl 
  2.     ...
  3.     xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit"
  4.     xmlns:local="clr-namespace:Viking"
  5.     xmlns:library="clr-namespace:Viking;assembly=Viking.Library"
  6.     ... >

I'm not going to show all the XAML in this blog post but merely a few points that people might find interesting. I'll cover the ViewModel in a later post, but for now here's how it's instantiated:

  1.     <UserControl.DataContext>
  2.         <local:MainViewModel />
  3.     </UserControl.DataContext>

First of all is the board. Its simplicity may be surprising to somebody who hasn't seen the power of Silverlight and MVVM before. There's no images here, no long complicated markup. It's short and concise as far as all that functionality goes.

  1. <Border BorderBrush="Black" BorderThickness="1">
  2.     <ItemsControl ItemsSource="{Binding Game.Board.Squares}">
  3.         <ItemsControl.ItemsPanel>
  4.             <ItemsPanelTemplate>
  5.                 <toolkit:WrapPanel Height="657" Width="657" />
  6.             </ItemsPanelTemplate>
  7.         </ItemsControl.ItemsPanel>
  8.         <ItemsControl.ItemTemplate>
  9.             <DataTemplate>
  10.                 <Border Width="73" Height="73" BorderThickness="1" BorderBrush="Black" Background="White">
  11.                     <Grid>
  12.                         <Rectangle HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Fill="BlanchedAlmond" Visibility="{Binding IsStartPosition, Converter={StaticResource BoolToVisibilityConverter}}" />
  13.                         <Rectangle HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Fill="Brown" Visibility="{Binding IsRestricted, Converter={StaticResource BoolToVisibilityConverter}}" />
  14.                         <Border Visibility="{Binding Occupant, Converter={StaticResource HideOnNullConverter}}">
  15.                             <Rectangle HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Fill="#6600FF00" Visibility="{Binding Occupant.IsActive, Converter={StaticResource BoolToVisibilityConverter}}" />
  16.                         </Border>
  17.                         <Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Command="{Binding DataContext.MakeMoveCommand, RelativeSource={RelativeSource AncestorType=local:MainPage}}" CommandParameter="{Binding}">
  18.                             <Button.Template>
  19.                                 <ControlTemplate>
  20.                                     <Rectangle HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Fill="#2200FF00" Visibility="{Binding IsValidMove, Converter={StaticResource BoolToVisibilityConverter}}" />
  21.                                 </ControlTemplate>
  22.                             </Button.Template>
  23.                         </Button>
  24.                         <Border Visibility="{Binding Occupant, Converter={StaticResource HideOnNullConverter}}">
  25.                             <Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Command="{Binding DataContext.ActivatePieceCommand, RelativeSource={RelativeSource AncestorType=local:MainPage}}" CommandParameter="{Binding Occupant}" IsEnabled="{Binding Occupant.IsMoveable}">
  26.                                 <Button.Template>
  27.                                     <ControlTemplate>
  28.                                         <Ellipse HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Stroke="{Binding Occupant, Converter={StaticResource KingStrokeConverter}}" StrokeThickness="{Binding Occupant, Converter={StaticResource KingStrokeConverter}}" Fill="{Binding Occupant, Converter={StaticResource PlayerColorConverter}}">
  29.                                             <Ellipse.Effect>
  30.                                                 <DropShadowEffect Opacity=".5" ShadowDepth="3" />
  31.                                             </Ellipse.Effect>
  32.                                         </Ellipse>
  33.                                     </ControlTemplate>
  34.                                 </Button.Template>
  35.                             </Button>
  36.                         </Border>
  37.                     </Grid>
  38.                     <Border.Effect>
  39.                         <DropShadowEffect />
  40.                     </Border.Effect>
  41.                 </Border>
  42.             </DataTemplate>
  43.         </ItemsControl.ItemTemplate>
  44.     </ItemsControl>
  45. </Border>

That's all there is to the board itself. It's a bunch of templated items within a WrapPanel. The ItemsSource of the ItemsControl is bound to the Game.Board.Squares collection. If you look inside the DataTemplate for each square you'll see:

  • A rectangle bound to IsStartPosition using a BoolToVisibilityConverter - Represents the lighter colored squares
  • A rectangle bound to IsRestricted using a BoolToVisibilityConverter - Represents the center, dark square
  • A border bound to Occupant using a HideOnNullConverter surrounding a Rectange bound to Occupant.IsActive - Represents an active piece (dark green when you click on it)
  • A button bound to IsValidMove using a BoolToVisibilityConverter - Represents possible moves (light green after activating a piece)
  • A border bound to Occupant using a HideOnNullConverter surrounding a button with IsEnabled bound to IsMoveable surrounding an Ellipse using various color converters to symbolize the color of the player, and whether the piece is a king.

The bindings here automatically update what is visible/enabled based upon the PropertyChanged event of the object it is bound to. The ItemsControl is a container for multiple objects that utilize a template, and the ItemsPanel is the parent panel that the items are laid out upon.

The AI controls reuse the same converters and bind in a few commands:

  1. <Grid HorizontalAlignment="Stretch" Margin="0 10" Height="25">
  2.     <Grid.Resources>
  3.         <Style TargetType="TextBlock">
  4.             <Setter Property="FontWeight" Value="Bold" />
  5.             <Setter Property="FontSize" Value="14" />
  6.             <Setter Property="VerticalAlignment" Value="Center" />
  7.         </Style>
  8.     </Grid.Resources>
  9.     <Border Margin="0" CornerRadius="3 0 0 3" BorderThickness="0" Background="{Binding Game.CurrentPlayer, Converter={StaticResource PlayerColorConverter}}" Opacity=".15" />
  10.     <Border Margin="0" CornerRadius="3" BorderThickness="1" Background="Transparent" BorderBrush="{Binding Game.CurrentPlayer, Converter={StaticResource PlayerColorConverter}}" />
  11.     <StackPanel Orientation="Horizontal">
  12.         <Grid Width="8" VerticalAlignment="Stretch" Margin="0 0 5 0">
  13.             <Border x:Name="FillRectangle" BorderBrush="Navy" BorderThickness="0" Background="{Binding Game.CurrentPlayer, Converter={StaticResource PlayerColorConverter}}" Width="8" Margin="0" CornerRadius="3 0 0 3" />
  14.             <Border x:Name="FillShadingRectangle" Width="8" Margin="0" CornerRadius="3 0 0 3">
  15.                 <Border.Background>
  16.                     <LinearGradientBrush StartPoint="1,1" EndPoint="0,0">
  17.                         <GradientStop Color="#AA010000" Offset="0" />
  18.                         <GradientStop Color="Transparent" Offset=".5" />
  19.                         <GradientStop Color="#BBFFFFFF" Offset="1" />
  20.                     </LinearGradientBrush>
  21.                 </Border.Background>
  22.             </Border>
  23.         </Grid>
  24.         <TextBlock Text="{Binding Game.CurrentPlayer, StringFormat='Current Player: {0}'}" Margin="0 0 10 0" />
  25.     </StackPanel>
  26.     <Button FontSize="14" Cursor="Hand" Command="{Binding RestartGameCommand}" HorizontalAlignment="Right" Margin="2" Padding="10 0">
  27.         <Button.Template>
  28.             <ControlTemplate>
  29.                 <Grid HorizontalAlignment="Stretch">
  30.                     <Border x:Name="FillRectangle" BorderBrush="#555" BorderThickness="2 0 0 0" Background="{Binding Game.CurrentPlayer, Converter={StaticResource PlayerColorConverter}}" Margin="0" CornerRadius="0 3 3 0" />
  31.                     <Border x:Name="FillShadingRectangle" Margin="0" CornerRadius="0 3 3 0">
  32.                         <Border.Background>
  33.                             <LinearGradientBrush StartPoint="1,1" EndPoint="0,0">
  34.                                 <GradientStop Color="#AA010000" Offset="0" />
  35.                                 <GradientStop Color="Transparent" Offset=".25" />
  36.                                 <GradientStop Color="#BBFFFFFF" Offset="1" />
  37.                             </LinearGradientBrush>
  38.                         </Border.Background>
  39.                     </Border>
  40.                     <ContentPresenter Margin="10 1" />
  41.                 </Grid>
  42.             </ControlTemplate>
  43.         </Button.Template>
  44.         Restart
  45.     </Button>
  46. </Grid>
  47. <Grid>
  48.     <Grid.ColumnDefinitions>
  49.         <ColumnDefinition Width="*" />
  50.         <ColumnDefinition Width="*" />
  51.     </Grid.ColumnDefinitions>
  52.  
  53.     <Button Command="{Binding TogglePlayerTypeCommand}" CommandParameter="{Binding AttackerPlayer}">
  54.         <TextBlock Text="{Binding Game.NextAttacker, StringFormat='Attacker: {0}'}" />
  55.     </Button>
  56.     <Button Grid.Column="1" Command="{Binding TogglePlayerTypeCommand}" CommandParameter="{Binding DefenderPlayer}">
  57.         <TextBlock Text="{Binding Game.NextDefender, StringFormat='Defender: {0}'}" />
  58.     </Button>
  59. </Grid>
  60. <TextBlock HorizontalAlignment="Center"><Italic>(Player type changes go into effect next game)</Italic></TextBlock>

Next time I'll go over the commands and the converters.

Comments

Minneapolis Web Design

Thanks for great share!
by ProWeb365

A nice article on the board

A nice article on the board game services. But to understand the code and other things we need best essays services along with the code and briefing. My appreciations are with you for displaying the code.

The View-Model of MVVM is

The View-Model of MVVM is essentially a worth converter on steroids, meaning that the View-Model is dependable for revealing the data matter from the representation in such a way that those matter are easily supervise and obsessive.

I most definitely value a part

I most definitely value a part of the new segments Windows 8 offers, even with the every so often impossible to miss interface. Having the ability to quickly shut down or suspend by moving the mouse cursor to the base right or have a moved survey of each open program and their benefit utilize really safeguards me out once per day. Assignment doer uk . Crushing the Windows key and searching for something is expedient and direct, and my ability groups have never been this responsive.

Software development

A product improvement handle gathers and makes an interpretation Write My Essay of business necessities into inventive innovation arrangements which then turn into a reality with custom programming formative programming application advancement administrations convey effective and solid custom programming frameworks. Application improvement programming can help programming advancement groups build and convey their tasks quicker and with higher quality. Application advancement programming instruments are the improvement arrangement of decision for a huge number of programming designers constructing genuine local applications for Windows.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.
  • You can enable syntax highlighting of source code with the following tags: <asp>, <c>, <cpp>, <cs>, <css>, <drupal5>, <drupal6>, <html4strict>, <java>, <javascript>, <jquery>, <php>, <python>, <ruby>, <sql>, <xml>. The supported tag styles are: <foo>, [foo]. PHP source code can also be enclosed in <?php ... ?> or <% ... %>.

More information about formatting options

By submitting this form, you accept the Mollom privacy policy.