We already saw an example of applying multiple group style here. Now we are going to do the same thing with ListView. The basic concept is almost similar. The only different is how we are going to bind and display items in these controls. At first step we are going to define two data template resources in XAML, one for each group header. Here is a XAML code for it.
<Border Margin="2" BorderBrush="Brown" BorderThickness="1" CornerRadius="5">
<TextBlock Margin="2" FontSize="16" FontWeight="Bold"
Foreground="Brown" Text="{Binding Path=Name}"/>
</Border>
</DataTemplate>
<DataTemplate x:Key="CountyTemplate">
<Border Margin="2" BorderBrush="Brown" Background="AliceBlue" BorderThickness="1" CornerRadius="5">
<TextBlock Margin="2" FontSize="12" Foreground="Red"
TextAlignment="Center" Text="{Binding Path=Name}"/>
</Border>
</DataTemplate>
Then we are going to add one class in our project. That class is inherited by DataTemplateSelector and define two DataTemplate type properties in it. We also override SelectTemplate method.
But now we have a problem. Here container is in fact CollectionViewGroupInternal class, which is inherited by CollectionViewGroup class. And we can’t access that class directly from our code, at least not easily.
But we know that our grouping is only two level depth therefore we can apply little trick here. If it is a first level grouping then all of items in this group is also a type of CollectionViewGroupInternal type. On the other hand if it is second level of grouping then its items type is StateInfo class. We are going to use this information and update our overridden method. Here is our new overridden method.
{
public DataTemplate StateTemplate
{ get; set; }
public DataTemplate CountyTemplate
{ get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
ContentPresenter cp = container as ContentPresenter;
if (cp != null)
{
CollectionViewGroup cvg = cp.Content as CollectionViewGroup;
if (cvg.Items.Count > 0)
{
StateInfo stinfo = cvg.Items[0] as StateInfo;
if (stinfo != null)
return CountyTemplate;
else
return StateTemplate;
}
}
return base.SelectTemplate(item, container);
}
}
Now it works in this case. But of course there is limitation, we can’t use the same technique if the grouping is more than two level depth. Here is a complete XAML code of our program.
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfListViewGroup"
Title="MainWindow" Height="400" Width="525">
<Window.Resources>
<DataTemplate x:Key="StateTemplate">
<Border Margin="2" BorderBrush="Brown" BorderThickness="1" CornerRadius="5">
<TextBlock Margin="2" FontSize="16" FontWeight="Bold"
Foreground="Brown" Text="{Binding Path=Name}"/>
</Border>
</DataTemplate>
<DataTemplate x:Key="CountyTemplate">
<Border Margin="2" BorderBrush="Brown" Background="AliceBlue" BorderThickness="1" CornerRadius="5">
<TextBlock Margin="2" FontSize="12" Foreground="Red"
TextAlignment="Center" Text="{Binding Path=Name}"/>
</Border>
</DataTemplate>
<local:MyTemplateSelector x:Key="MyTemplateSelectorObj"
CountyTemplate="{StaticResource CountyTemplate}"
StateTemplate="{StaticResource StateTemplate}"/>
</Window.Resources>
<Grid>
<ListView Name="list" Margin="5" ItemsSource="{Binding}">
<ListView.GroupStyle>
<GroupStyle HeaderTemplateSelector="{StaticResource MyTemplateSelectorObj}"/>
</ListView.GroupStyle>
<ListView.View>
<GridView>
<GridViewColumn Header="State" Width="100" DisplayMemberBinding="{Binding State}"/>
<GridViewColumn Header="County" Width="100" DisplayMemberBinding="{Binding County}"/>
<GridViewColumn Header="City" Width="100" DisplayMemberBinding="{Binding City}"/>
<GridViewColumn Header="Population" Width="200" DisplayMemberBinding="{Binding Population}"/>
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>
Here is complete C# code of our program.
using System.Windows;
using System.Windows.Data;
using System.Windows.Controls;
namespace WpfListViewGroup
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private ObservableCollection<StateInfo> states = new ObservableCollection<StateInfo>();
public MainWindow()
{
InitializeComponent();
states.Add(new StateInfo("Maryland", "Frederick", "Frederick", 52767));
states.Add(new StateInfo("Maryland", "Frederick", "Brunswick", 4894));
states.Add(new StateInfo("Maryland", "Frederick", "New Market", 427));
states.Add(new StateInfo("Maryland", "Montgomery", "Rockville", 60734));
states.Add(new StateInfo("Maryland", "Montgomery", "Gaithersburg", 52613));
states.Add(new StateInfo("Taxes", "Harris", "Deer Park", 28520));
states.Add(new StateInfo("Taxes", "Harris", "Jersey Village", 6880));
states.Add(new StateInfo("Taxes", "Dallas", "Irving", 201927));
states.Add(new StateInfo("Taxes", "Dallas", "DeSoto", 37646));
states.Add(new StateInfo("Taxes", "Bexar", "Leon Valley", 9239));
states.Add(new StateInfo("California", "Los Angeles", "Burbank", 100316));
states.Add(new StateInfo("California", "Los Angeles", "Azusa", 44712));
states.Add(new StateInfo("California", "Los Angeles", "Culver City", 38816));
states.Add(new StateInfo("California", "Los Angeles", "Glendale", 194973));
states.Add(new StateInfo("California", "Sacramento", "Citrus Heights", 85071));
states.Add(new StateInfo("California", "Sacramento", "Elk Grove", 59984));
list.ItemsSource = states;
CollectionView cv = (CollectionView)CollectionViewSource.GetDefaultView(list.ItemsSource);
PropertyGroupDescription group1 = new PropertyGroupDescription("State");
PropertyGroupDescription group2 = new PropertyGroupDescription("County");
cv.GroupDescriptions.Add(group1);
cv.GroupDescriptions.Add(group2);
}
}
public class StateInfo
{
public StateInfo(string state, string county, string city, int population)
{
State = state;
County = county;
City = city;
Population = population;
}
public string State
{ get; set; }
public string County
{ get; set; }
public string City
{ get; set; }
public int Population
{ get; set; }
}
public class MyTemplateSelector : DataTemplateSelector
{
public DataTemplate StateTemplate
{ get; set; }
public DataTemplate CountyTemplate
{ get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
ContentPresenter cp = container as ContentPresenter;
if (cp != null)
{
CollectionViewGroup cvg = cp.Content as CollectionViewGroup;
if (cvg.Items.Count > 0)
{
StateInfo stinfo = cvg.Items[0] as StateInfo;
if (stinfo != null)
return CountyTemplate;
else
return StateTemplate;
}
}
return base.SelectTemplate(item, container);
}
}
}
Here is the output of our program.

I need source code help me
By: Ysn-Elf Shn on May 11, 2012
at 2:43 am
Thanks to visit my blog and post comment here. I email you the source code of complete project.
Regards
Zeeshan Amjad
By: Zeeshan Amjad on May 14, 2012
at 3:35 pm