WPFのListBoxは、グルーピングの機能も持っている。この機能を使うと、同じ部署にいる人をまとめて表示したりとかってことが可能になる。
ということで、早速動きを確認。
やり方は、データを表示するときに直接配列やリストをバインドするんじゃなくてCollectionViewSourceを間に挟む。そして、GroupDescriptionsにグルーピングする方法を設定すればOK。
お試し用にPersonクラスを作成してみた。
namespace WpfGroup
{
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
}
これをWindowのResourcesプロパティに配列として登録する。
<!-- 何処か上のほうでこれを定義しておく -->
xmlns:WpfGroup="clr-namespace:WpfGroup"
<Window.Resources>
<x:Array Type="{x:Type WpfGroup:Person}" x:Key="People">
<WpfGroup:Person Name="田中 太郎" Age="18" />
<WpfGroup:Person Name="田中 次郎" Age="28" />
<WpfGroup:Person Name="田中 三郎" Age="18" />
<WpfGroup:Person Name="田中 四郎" Age="18" />
<WpfGroup:Person Name="田中 五郎" Age="58" />
<WpfGroup:Person Name="田中 六郎" Age="28" />
</x:Array>
</Window.Resources>
次に、このデータを表示するためのDataTemplateも簡単に用意する。
<DataTemplate x:Key="HeaderTemplate" DataType="{x:Type WpfGroup:Person}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" />
<TextBlock Text="才の人たち" />
</StackPanel>
</DataTemplate>
次に、CollectionViewSourceを用意する。
<CollectionViewSource x:Key="PeopleSource"
Source="{StaticResource People}">
<!-- Ageプロパティの値でグルーピング -->
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Age" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
これをListBoxにバインドすることでグルーピングされて表示される。
<ListBox ItemsSource="{Binding Source={StaticResource PeopleSource}}" />
OKOKちゃんと動いてる。ついでにグルーピングした時に、各グループにヘッダーをつけることが出来るようになってる。これは、DataTemplateを用意して、GroupStyleに指定することで出来るようになる。
Window.Resourcesに下のようなDataTemplateをこさえる。
<DataTemplate x:Key="HeaderTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" />
<TextBlock Text="才の人たち" />
</StackPanel>
</DataTemplate>
これを、ListBoxのGroupStyleプロパティのGroupStyleに設定する。ListBoxタグの部分はしたのようになる。
<ListBox ItemsSource="{Binding Source={StaticResource PeopleSource}}">
<ListBox.GroupStyle>
<GroupStyle HeaderTemplate="{StaticResource HeaderTemplate}" />
</ListBox.GroupStyle>
</ListBox>
これで実行すると、グループ分けされてるのがよくわかるようになってくる。
因みに、独自のグルーピング処理を行いたい場合は、GroupDescriptionクラスを派生させて、GroupNameFromItemメソッドをオーバーライドすれば出来るようだ。ということで実験!10代 20代 30代とか10歳くくりでグルーピングできるようにしてみようと思う。さくっとコードにしてみた。
using System.ComponentModel;
namespace WpfGroup
{
public class GenerationGroupDescription : GroupDescription
{
public override object GroupNameFromItem(object item, int level, System.Globalization.CultureInfo culture)
{
var p = (Person)item;
return p.Age / 10 * 10 + "代";
}
}
}
これをGroupDescriptionsに設定するようにコードをなおす。
<CollectionViewSource x:Key="PeopleSource"
Source="{StaticResource People}">
<CollectionViewSource.GroupDescriptions>
<!-- 年代別グルーピング -->
<WpfGroup:GenerationGroupDescription />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
ついでに、元になるデータの年齢もばらばらになるように変更して実行する。
<x:Array Type="{x:Type WpfGroup:Person}" x:Key="People">
<WpfGroup:Person Name="田中 太郎" Age="13" />
<WpfGroup:Person Name="田中 次郎" Age="22" />
<WpfGroup:Person Name="田中 三郎" Age="18" />
<WpfGroup:Person Name="田中 四郎" Age="32" />
<WpfGroup:Person Name="田中 五郎" Age="21" />
<WpfGroup:Person Name="田中 六郎" Age="40" />
</x:Array>
ばっちりっぽい。