2

tldr: CollectionViewSource.Filter は別のコントロールによって上書きされます。コントロールが事前にフィルター処理されたコレクションのみを参照できるように、2 層のフィルター処理を行うにはどうすればよいですか?

ICollectionView を介してビューモデルのコレクションにバインドするサードパーティのグリッド コントロールがあります。

private CollectionViewSource _filteredCollection;

public ItemListViewModel (List<ItemViewModel> items)
{
    _items = items;
    _filteredCollection = new CollectionViewSource {Source = _items};
}

public ICollectionView AllInstructions
{
    get { return _filteredCollection.View; }
}

これは正常に機能し、グリッド コントロールが独自のフィルタリング、グループ化、および並べ替えを実行できるようにします。ここで、グリッドのフィルターの前に独自のフィルターを適用したいと思います (つまり、今日のアイテムのみを表示するボタン)。

public ItemListViewModel (List<ItemViewModel> items)
{
    ...
    _filteredCollection.Filter += new FilterEventHandler(FilterByDate);
}

private void FilterByDate(object sender, FilterEventArgs e)
{
    var item = e.Item as ItemViewModel;

    if (item == null)
    {
        e.Accepted = false;
    }
    else
    {
        e.Accepted = item.CreatedDate >= _selectedDate;
    }
}

新しいフィルターは期待どおりに機能します。問題は、gridcontrol が適切に機能せず、独自のフィルタで上書きしてしまうことです。

私が考えていたのは、_filteredCollection CVS でフィルタリングを実行し、その周りに別の CollectionViewSource または CollectionView を作成して、グリッド コントロールに渡すことでした。

_filteredCollection を ICollectionView にラップすると、2 層のフィルタリングは完全に機能しますが、ICollectionView の既定のコンストラクターの CanSort と CanGroup が false に設定されているため、並べ替えやグループ化はできません。

私が理解できないのは、_filteredCollection を 2 番目の CollectionViewSource のコンストラクターにフィードする方法です。それは可能ですか、それとも間違った角度からこの問題に取り組んでいますか?

4

2 に答える 2

2

次のコードのように、ListCollectionViewから派生させることにより、定義済みのフィルターを使用して独自のコレクション ビューを作成できます。

class FilteredListCollectionView : ListCollectionView
{
    // internal filter
    private Predicate<object> preFilter;

    // public filter
    private Predicate<object> filter;

    public FilteredListCollectionView(IList list)
        : base(list)
    {
    }

    private Predicate<object> GetCombinedFilter()
    {
        if (this.preFilter != null)
            return this.filter != null ? x => this.preFilter(x) && this.filter(x) : this.preFilter;
        else
            return this.filter;
    }

    public Predicate<object> PreFilter
    {
        get { return this.preFilter; }
        set
        {
            this.preFilter = value;
            base.Filter = this.GetCombinedFilter();
        }
    }

    public override Predicate<object> Filter
    {
        get { return base.Filter; }
        set
        {
            this.filter = value;
            base.Filter = this.GetCombinedFilter();
        }
    }
}

これで、次のように使用できます。

private FilteredListCollectionView _filteredCollection;

public ItemListViewModel(List<ItemViewModel> items)
{
    _items = items;
    _filteredCollection = new FilteredListCollectionView(_items);
    _filteredCollection.PreFilter = FilterByDate;
}

public ICollectionView AllInstructions
{
    get { return _filteredCollection; }
}

private bool FilterByDate(object obj)
{
    var item = obj as ItemViewModel;

    if (item == null)
    {
        return false;
    }
    else
    {
        return item.CreatedDate >= _selectedDate;
    }
}

これをコントロールでテストしたことはありませんが、うまくいくはずです。

于 2013-07-19T21:05:09.353 に答える
2

私の理解が正しければ、リストにいくつかのフィルターを適用したいと思いませんか?

いくつかの述語を管理するメインの FilterHandler に Filter をサブスクライブするのはどうですか。より柔軟にするために、これらの述語を、メインの FilterHandler がアンスタックするリストまたはスタックに追加できます。CollectionViewSources の更新プロセスのおかげで、次の Refresh() で新しいフィルターが考慮されると思います。

于 2013-07-18T09:03:57.447 に答える