Search code examples
c#wpfxamlmvvmdatatemplate

How to use WPF DataTemplates only on a part of the layout


In a MVVM environment I am using a list box where I am visualizing different data types in a different way but having some style elements in common. A minimal sample looks like this:

interface IPropertyItem
{
    string Description { get; }
}

class PropertyBoolItem : IPropertyItem
{
    public string Description { get; }
    public bool Value { get; set; }
}

class PropertyStringItem : IPropertyItem
{
    public string Description { get; }
    public string DifferentValue { get; set; }
}
<ListBox>
    <ListBox.Resources>
        <!-- A bool item -->
        <DataTemplate DataType="{x:Type types:PropertyBoolItem}">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="10"/>
                    <ColumnDefinition Width="130"/>
                    <ColumnDefinition Width="10"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>

                <TextBlock Text{Binding Description}/>
                <CheckBox Grid.Column="3" IsChecked="{Binding Value}"/>
            </Grid>
        </DataTemplate>

        <!-- A string item -->
        <DataTemplate DataType="{x:Type types:PropertyStringItem}">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="10"/>
                    <ColumnDefinition Width="130"/>
                    <ColumnDefinition Width="10"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>

                <TextBlock Text{Binding Description}/>
                <TextBox Grid.Column="3" Text="{Binding DifferentValue, Mode=TwoWay}"/>
            </Grid>
        </DataTemplate>

        <!-- and so on... -->
    </ListBox.Resources>
</ListBox>

Everythings is working so far. But I was wondering if there is a more elegant way to implement this as big parts of the markup are always the same and only some parts (as the checkbox or the textbox) are dependent on the data type.

Thanks in advance!


Solution

  • Not sure if this qualifies as "more elegant", but it is less XAML, and you wouldn't have to bother with the complex ListBoxItem Template.

    <ListBox ...>
        <ListBox.Resources>
            <!-- A bool item -->
            <DataTemplate DataType="{x:Type types:PropertyBoolItem}">
                <CheckBox IsChecked="{Binding Value}"/>
            </DataTemplate>
            <!-- A string item -->
            <DataTemplate DataType="{x:Type types:PropertyStringItem}">
                <TextBox Text="{Binding DifferentValue}"/>
            </DataTemplate>
        </ListBox.Resources>
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="10"/>
                        <ColumnDefinition Width="130"/>
                        <ColumnDefinition Width="10"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Text="{Binding Description}"/>
                    <ContentPresenter Grid.Column="3" Content="{Binding}"/>
                </Grid>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>