CollectionViewSourceのグループ化機能
今回はCollectionViewSourceのグループ化機能を使ってグループ毎にアイテムを表示する方法を説明します。
今回もXAML上でグループ化の定義を行う場合とViewModelで動的にグループ化の定義を行う方法を紹介します。
Modelのコードは以下の様になっています。
XAMLでグループ化の定義を行う場合もGroupDescriptionsにPropertyGroupDescriptionを指定するだけです。
PropertyGroupDescriptionを使用したい場合はxmlnsにclr-namespace:System.Windows.Data;assembly=PresentationFrameworkを追加してください。
グループ化を行う場合はGroupStyleを指定する必要があります。
これを行わないとグループ化しても見た目に変化がありません。
規定のGroupStyleを使用する場合は以下の様にします。
using Livet; using System.Collections.ObjectModel; namespace CollectionViewSourceDemo3.Models { public class Library : NotificationObject { public Library() { BookList = new ObservableCollection<Book>(); BookList.Add(new Book("オーバーロード1", "オーバーロード", "丸山くがね")); BookList.Add(new Book("オーバーロード2", "オーバーロード", "丸山くがね")); BookList.Add(new Book("オーバーロード3", "オーバーロード", "丸山くがね")); BookList.Add(new Book("オーバーロード4", "オーバーロード", "丸山くがね")); BookList.Add(new Book("鋼の錬金術師1", "鋼の錬金術師", "荒川弘")); BookList.Add(new Book("鋼の錬金術師2", "鋼の錬金術師", "荒川弘")); BookList.Add(new Book("鋼の錬金術師3", "鋼の錬金術師", "荒川弘")); BookList.Add(new Book("銀の匙1", "銀の匙", "荒川弘")); BookList.Add(new Book("銀の匙2", "銀の匙", "荒川弘")); BookList.Add(new Book("アルスラーン戦記1", "アルスラーン戦記", "荒川弘")); } public ObservableCollection<Book> BookList { get; private set; } } public class Book : NotificationObject { public Book(string title, string series, string author) { Title = title; Series = series; Author = author; } public string Title { get; private set; } public string Author { get; private set; } public string Series { get; private set; } } }Modelでは本のデータを用意しているだけです。 本のタイトル等を変更することはないので変更通知プロパティにしていません。 次にViewModelのコードです。
using CollectionViewSourceDemo3.Models; using Livet; using System.Windows.Data; namespace CollectionViewSourceDemo3.ViewModels { public class MainWindowViewModel : ViewModel { private Library BookLibrary; public MainWindowViewModel() { BookLibrary = new Library(); CanGrouping = true; CanUngroup = false; BookList = ViewModelHelper.CreateReadOnlyDispatcherCollection( BookLibrary.BookList, m => new BookViewModel(m), DispatcherHelper.UIDispatcher); CompositeDisposable.Add(BookList); BookListViewSource = new CollectionViewSource() { Source = BookList }; } public ReadOnlyDispatcherCollection<BookViewModel> BookList { get; private set; } public CollectionViewSource BookListViewSource { get; private set; } #region CanGrouping変更通知プロパティ private bool _CanGrouping; public bool CanGrouping { get { return _CanGrouping; } private set { if (_CanGrouping == value) return; _CanGrouping = value; RaisePropertyChanged(); } } #endregion #region CanUngroup変更通知プロパティ private bool _CanUngroup; public bool CanUngroup { get { return _CanUngroup; } private set { if (_CanUngroup == value) return; _CanUngroup = value; RaisePropertyChanged(); } } #endregion /// <summary> /// グループ分けする /// </summary> public void Grouping() { CanGrouping = false; BookListViewSource.GroupDescriptions.Add(new PropertyGroupDescription("Author")); BookListViewSource.GroupDescriptions.Add(new PropertyGroupDescription("Series")); CanUngroup = true; } /// <summary> /// グループ化解除 /// </summary> public void Ungroup() { CanUngroup = false; BookListViewSource.GroupDescriptions.Clear(); CanGrouping = true; } } public class BookViewModel : ViewModel { private Book Book; public BookViewModel(Book book) { Book = book; } public string Title { get { return Book.Title; } } public string Author { get { return Book.Author; } } public string Series { get { return Book.Series; } } } }BookViewModelはBook(Modelクラス)のプロパティを公開しているだけです。 MainWindowViewModelでは本のリスト(CollectionViewSourceのソース)とCollectionViewSourceを作っています。 GroupingメソッドはCollectionViewSourceのグループ化定義を行うメソッドです。 CollectionViewSourceのグループ定義はGroupDescriptionsにグループ化条件を追加するだけです。(ソートの時と同じような感じです) プロパティ名によるグループ化を行う場合はPropertyGroupDescriptionを使用します。 サンプルコードの様に複数の条件を指定することもできます。 この場合、まず「Auther」でグループ化され、子グループ内でさらに「Series」でグループ化が行われます。 グループ化を解除したい場合はGroupDescriptionsをクリアするだけでOKです。 最後にViewのコードです。
<Window x:Class="CollectionViewSourceDemo3.Views.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" xmlns:l="http://schemas.livet-mvvm.net/2011/wpf" xmlns:v="clr-namespace:CollectionViewSourceDemo3.Views" xmlns:vm="clr-namespace:CollectionViewSourceDemo3.ViewModels" xmlns:data="clr-namespace:System.Windows.Data;assembly=PresentationFramework" Title="MainWindow" Height="350" Width="525"> <Window.DataContext> <vm:MainWindowViewModel/> </Window.DataContext> <i:Interaction.Triggers> <!--Windowが閉じたタイミングでViewModelのDisposeメソッドが呼ばれます--> <i:EventTrigger EventName="Closed"> <l:DataContextDisposeAction/> </i:EventTrigger> </i:Interaction.Triggers> <Window.Resources> <DataTemplate DataType="{x:Type vm:BookViewModel}"> <TextBlock> 【<Run Text="{Binding Series, Mode=OneWay}"/>】 <Run Text="{Binding Title, Mode=OneWay}"/> (<Run Text="{Binding Author, Mode=OneWay}"/>) </TextBlock> </DataTemplate> <DataTemplate x:Key="GroupHeadderTemplate"> <Border Background="WhiteSmoke" BorderThickness="0,0,0,2" BorderBrush="DarkBlue" > <TextBlock Text="{Binding Name}" Foreground="DarkBlue" FontSize="16"/> </Border> </DataTemplate> <CollectionViewSource x:Key="group" Source="{Binding BookList}"> <CollectionViewSource.GroupDescriptions> <data:PropertyGroupDescription PropertyName="Author"/> <data:PropertyGroupDescription PropertyName="Series"/> </CollectionViewSource.GroupDescriptions> </CollectionViewSource> </Window.Resources> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <GroupBox Grid.Column="0" Header="XAMLでグループ化定義"> <ListBox ItemsSource="{Binding Source={StaticResource group}}"> <ListBox.GroupStyle> <!--規定のグループスタイル--> <x:Static Member="GroupStyle.Default"/> </ListBox.GroupStyle> </ListBox> </GroupBox> <GroupBox Grid.Column="1" Header="ViewModelでグループ化定義"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <ListBox ItemsSource="{Binding BookListViewSource.View}"> <ListBox.GroupStyle> <GroupStyle HeaderTemplate="{StaticResource GroupHeadderTemplate}"/> </ListBox.GroupStyle> </ListBox> <StackPanel Grid.Row="1" HorizontalAlignment="Right" Orientation="Horizontal"> <Button Content="グループ化" IsEnabled="{Binding CanGrouping}"> <i:Interaction.Triggers> <i:EventTrigger EventName="Click"> <l:LivetCallMethodAction MethodTarget="{Binding}" MethodName="Grouping"/> </i:EventTrigger> </i:Interaction.Triggers> </Button> <Button Content="グループ化解除" IsEnabled="{Binding CanUngroup}"> <i:Interaction.Triggers> <i:EventTrigger EventName="Click"> <l:LivetCallMethodAction MethodTarget="{Binding}" MethodName="Ungroup"/> </i:EventTrigger> </i:Interaction.Triggers> </Button> </StackPanel> </Grid> </GroupBox> </Grid> </Window>このサンプルコードを実行し、グループ化させると以下の様になります。

<ListBox.GroupStyle> <x:Static Member="GroupStyle.Default"/> </ListBox.GroupStyle>もちろん、グループスタイルを変更して見た目を変更することもできます。 このサンプルコードではグループヘッダーを以下の様に定義して使用しています。
<DataTemplate x:Key="GroupHeadderTemplate"> <Border Background="WhiteSmoke" BorderThickness="0,0,0,2" BorderBrush="DarkBlue" > <TextBlock Text="{Binding Name}" Foreground="DarkBlue" FontSize="16"/> </Border> </DataTemplate>このテンプレートをGroupStyleのHeaderTemplateに指定すればOKです。 並び替えやフィルターと違って、条件設定だけでなくグループ化した際の見た目(GroupStyle)を定義・指定しないとグループ化表示ができない点に注意してください。 ----- 11/7修正 ----- アルスラーン戦記のシリーズ名が間違っていたのでサンプルコードと画像を修正しました。
スポンサーサイト