[Silverlight]PagedCollectionViewとチェックボックスを組み合わせた動的フィルタリングソリューション

31067 ワード

前の記事でにおいて、PagedCollectionはフィルタ機能を提供する.
実際のプロジェクトでは、このようなニーズがあります.
すなわち、上述した例のフィルタGender列の特定の項目のような、DataGirdの関連項目は、チェックボックスによって動的にフィルタされる.ObservableCollectionを直接操作すればいいのではないかと考えている人もいるかもしれません.2つの問題があります
  • PagedCollectionViewはもともとフィルタ機能を提供していますが、ObservableCollectionを操作するのは少し愚かではないでしょうか.
  • ObservableCollectionを操作すると(フィルタリングの場合は一般的に削除される)、集合自体も変化するが、PagedCollectionViewが提供するフィルタリングは、集合項目
  • を変更することなくUIに変化を反映するだけである.
    上記の2つの問題がある以上、PagedCollectionViewのFilterプロパティを正直に使ってフィルタリングを実現しましょう.
    しかし依然として問題が存在して、これはしばらく言わないで、まず正常な情況の下で私達が以上の需要を実現するためにしなければならない仕事を見てみましょう
    まずXAMLに4つのチェックボックスを追加します
    <StackPanel Orientation="Horizontal" x:Name="cbContainer">
    
         <CheckBox Content=" " IsChecked="True"  Click="CheckBox_Click"/>
    
         <CheckBox Content=" " IsChecked="True"  Click="CheckBox_Click" />
    
         <CheckBox Content=" " IsChecked="True"  Click="CheckBox_Click" />
    
    </StackPanel>

    3つのCheckBoxと1つのStackPanelをレイアウトの必要性に加えて、すべてのCheckBoxを巡回して操作をフィルタすることができます.
    次はCheckBoxでClickのcsコードでは次のような作業を行います.
    チェックボックスが1つしかないなら簡単にできます
    string genderToFilter = ((CheckBox)sender).Content.ToString();
    
    _pcv.Filter = p => ((Person)p).Gender == genderToFilter;

    しかし、今私たちはN個のCheckBoxを持っています.PagedCollectionViewのFilterはまたPredicateなので、私たちはそうするしかありません(ここでは2個のCheckBoxしかないと仮定します.本当に面倒だからです).
      var els = cbContainer.Children;
    
                var cb1 = els[0] as CheckBox;
    
                var cb2 = els[1] as CheckBox;
    
    
    
                Predicate<object> predicate;
    
                if (cb1.IsChecked == true || cb2.IsChecked == false) {
    
                    predicate = p => ((Person)p).Gender == cb1.Content.ToString();
    
                }
    
                else if (cb1.IsChecked == true || cb2.IsChecked == false) {
    
                    predicate = p => ((Person)p).Gender == cb1.Content.ToString() || ((Person)p).Gender == cb2.Content.ToString();
    
                }
    
                else {
    
                    predicate = p => ((Person)p).Gender == cb2.Content.ToString();
    
                }
    
    
    
                _pcv.Filter = predicate;

    さらにいくつかのチェックボックスがあれば、これらの判断は死んでしまうことがわかります.この問題を解決する鍵は、Predicateを動的に構築することです.そこで、ここでは、PredicateBuilderを作成し、パッチ式によってPredicateの動的構築を支援します.
    public static class PredicateBuilder {
    
            public static Expression<Func<T, bool>> True<T>() { return f => true; }
    
            public static Expression<Func<T, bool>> False<T>() { return f => false; }
    
    
    
            public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1,
    
                                                                Expression<Func<T, bool>> expr2) {
    
                var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
    
                return Expression.Lambda<Func<T, bool>>
    
                      (Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
    
            }
    
    
    
            public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1,
    
                                                                 Expression<Func<T, bool>> expr2) {
    
                var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
    
                return Expression.Lambda<Func<T, bool>>
    
                      (Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
    
            }
    
    
    
            public static Predicate<T> ConvertToPredicate<T>(this Func<T, bool> func) {
    
                return new Predicate<T>(func);
    
            }
    
        }

    コードは比較的簡単で、あまり説明しません.最後のConvertToPredicateこの拡張方法は、構築されたExpressionをコンパイルしたFuncをPredicateに変換するために使用されることに注意してください.
    このクラスの補助があったら、私たちのCheckBox_Click事件は手間が省けて優雅だ
            private void CheckBox_Click(object sender, RoutedEventArgs e) {
    
                var els = cbContainer.Children;
    
                var predicate = PredicateBuilder.False<object>();
    
                foreach (var el in els) {
    
                    var cb = el as CheckBox;
    
                    if (cb.IsChecked == true) {
    
                        predicate = predicate.Or(p => ((Person)p).Gender == cb.Content.ToString());
    
                    }
    
                }
    
                _pcv.Filter = predicate.Compile().ConvertToPredicate<object>();
    
            }

    ここまで問題を解決して、Slの企業レベルの開発をする兄弟達に役に立つことを望みます
    Okay,have fun~