WPF Data Templates and the Composite Pattern

May 17, 2007

no comments

WPF Data Template is the ultimate utility for generating view from data. To work with Data Templates correctly, one should design the data first, than it should let the data to build the view. At first place it sounds very weird because up until WPF you built the view first, and then bind it to data.

Let’s say that you have to build a composite dynamic view, such as a weird table, which has composite headers and values binded to data. For example:

As you can see, “Master Header” is the main header, “Sub Header 1” and “Sub Header 2” are sub headers of the master header, “Value Group 1” and “Value Group 2” are sub headers of the first sub header and “Value 1”, “Value 2” are editable values which are actually the table values and are the children of “Value Group 1”.

If you are thinking about the structure of the data behind this table, you will find that it is based on the Composite Pattern.

The class diagram bellow summarizes it.

Now thinking about Data Templates, as I already said, it is the ultimate tool to turn this complex, recursive data structure into view.

The code snippet bellow demonstrates how to turn this structure into view using Data Templates.

 

    <!-- ValueItem Data Template -->
    <DataTemplate DataType="{x:Type c:ValueItem}">
        <Border Margin="2" Padding="2" CornerRadius="5" BorderThickness="1" BorderBrush="Blue">
            <TextBox BorderBrush="{x:Null}" Text="{Binding Value}" />
        </Border>
    </DataTemplate>
 
    <!-- ValueGroupItem Data Template -->
    <DataTemplate DataType="{x:Type c:ValueGroupItem}">
        <HeaderedItemsControl Header="{Binding Header}" ItemsSource="{Binding Items}" />
    </DataTemplate>
 
    <!-- HeaderedGroupItem Data Template -->
    <DataTemplate DataType="{x:Type c:HeaderedGroupItem}">
        <HeaderedItemsControl Header="{Binding Header}" ItemsSource="{Binding Items}">
            <HeaderedItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <UniformGrid Columns="0" Rows="1" IsItemsHost="True" />
                </ItemsPanelTemplate>
            </HeaderedItemsControl.ItemsPanel>
        </HeaderedItemsControl>
    </DataTemplate>

 

Actually, there are three Data Templates. The first one is for translating the ValueItem instances into a border with a text box. The second one is for translating the ValueGroupItem instances into a WPF’s HeaderedItemsControl, to display a header, and to display the value items as a list. And the third is for translating the HeaderedGroupItem instances into a WPF’s HeaderedItemsControl with a UniformGrid as its ItemsPanelTemplate.

The code snippet bellow magically translate the composite structure into the table above.

 

    class TableItem : HeaderedGroupItem
    {
        public TableItem() : base ("Master Header")
        {
            ValueItem value1 = new ValueItem("Value 1");
            ValueItem value2 = new ValueItem("Value 2");
            ValueItem value3 = new ValueItem("Value 3");
            ValueItem value4 = new ValueItem("Value 4");
            ValueItem value5 = new ValueItem("Value 5");
            ValueItem value6 = new ValueItem("Value 6");
            ValueItem value7 = new ValueItem("Value 7");
 
            ValueGroupItem valueGroup1 = new ValueGroupItem("Value Group 1");
            valueGroup1.Items.Add(value1);
            valueGroup1.Items.Add(value2);
 
            ValueGroupItem valueGroup2 = new ValueGroupItem("Value Group 2");
            valueGroup2.Items.Add(value3);
            valueGroup2.Items.Add(value4);
 
            HeaderedGroupItem super1 = new HeaderedGroupItem("Sub Header 1");
            super1.Items.Add(valueGroup1);
            super1.Items.Add(valueGroup2);
 
            ValueGroupItem valueGroup3 = new ValueGroupItem("Value Group 3");
            valueGroup3.Items.Add(value5);
            valueGroup3.Items.Add(value6);
            valueGroup3.Items.Add(value7);
 
            ValueGroupItem valueGroup4 = new ValueGroupItem("Value Group 4");
            valueGroup4.Items.Add(value5);
            valueGroup4.Items.Add(value6);
            valueGroup4.Items.Add(value7);
 
            ValueGroupItem valueGroup5 = new ValueGroupItem("Value Group 5");
            valueGroup5.Items.Add(value5);
            valueGroup5.Items.Add(value6);
            valueGroup5.Items.Add(value7);
 
            HeaderedGroupItem super2 = new HeaderedGroupItem("Sub Header 2");
            super2.Items.Add(valueGroup3);
            super2.Items.Add(valueGroup4);
            super2.Items.Add(valueGroup5);
 
            Items.Add(super1);
            Items.Add(super2);
        }
    }

 

    <Grid>
       <Border BorderBrush="Red" BorderThickness="1">
          <ContentControl>
             <c:TableItem />
          </ContentControl>
       </Border>
    </Grid>

 

Data Template is a very strong tool for translating a simple or complex data into view.

You can download the code from here.

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*