FC2ブログ

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

CollectionViewSourceのフィルター機能

 CollectionViewSourceには指定した条件を満たす項目のみを表示するフィルター機能も持っています。
 フィルター機能も並べ替えと同じく元コレクションは変更させず表示用のViewのみ変更させています。
 以下のサンプルではCollectionViewSourceのフィルター機能を使って本のタイトル検索を行っています。
 Modelは前回の並べ替えの時と同じなので省略します(本の情報を表すModelがあるだけです)。
using CollectionViewSourceDemo2.Models;
using Livet;
using System.ComponentModel;
using System.Windows.Data;
using Livet.EventListeners;

namespace CollectionViewSourceDemo2.ViewModels
{
    public class MainWindowViewModel : ViewModel
    {
        private Model Model;

        public MainWindowViewModel()
        {
            Model = new Model();
            Keyword = "";

            // ModelコレクションをViewModelコレクションに変換
            Books = ViewModelHelper.CreateReadOnlyDispatcherCollection(
                Model.Books,
                m => new BookViewModel(m),
                DispatcherHelper.UIDispatcher);
            CompositeDisposable.Add(Books);

            // CollectionViewSource作成
            BooksViewSource = new CollectionViewSource() { Source = Books };

            // タイトル検索用フィルター
            CompositeDisposable.Add(new EventListener<FilterEventHandler>(
                h => BooksViewSource.Filter += h,
                h => BooksViewSource.Filter -= h,
                (sender, e) =>
                {
                    // キーワードが空ならすべて表示
                    var book = (BookViewModel)e.Item;
                    e.Accepted = string.IsNullOrWhiteSpace(Keyword)
                        ? true
                        : book.Title.Contains(Keyword);
                }));
        }

        public ReadOnlyDispatcherCollection<BookViewModel> Books { get; private set; }

        public CollectionViewSource BooksViewSource { get; private set; }

        #region Keyword変更通知プロパティ
        private string _Keyword;
        /// <summary>
        /// タイトル検索キーワード
        /// </summary>
        public string Keyword
        {
            get
            { return _Keyword; }
            set
            {
                if (_Keyword == value)
                    return;
                _Keyword = value;
                RaisePropertyChanged();
            }
        }
        #endregion

        /// <summary>
        /// タイトル検索を行う。
        /// </summary>
        public void TitleSearch()
        {
            BooksViewSource.View.Refresh();
        }

        /// <summary>
        /// タイトル検索結果をクリアする
        /// </summary>
        public void ClearSearchResult()
        {
            Keyword = "";
            TitleSearch();
        }
    }

    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 int Price
        {
            get { return Book.Price; }
        }
    }
}
 BookViewModelはModelのプロパティを公開しているだけです。(前回と同じ)
 CollectionViewSourceのフィルター機能はFilterイベントを使って行われます。
 サンプルコードではLivetの機能を使用しているので見慣れない形をしているかもしれませんが、CollectionViewSourceのFilterイベントにイベントハンドラを登録しているだけです。
 あとはそのイベントハンドラで項目を表示するかどうかを判断するようなコードを記載します。
 Filterイベントハンドラでは引数としてFilterEventArgsが渡されます。
 このイベント変数はAcceptedプロパティとItemプロパティを持っています。
 Acceptedプロパティはフィルターの結果を表すプロパティでこの値がtrueの項目が表示されます。
 Itemプロパティには評価対象のインスタンスが入っています。(object型なのでキャストする必要があります)
 Itemをキャストして表示するかどうかを評価し、その結果をAcceptedプロパティに設定します。
 ここでは、Titleが指定したキーワードを含んでいるかどうかで表示するかどうかを判断しています。
 キーワードが指定されていない場合は全表示としています。

 これでフィルター機能は使えるようになっていますが、これだけだとCollectionViewが更新されないので適切なタイミングでCollectionViewを更新する必要があります。
 このサンプルでは「検索」ボタンを押した際にCollectionViewを更新するようにしています。
 CollectionViewの更新を行うにはCollectionViewインスタンスのRefreshメソッドを呼ぶだけでOKです。
 RefreshメソッドはUIスレッドから呼び出さないと例外が発生するので注意してください。

<Window x:Class="CollectionViewSourceDemo2.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:CollectionViewSourceDemo2.Views"
        xmlns:vm="clr-namespace:CollectionViewSourceDemo2.ViewModels"
        Title="MainWindow" Height="250" Width="625">
    
    <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}">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding Title}" Margin="0,0,10,0"/>
                <TextBlock Text="{Binding Author, StringFormat=作者:{0}}" Margin="0,0,10,0"/>
                <TextBlock Text="{Binding Price, StringFormat=価格:{0}円}"/>
            </StackPanel>
        </DataTemplate>
    </Window.Resources>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <Grid Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <TextBlock Grid.Column="0" Text="検索ワード:"/>
            <TextBox Grid.Column="1" Text="{Binding Keyword}"/>
            <Button Grid.Column="2" Content="検索">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="Click">
                        <l:LivetCallMethodAction MethodTarget="{Binding}" MethodName="TitleSearch"/>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </Button>
            <Button Grid.Column="3" Content="クリア">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="Click">
                        <l:LivetCallMethodAction MethodTarget="{Binding}" MethodName="ClearSearchResult"/>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </Button>
        </Grid>

        <GroupBox Grid.Row="1" Grid.Column="0" Header="元コレクション">
            <ListBox ItemsSource="{Binding Books}"/>
        </GroupBox>
        <GroupBox Grid.Row="1" Grid.Column="1" Header="ViewModelで作ったCollectionViewSource">
            <ListBox ItemsSource="{Binding BooksViewSource.View}"/>
        </GroupBox>
    </Grid>
</Window>
 Viewでは元のコレクションとCollectionViewの2つを表示しています。
 検索ワードを入力して「検索」ボタンを押すとCollectionViewのリストのみが更新されます。(元コレクションに変化がないことが確認できます)
 以下は「きんいろ」でタイトル検索した結果です。
CollectionViewSource-Filter.png
 元のコレクションを再度表示したい場合は全ての項目が表示されるような条件を入力してCollectionViewを再評価します。
 フィルター機能自体を削除したい場合は、Filterイベントからイベントハンドラを解除すればフィルター機能なしのCollectionViewSourceに戻ります。
 
スポンサーサイト

テーマ : プログラミング
ジャンル : コンピュータ

コメントの投稿

非公開コメント

カレンダー
09 | 2018/10 | 11
- 1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31 - - -
全記事表示リンク

全ての記事を表示する

カテゴリ
タグリスト

月別アーカイブ
11  09  08  07  06  05  04  03  02  01  12  11  10  09  08  07  06  04  03  02  01  12  11  10  09  08  07  06  05  04  03  02  01  12  11  10  09 
最新記事
リンク
最新コメント
検索フォーム
Amazon
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。