Search code examples
wpflistviewgridviewdatatemplate

How to define an ItemTemplate for GridView (inside a ListView) so it can be used in multiple different ListViews?


I have some ListView's which bind to collections in the ViewModel. The type of items in those collections are the same (let's call them TypeA) which is a class exposing multiple simple type properties. I would like to display them in a GridView inside the ListView. Naturally, I would want to define a DataTemplate for this TypeA so that I don't have to duplicate the same XAML for each of the ListView's. All of the examples I've found so far define the ItemTemplate inside the ListView. How can I make a resource and let different ListView's refer to this single resource?

UPDATE:

I am posting my XAML code for better clarification. My original XAML code (simplified) looks like this:

<ListView ItemsSource="{Binding MYCOLLECTION}" SelectionMode="Extended" >                                                                       
  <ListView.View>
    <GridView>
      <GridViewColumn DisplayMemberBinding="{Binding Prop1}" >
        <GridViewColumn.Header>
          <Border >
            <TextBlock Text="Prop1" />
          </Border>
        </GridViewColumn.Header>
      </GridViewColumn>
      <GridViewColumn DisplayMemberBinding="{Binding Prop2}" >
        <GridViewColumn.Header>
          <Border >
            <TextBlock Text="Prop2" />
          </Border>
        </GridViewColumn.Header>
      </GridViewColumn>
      <GridViewColumn DisplayMemberBinding="{Binding Prop3}" >
        <GridViewColumn.Header>
          <Border >
            <TextBlock Text="Prop3" />
          </Border>
        </GridViewColumn.Header>
      </GridViewColumn>
...                         
    </GridView>
  </ListView.View>
</ListView>

I have many dependency properties set to the headers and that's why I put individual Header items as well as why my code is really long--hence why I'm seeking to use a datatemplate.

So my idea is that I can show different selections of the same type in the same way in different GridView's (because we want the column headers to display the names of the properties so we use GridView).

BTW those are not the only places I am presenting this data type, so I definitely need to specify a Resource key and restrict this to be used only for GridView. And because I want to display in a Grid way, I assume can't define a DataTemplate for my type and use it as ItemTemplate in a ListView.


Solution

  • You do not even have to define a resource key just set the DataType because that will be used as a key internally by WPF. Just make sure your datatemplates are visible from any control where you want to use it, they will be automatically applied. (Just for example you can define them at application level in the resources of App.xaml, but you probably have separate resource dictionaries):

    <Application x:Class="WpfTest.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:dataModel="clr-namespace:DataModel"
             StartupUri="MainWindow.xaml">
        <Application.Resources>
            <DataTemplate DataType="{x:Type dataModel:GreekGod}">
                <TextBlock Text="{Binding Path=Name}" Foreground="Gold"/>
            </DataTemplate>
        </Application.Resources>
    </Application>
    

    For your code you need to define templates for each property because you are using it as a grid and you need to set the cell template for each column after removing the DisplaymemberBinding:

                   <GridViewColumn CellTemplate="{StaticResource prop1Template}">
                        <GridViewColumn.Header>
                            <Border >
                                <TextBlock Text="Prop1" />
                            </Border>
                        </GridViewColumn.Header>                                                
                    </GridViewColumn>
                    ...
    

    And put the resource in a visible place just as mentioned before like in the Application resources:

                    <Application.Resources>
                       <DataTemplate x:Key="prop1Template">
                          <TextBlock Text="{Binding Prop1}" Foreground="Red"/>
                       </DataTemplate>
                    </Application.Resources>
    

    You can use a ColumnHeaderTemplate and a ColumnContainerStyle like this:

         <GridView
               ColumnHeaderTemplate="{StaticResource myHeaderTemplate}"
               ColumnHeaderContainerStyle="{StaticResource myHeaderStyle}"
         >
               <GridViewColumn Header="Prop1" CellTemplate="{StaticResource prop1Template}"/>
         ...
    

    where the resources are for example:

        <Style x:Key="myHeaderStyle" TargetType="{x:Type GridViewColumnHeader}">
            <Setter Property="Background" Value="LightBlue"/>
        </Style>
    
        <DataTemplate x:Key="myHeaderTemplate">
            <DockPanel>
                <CheckBox/>
                <TextBlock FontSize="16" Foreground="DarkBlue">
                    <TextBlock.Text>
                        <Binding/>
                    </TextBlock.Text>
                </TextBlock>
            </DockPanel>
        </DataTemplate>