CollectionViewSources是否可嵌套?

时间:2013-07-10 11:46:10

标签: .net wpf mvvm collections

tldr:CollectionViewSource.Filter被另一个控件覆盖。如何进行两层过滤,以便控件只能看到预过滤的集合?

我有一个第三方gridcontrol,我通过ICollectionView绑定到我的viewmodel中的一个集合。

private CollectionViewSource _filteredCollection;

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

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

这很好用,允许gridcontrol自己进行过滤,分组和排序。 现在我想在网格之前应用我自己的过滤器(即只显示今天项目的按钮)

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上执行我的过滤,然后在它周围创建另一个我传递给gridcontrol的CollectionViewSource或CollectionView。

如果我在ICollectionView中包装_filteredCollection,则两层过滤工作完美但我无法排序或分组,因为ICollectionView的默认构造函数将CanSort和CanGroup设置为false。

我无法弄清楚如何将_filteredCollection提供给第二个CollectionViewSource的构造函数。是否有可能或者我是从错误的角度处理这个问题?

2 个答案:

答案 0 :(得分:2)

如果我理解正确,您想在列表中应用多个过滤器,不是吗?

如何将Filter过滤到管理多个谓词的主FilterHandler。为了使其更灵活,您可以将这些谓词添加到主FilterHandler将取消堆栈的列表或堆栈中。由于CollectionViewSources的刷新过程,我相信在下一个Refresh()时会考虑任何新的过滤器。

答案 1 :(得分: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;
    }
}

我没有用任何控件对此进行测试,但我认为它应该可行。