Wednesday, February 24, 2010

Shatranj – The Board (Or) Using ItemsControl & ItemSource to render UI dynamically

A naive implementation of ChessBoardView:

    <Grid>

        <Grid.RowDefinitions>

            <RowDefinition />

            <RowDefinition/>

            <RowDefinition/>

            <RowDefinition/>

            <RowDefinition/>

            <RowDefinition/>

            <RowDefinition/>

            <RowDefinition/>

        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>

            <ColumnDefinition/>

            <ColumnDefinition/>

            <ColumnDefinition/>

            <ColumnDefinition/>

            <ColumnDefinition/>

            <ColumnDefinition/>

            <ColumnDefinition/>

            <ColumnDefinition/>

        </Grid.ColumnDefinitions>

 

        <Shatranj:BoardSquareView DataContext="{Binding Path=Board[a1]}"

                                  Grid.Row="{Binding Path=Placement.X}"

                                  Grid.Column="{Binding Path=Placement.Y}"/>

        <Shatranj:BoardSquareView Background="Bisque"

                                  DataContext="{Binding Path=Board[b1]}"

                                  Grid.Row="{Binding Path=Placement.X}"

                                  Grid.Column="{Binding Path=Placement.Y}"/>

        <Shatranj:BoardSquareView Background="Tan"

                                  DataContext="{Binding Path=Board[c1]}"

                                  Grid.Row="{Binding Path=Placement.X}"

                                  Grid.Column="{Binding Path=Placement.Y}"/>

<snip>

Though the above works, it also means you need to define all 64 BoardSquares one by one!  Happy typing :)  Here’s the revised version using ItemsControl:

    <UserControl.Resources>

        <Shatranj:ChessBoardViewModel x:Key="ChessBoardViewModel"/>

    </UserControl.Resources>   

 

    <Grid>

        <ItemsControl DataContext="{StaticResource ChessBoardViewModel}" ItemsSource="{Binding Path=Board.AllSquares, Mode=OneWay}">

            <ItemsControl.ItemTemplate>

                <DataTemplate>

                    <Shatranj:BoardSquareView />

                </DataTemplate>

            </ItemsControl.ItemTemplate>

            <ItemsControl.ItemsPanel>

                <ItemsPanelTemplate>

                    <Grid>

                        <Grid.RowDefinitions>

                            <RowDefinition />

                            <RowDefinition />

                            <RowDefinition />

                            <RowDefinition />

                            <RowDefinition />

                            <RowDefinition />

                            <RowDefinition />

                            <RowDefinition />

                        </Grid.RowDefinitions>

                        <Grid.ColumnDefinitions>

                            <ColumnDefinition />

                            <ColumnDefinition />

                            <ColumnDefinition />

                            <ColumnDefinition />

                            <ColumnDefinition />

                            <ColumnDefinition />

                            <ColumnDefinition />

                            <ColumnDefinition />

                        </Grid.ColumnDefinitions>

                    </Grid>

                </ItemsPanelTemplate>

            </ItemsControl.ItemsPanel>

            <ItemsControl.ItemContainerStyle>

                <!-- The content of ItemsPanelTemplate actually is inside a ContentPresenter -->

                <!-- Even the content of DataTemplate gets wrapped by a ContentPresenter -->

                <Style TargetType="{x:Type ContentPresenter}">

                    <Setter Property="Grid.Row" Value="{Binding Path=Placement.X, Mode=TwoWay}" />

                    <Setter Property="Grid.Column" Value="{Binding Path=Placement.Y, Mode=TwoWay}" />

                </Style>

            </ItemsControl.ItemContainerStyle>

        </ItemsControl>

    </Grid>

 

Well, the above is where Snoop saved me!  And thanks to Marcho Zhou @ MSDN.  As documented above, you get a ContentPresenter in both DataTemplate & ItemsPanelTemplate.  So, x:Type must be ContentPresenter.

Here’s also a trick I use to avoid Code-Behind:  Where you link ViewModel to Model:

    <UserControl.Resources>

        <Shatranj:ChessBoardViewModel x:Key="ChessBoardViewModel"/>

    </UserControl.Resources>  

Aside:  You need to leave out {x:Type} for Silverlight

No comments: