The WPF ListView

By default a ListView looks and acts much like a standard WPF ListBox (when in it’s default state) but ofcourse we can also include headers/columns and groupings whichon top of the basic list of data.

Let’s assume we’re wanting to display a collection of Person objects where the Person type is made up of FirstName, LastName and Age. For this example assume these are exposed by the People property on our view model.

To display our collection we can simply do the following

<ListView ItemsSource="{Binding People}" />

But this will display the type name for each item in our collection and ofcourse doesn’t have headings. So to add headings we need to use the following

<ListView ItemsSource="{Binding People}">
   <ListView.View>
      <GridView>
         <GridViewColumn Header="First Name" Width="150" 
                   DisplayMemberBinding="{Binding FirstName}"/>
         <GridViewColumn Header="Last Name" Width="150" 
                   DisplayMemberBinding="{Binding LastName}"/>
         <GridViewColumn Header="Age" Width="100" 
                   DisplayMemberBinding="{Binding Age}"/>
      </GridView>
   </ListView.View>
</ListView>

this will also display the members we’re binding to so no longer display the type name.

So far so good, but to add groupings we need to do a little more work. In XAML we have the following (in the Window ResourceDictionary)

<CollectionViewSource Source="{Binding People}" x:Key="GroupedItems">
   <CollectionViewSource.GroupDescriptions>
      <PropertyGroupDescription PropertyName="LastName" />
   </CollectionViewSource.GroupDescriptions>
</CollectionViewSource>

If using the above XAML we also need to alter the ListView’s ItemSource to this

<ListView ItemsSource="{Binding Source={StaticResource GroupedItems}}">

this will then bind to the GroupedItems. Note we must use the “Source=” XAML.

We can also easily declare the same groupings in C# code as per below

CollectionView collectionView = 
      (CollectionView)CollectionViewSource.GetDefaultView(list.ItemsSource);
PropertyGroupDescription pgd = new PropertyGroupDescription("LastName");
collectionView.GroupDescriptions.Add(pgd);

Note: in the above case our ListView has the x:Name=”list” and ofcourse doesn’t require the ItemsSource binding change listed for the XAML code.

Using the CollectionView we add property group descriptions but we need to amend our ListView XAML to use this. By adding the ListView.GroupStyle as per below, we create the control template for the groupings

<ListView.GroupStyle>
   <GroupStyle>
      <GroupStyle.ContainerStyle>
         <Style TargetType="GroupItem">
            <Setter Property="Template">
               <Setter.Value>
                  <ControlTemplate TargetType="{x:Type GroupItem}">
                     <StackPanel>
                        <TextBlock FontWeight="Bold" 
                                FontSize="14" Text="{Binding Path=Name}"/>
                        <ItemsPresenter/>
                     </StackPanel>
                  </ControlTemplate>
               </Setter.Value>
            </Setter>
         </Style>
      </GroupStyle.ContainerStyle>
   </GroupStyle>
</ListView.GroupStyle>

The key things to note in the above XAML are that we need to ensure we put the ItemsPresenter into the ControlTemplate or now items are displayed and we do not bind to the data but instead bind to the CollectionViewGroup which is what the CollectionViewSource groups the data into. So in this case Name represents the string data for the grouping name and we could also bind to ItemCount for example if we wanted to show to the user the number of items in the grouping.