#455 – Using ItemContainerStyle to Bind Data Elements in a Collection to a Grid

I showed earlier that to bind Grid.Row and Grid.Column properties on child items in an ItemsControl,  we need to set up the binding on the ContentPresenter elements that contain the individual items.  I did this by creating a class that inherited from ItemsControl and then set the bindings at runtime, programmatically.

There is a much easier way to do this, pointed out by reader Bruno (thanks Bruno)!

You can set up the bindings by specifying the ItemContainerStyle of the ItemsControl and using property setters to do the binding.

        <ItemsControl ItemsSource="{Binding ChessPieces}" Height="500" Width="500">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Grid ShowGridLines="True">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="*"/>
                            <!-- 7 more rows -->
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*"/>
                            <!-- 7 more columns -->
                        </Grid.ColumnDefinitions>
                    </Grid>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Label Content="{Binding Text}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
            <ItemsControl.ItemContainerStyle>
                <Style>
                    <Setter Property="Grid.Row" Value="{Binding Row}"/>
                    <Setter Property="Grid.Column" Value="{Binding Column}"/>
                </Style>
            </ItemsControl.ItemContainerStyle>
        </ItemsControl>

#452 – Data Binding Elements in a Collection to a Grid, Part V

We saw earlier that to bind Grid.Row and Grid.Column properties on child items in an ItemsControl,  we need to set up the binding on the ContentPresenter elements that contain the individual items.

We can do this by overriding the ItemsControl.PrepareContainerForItemOverride method.  This method is called for each item in the collection and receives both the containing element (a ContentPresenter in our case) and the contained item (a ChessPiece object in our example).  We bind the Grid.Row and Grid.Column properties on the ContentPresenter to the same properties on the contained item.

public class GridBasedItemsControl : ItemsControl
    {
        protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
        {
            base.PrepareContainerForItemOverride(element, item);

            ContentPresenter cp = element as ContentPresenter;

            if ((cp != null) && (item != null))
            {
                BindingOperations.SetBinding(cp, Grid.RowProperty, new Binding { Source = item, Path = new PropertyPath("Row")});
                BindingOperations.SetBinding(cp, Grid.ColumnProperty, new Binding { Source = item, Path = new PropertyPath("Column") });
            }

        }
    }

Everything now works as expected.

NOTE: Reader Bruno pointed out a much better way to do this, using the ItemContainerStyle property.

#449 – Data Binding Elements in a Collection to a Grid, part II

This post continues with the goal of binding a collection of elements to a Grid, with each object’s Row and Column properties indicating where in the Grid it should be located.  Last time we set the ItemsPanel property of an ItemsControl to order things in an 8×8 grid.  We also set the ItemTemplate property to include a Label with attached Grid.Row and Grid.Column properties.

In this post, we create a series of ChessPiece elements at runtime, representing a series of chess pieces.

            ChessPieces = new ObservableCollection<ChessPiece>();
            ChessPieces.Add(new ChessPiece("QR-Blk", 1, 1));
            ChessPieces.Add(new ChessPiece("QN-Blk", 1, 2));
            ChessPieces.Add(new ChessPiece("QB-Blk", 1, 3));
            ChessPieces.Add(new ChessPiece("Q-Blk", 1, 4));
            ChessPieces.Add(new ChessPiece("K-Blk", 1, 5));
            ChessPieces.Add(new ChessPiece("KB-Blk", 1, 6));
            ChessPieces.Add(new ChessPiece("KN-Blk", 1, 7));
            ChessPieces.Add(new ChessPiece("KR-Blk", 1, 8));

            ChessPieces.Add(new ChessPiece("P1-Blk", 2, 1));
            ChessPieces.Add(new ChessPiece("P2-Blk", 2, 2));
            ChessPieces.Add(new ChessPiece("P3-Blk", 2, 3));
            ChessPieces.Add(new ChessPiece("P4-Blk", 2, 4));
            ChessPieces.Add(new ChessPiece("P5-Blk", 2, 5));
            ChessPieces.Add(new ChessPiece("P6-Blk", 2, 6));
            ChessPieces.Add(new ChessPiece("P7-Blk", 2, 7));
            ChessPieces.Add(new ChessPiece("P8-Blk", 2, 8));
            OnPropertyChanged("ChessPieces");

#448 – Data Binding Elements in a Collection to a Grid, part I

Assume that you have a collection of objects that you want to place in a grid, with their position only known at runtime.  You might have properties on the objects indicating what row and column they should be placed in and then use data binding to locate the objects.

You can use a Grid panel as the ItemsPanel of an ItemsControl.  This dictates the layout of the items in the collection.  You can then specify the ItemTemplate to indicate how each item should be displayed.

Your first try might look something like this:

    <ItemsControl ItemsSource="{Binding ChessPieces}" Height="500" Width="500">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Grid ShowGridLines="True">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="*"/>
                        <!-- 7 more rows -->
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*"/>
                        <!-- 7 more columns -->
                    </Grid.ColumnDefinitions>
                </Grid>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Label Content="{Binding Text}" Grid.Row="{Binding Row}" Grid.Column="{Binding Column}"
                        HorizontalAlignment="Center" VerticalAlignment="Center"/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>

Next time–create a collection of ChessPiece objects at runtime.

#35 – ItemsControl

ItemsControl is another WPF class that inherits from Control and serves as a base class for other controls.  Controls that inherit from ItemsControl display a collection of items.

Controls that derive from ItemsControl typically get a list of items to display using data binding, binding to an object that implements IEnumerable.

Controls that inherit directly or indirectly from ItemsControl include: Menu, ContextMenu, ComboBox, ListBox, ListView, TabControl, DataGrid, StatusBar, ToolBar and TreeView.