基本操作 > フィルタリング > フィルタリングを適用する(DataCollection を使用) |
IDataCollection インターフェイスでは、Filter プロパティを使用したデータのフィルタ処理がサポートされます。Filter プロパティは、コレクション内の各項目に対して呼び出されるメソッドを指定します。このメソッドが true を返す場合、その項目はビューに含まれます。このメソッドが false を返す場合、その項目はフィルタ処理されて非表示になります(このタイプの方法は、述語と呼ばれています)。次のセクションでは、FlexGrid .NET 4.5.2および.NET 5バージョンでDataCollectionを使用してフィルターデータを実装する方法を学習します。
ユーザーコントロールSearchBox をIDataCollectionフィルタの例とします。このコントロールは、検索する値をユーザーが入力する TextBox コントロールと、1 つのタイマーから構成されます。このタイマーは、検索する値をユーザーが入力する際に、1 文字ごとにフィルタが適用し直されることがないように、短時間の遅延を提供します。
ユーザーが入力を停止すると、このタイマーが次のコードを使って動作し、フィルタを適用します。
C# |
コードのコピー
|
---|---|
_view.Filter = null; _view.Filter = (object item) => { // 検索テキストを取得します。 var srch = _txtSearch.Text; // テキストがない場合、すべての項目を表示します。 if (string.IsNullOrEmpty(srch)) { return true; } // 任意の指定したプロパティのテキストを含む項目を表示します。 foreach (PropertyInfo pi in _propertyInfo) { var value = pi.GetValue(item, null) as string; if (value != null && value.IndexOf(srch, StringComparison.OrdinalIgnoreCase) > -1) { return true; } } // この項目を除外します。 return false; }; |
ラムダ関数を使って Filter プロパティの値を設定していることに注意してください。独立したメソッドを提供することもできましたが、この表記は簡潔であり、必要に応じてローカル変数を使用できるため、こちらの方が使いやすい場合も数多く存在します。
このラムダ関数は、項目をパラメータとして受け取り、オブジェクトの指定されたプロパティの値を取得し、オブジェクトのいずれかのプロパティに検索対象の文字列が含まれる場合は true を返します。
たとえば、オブジェクトの型が "Song" であり、指定されたプロパティが "Title"、"Album"、および "Artist" である場合、この関数は、曲のタイトル、アルバム、またはアーティスト内に検索対象の文字列が見つかった場合に true を返します。
フィルタが適用されると、グリッド(および DataCollection オブジェクトに連結されているその他すべてのコントロール)にはフィルタの結果が直ちに反映されて、フィルタによって選択された項目のみが表示されます。
フィルタ処理とグループ化は、組み合わせて使用しても適切に機能することに注目してください。次の図(MainTestApplication サンプルより)に、非常に多い曲のリストにフィルタが適用されている様子を示します。
この図は、フィルタが "Water" という単語に設定された際に取得したものです。フィルタは、すべてのフィールド(曲、アルバム、アーティスト)で一致を検索します。このため、"Creedence Clearwater Revival" の曲はすべて自動的に含まれます。
グリッドの上に表示されているステータスラベルに注目してください。リストが変更されるたびに、このラベルは自動的に更新されます。したがって、フィルタが適用されると、このステータスは新しいフィルタを反映して更新されます。ステータスを更新するルーチンは、LINQ を使用して、選択されたアーティスト、アルバム、および曲の数を計算し、合計のストレージと再生時間を計算します。曲のステータス更新ルーチンは、次のように実装されます。
C# |
コードのコピー
|
---|---|
// update song status void UpdateSongStatus() { var view = _flexiTunes.ItemsSource as DataCollection; var songs = view.OfType<Song>(); _txtSongs.Text = string.Format( "{0:n0} Artists; {1:n0} Albums; {2:n0} Songs; " + "{3:n0} MB of storage; {4:n2} days of music.", (from s in songs select s.Artist).Distinct().Count(), (from s in songs select s.Album).Distinct().Count(), (from s in songs select s.Name).Count(), (double)(from s in songs select s.Size/1024.0/1024.0).Sum(), (double)(from s in songs select s.Duration/3600000.0/24.0).Sum()); } |
このルーチンは、グリッドには直接関連しませんが、大きなデータソースに連結されたグリッドを表示する際に、情報の取得が必要になることが多いため、LINQ 機能を活用する方法を示しました。
上の LINQ 文は、Distinct および Count コマンドを使用して、現在データソースで公開されているアーティスト、アルバム、および曲の数を計算します。また、Sum コマンドを使用して、現在の選択範囲の合計のストレージと再生時間を計算します。
ICollectionView のフィルタ述語は子行をフィルタできません。子行をフィルタできるには、子行のタイプはICollectionViewに設定されている必要があります。親グリッドと子行の両方がICollectionViewタイプに設定されている場合、両方をフィルタすることが可能です。DataCollection を使用する子行では、ソートが対応されていません。
ユーザーコントロールSearchBox をDataCollectionフィルタの例とします。このコントロールは、検索する値をユーザーが入力する TextBox コントロールと、1 つのタイマーから構成されます。このタイマーは、検索する値をユーザーが入力する際に、1 文字ごとにフィルタが適用し直されることがないように、短時間の遅延を提供します。
ユーザーが入力を停止すると、このタイマーが次のコードを使って動作し、フィルタを適用します。
ラムダ関数を使って Filter プロパティの値を設定していることに注意してください。独立したメソッドを提供することもできましたが、この表記は簡潔であり、必要に応じてローカル変数を使用できるため、こちらの方が使いやすい場合も数多く存在します。
このラムダ関数は、項目をパラメータとして受け取り、オブジェクトの指定されたプロパティの値を取得し、オブジェクトのいずれかのプロパティに検索対象の文字列が含まれる場合は true を返します。
C# |
コードのコピー
|
---|---|
C1DataCollection<Customer> _view; public MainWindow() { InitializeComponent(); //グリッドデータを生成します。 var customerlist = Customer.GetCustomerList(50); _view = new C1.DataCollection.C1DataCollection<Customer>(customerlist); //グリッドにデータをバインドします。 grid.ItemsSource = _view; } private void filter_Click(object sender, RoutedEventArgs e) { //検索テキストを取得します。 if (!string.IsNullOrEmpty(_txtSearch.Text)) { FilterTextExpression filterText = new FilterTextExpression("FirstName", FilterOperation.Equal, _txtSearch.Text, false, false); _view.FilterAsync(filterText); } } |