13

ViewModel の ListCollectionView にバインドされた ListView を使用して、MVVM デザイン パターンを使用しています。ListView のフィルター処理に使用するコンボボックスもいくつかあります。ユーザーがコンボボックスから項目を選択すると、ListView は選択された項目に対してフィルター処理されます。すでにフィルタリングされているものの上にフィルタリングしたいときはいつでも、前のフィルターが元に戻されます。フィルターを外す場合も同様です。1 つのコンボボックスのフィルターを削除すると、すべてのフィルターが削除され、元のリストが表示されます。同じ ListCollectionView に複数の個別のフィルターを設定することは可能ですか?

私は何か間違ったことをしていますか、それとも単にサポートされていませんか? ここで私のアプリケーションのスクリーン キャプチャを見つけて、私が達成しようとしていることを確認できます。これがフィルタリングのための私のコードです...

    /// <summary>
    /// Filter the list
    /// </summary>
    /// <param name="filter">Criteria and Item to filter the list</param>
    [MediatorMessageSink("FilterList", ParameterType = typeof(FilterItem))]
    public void FilterList(FilterItem filter)
    {
        // Make sure the list can be filtered...
        if (Products.CanFilter)
        {
            // Now filter the list
            Products.Filter = delegate(object obj)
            {
                Product product = obj as Product;

                // Make sure there is an object
                if (product != null)
                {
                    bool isFiltered = false;
                    switch (filter.FilterItemName)
                    {
                        case "Category":
                            isFiltered = (product.Category.IndexOf(filter.Criteria, StringComparison.CurrentCultureIgnoreCase)) != -1 ? true : false;
                            break;

                        case "ClothingType":
                            isFiltered = (product.ClothingType.IndexOf(filter.Criteria, StringComparison.CurrentCultureIgnoreCase)) != -1 ? true : false;
                            break;

                        case "ProductName":
                            isFiltered = (product.ProductName.IndexOf(filter.Criteria, StringComparison.CurrentCultureIgnoreCase)) != -1 ? true : false;
                            break;

                        default:
                            break;
                    }

                    return isFiltered;
                }
                else
                    return false;
            };
        }
    }
4

2 に答える 2

29

Filter プロパティを設定するたびに、以前のフィルターがリセットされます。これは事実です。どうすれば複数のフィルターを使用できますか?

ご存じのとおり、フィルタリングには と の 2 つの方法がありCollectionViewますCollectionViewSource。最初のケースでCollectionViewは、デリゲートでフィルタリングし、複数のフィルターを実行するには、カスタム フィルターを集約するクラスを作成し、フィルター アイテムごとに 1 つずつ呼び出します。次のコードのように:

  public class GroupFilter
  {
    private List<Predicate<object>> _filters;

    public Predicate<object> Filter {get; private set;}

    public GroupFilter()
    {
      _filters = new List<Predicate<object>>();
      Filter = InternalFilter;
    }

    private bool InternalFilter(object o)
    {
      foreach(var filter in _filters)
      {
        if (!filter(o))
        {
          return false;
        }
      }

      return true;
    }

    public void AddFilter(Predicate<object> filter)
    {
      _filters.Add(filter);
    }

    public void RemoveFilter(Predicate<object> filter)
    {
      if (_filters.Contains(filter))
      {
        _filters.Remove(filter);
      }
    }    
  }

  // Somewhere later:
  GroupFilter gf = new GroupFilter();
  gf.AddFilter(filter1);
  listCollectionView.Filter = gf.Filter;

フィルタリングされたビューを更新するには、ListCollectionView.Refresh()メソッドを呼び出します。

2 番目のケースでは、イベントをCollectionViewSource使用Filterしてコレクションをフィルタリングします。複数のイベント ハンドラーを作成して、さまざまな条件でフィルター処理できます。このアプローチの詳細については、Bea Stollnitz によるこの素晴らしい記事を参照してください:複数のフィルターを適用するにはどうすればよいですか? (アーカイブ)

お役に立てれば。

乾杯、アンバカ。

于 2009-12-20T10:02:29.687 に答える
8

ユーザーがフィルタリングするたびに、コードはコレクション ビュー内のデリゲートを新しいものに置き換えます。Filterさらに、新しいものは、ユーザーが で選択した特定の基準のみをチェックしますComboBox

必要なのは、すべての基準をチェックする単一のフィルター ハンドラーです。何かのようなもの:

public MyViewModel()
{
    products = new ObservableCollection<Product>();
    productsView = new ListCollectionView(products);
    productsView.Filter += FilterProduct;
}

public Item SelectedItem
{
    //get,set omitted. set needs to invalidate filter with refresh call
}

public Type SelectedType
{
    //get,set omitted. set needs to invalidate filter with refresh call
}

public Category SelectedCategory
{
    //get,set omitted. set needs to invalidate filter with refresh call
}

public ICollection<Product> FilteredProducts
{
    get { return productsView; }
}

private bool FilterProduct(object o)
{
    var product = o as Product;

    if (product == null)
    {
        return false;
    }

    if (SelectedItem != null)
    {
        // filter according to selected item
    }

    if (SelectedType != null)
    {
        // filter according to selected type
    }

    if (SelectedCategory != null)
    {
        // filter according to selected category
    }

    return true;
}

ビューを適切なプロパティにバインドするだけで、フィルタリングが機能します。

于 2009-12-20T10:10:35.547 に答える