WPF & XAML – ListBoxes with a Grouping Capability

This tutorial is about learning: <ItemsControl.GroupStyle>

It is now possible to have a listbox with “grouping” capabilities.

The following example show an ItemsControl that is bound to an XmlDataProvider and the code-behind content that contains the logic to add and remove grouping.

When the check box is checked, the content of the ItemsControl is grouped by the Type attribute.

Each group is of type CollectionViewGroup.

The GroupStyle HeaderTemplate is specified so that it appears as a TextBlock that displays the Name of each the group. In this case, the Name is either Work or Home.

This blog entry is implementing the following sample:

https://msdn.microsoft.com/en-us/library/system.windows.controls.itemscontrol.groupstyle.aspx

image

image

The next step is build this application and explain how it works.

(1) Start Visual Studio and select “File / New Project”

image

(2)  Select “WPF Application” and enter a project name, such as  “ItemsControlGroupStyle.” When you paste in the code, replace the whole window XAML code. Notice that you need to make sure you named your project ItemsControlGroupStyle.

image

Source code for Window1.xaml

 <Window x:Class="ItemsControlGroupStyle.Window1"
     xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
     Title="Grouping Sample"
     Width="220" Height="550">
     <StackPanel>
         <StackPanel.Resources>
             <XmlDataProvider x:Key="myTasks" XPath="Tasks/Task">
                 <x:XData>
                     <Tasks xmlns="">
                         <Task Name="Groceries" Priority="2" Type="Home">
                             <Description>Pick up Groceries and Detergent</Description>
                         </Task>
                         <Task Name="Laundry" Priority="2" Type="Home">
                             <Description>Do Laundry</Description>
                         </Task>
                         <Task Name="Email" Priority="1" Type="Work">
                             <Description>Email Clients</Description>
                         </Task>
                         <Task Name="Clean" Priority="3" Type="Work">
                             <Description>Clean my office</Description>
                         </Task>
                         <Task Name="Dinner" Priority="1" Type="Home">
                             <Description>Get ready for family reunion</Description>
                         </Task>
                         <Task Name="Proposals" Priority="2" Type="Work">
                             <Description>Review new budget proposals</Description>
                         </Task>
                     </Tasks>
                 </x:XData>
             </XmlDataProvider>
         </StackPanel.Resources>
  
         <TextBlock Margin="12,5,5,0" FontSize="20" Text="My Task List"/>
         <CheckBox Margin="10,5,5,10" Checked="AddGrouping"
               Unchecked="RemoveGrouping">Group by task type</CheckBox>
         <ItemsControl Margin="10" Name="myItemsControl"
                   ItemsSource="{Binding Source={StaticResource myTasks}}">
             <ItemsControl.ItemTemplate>
                 <DataTemplate>
                     <DataTemplate.Resources>
                         <Style TargetType="TextBlock">
                             <Setter Property="FontSize" Value="18"/>
                             <Setter Property="HorizontalAlignment" Value="Center"/>
                         </Style>
                     </DataTemplate.Resources>
                     <Grid>
                         <Ellipse Fill="Silver"/>
                         <StackPanel>
                             <TextBlock Margin="3,3,3,0"
                          Text="{Binding XPath=@Name}"/>
                             <TextBlock Margin="3,0,3,7"
                          Text="{Binding XPath=@Priority}"/>
                         </StackPanel>
                     </Grid>
                 </DataTemplate>
             </ItemsControl.ItemTemplate>
             <ItemsControl.ItemContainerStyle>
                 <Style>
                     <Setter Property="Control.Width" Value="100"/>
                     <Setter Property="Control.Margin" Value="5"/>
                 </Style>
             </ItemsControl.ItemContainerStyle>
             <ItemsControl.GroupStyle>
                 <GroupStyle>
                     <GroupStyle.HeaderTemplate>
                         <DataTemplate>
                             <TextBlock FontWeight="Bold" FontSize="15"
                          Text="{Binding Path=Name}"/>
                         </DataTemplate>
                     </GroupStyle.HeaderTemplate>
                 </GroupStyle>
             </ItemsControl.GroupStyle>
         </ItemsControl>
     </StackPanel>
 </Window>
  

Window1.xaml looks like this:

image

 

StackPanel.Resources contains XML data that is used to populate the listbox. There are 4 columns in each XML node (name, priority, type, description).

image

Notice that “Home” represents the top level grouping. Our “ItemsControl” points to “myTasks” for data. “myTasks” is just a <StackPanel> resource with XML data.

image

The <ItemsControl> control has pieces of XAML code:

  • ItemTemplate (Allows you to define how content is displayed)
  • ItemContainerStyle (Allows you to style the ItemsControl)
  • GroupStyle (Allows  you to group content)

The ItemTemplate section looks like this:

image

ItemContainerStyle

image

GroupStyle

image

GroupStyle allows us to easily specify a header template. Notice we are using “Name” as the “Path.” When we click on the Checkbox to tell WPF to group our list, then code executes below. The list is grouped according to “Type,” which is either “Home” or “Work.” 

image

Here is the code behind you will need for Window1.xaml.cs

 using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Data;
 using System.Windows.Documents;
 using System.Windows.Input;
 using System.Windows.Media;
 using System.Windows.Media.Imaging;
 using System.Windows.Navigation;
 using System.Windows.Shapes;
  
 namespace ItemsControlGroupStyle
 {
     /// <summary>
     /// Interaction logic for Window1.xaml
     /// </summary>
     public partial class Window1 : Window
     {
         public Window1()
         {
             InitializeComponent();
         }
         CollectionView myView;
         private void AddGrouping(object sender, RoutedEventArgs e)
         {
             myView = (CollectionView)CollectionViewSource.GetDefaultView(myItemsControl.ItemsSource);
             if (myView.CanGroup == true)
             {
                 PropertyGroupDescription groupDescription
                     = new PropertyGroupDescription("@Type");
                 myView.GroupDescriptions.Add(groupDescription);
             }
             else
                 return;
         } 
  
         private void RemoveGrouping(object sender, RoutedEventArgs e)
         {
             myView = (CollectionView)CollectionViewSource.GetDefaultView(myItemsControl.ItemsSource);
             myView.GroupDescriptions.Clear();
         }
     }
 }

All the source is available here:

image

There you have it, an example project that demonstrates grouping in a list.