2

tldr:CollectionViewSource.Filter 被另一个控件覆盖。我怎样才能有两层过滤,以便控件只能看到预过滤的集合?

我有一个第三方网格控件,我通过 ICollectionView 绑定到我的视图模型中的集合。

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

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

我想不通的是如何将 _filteredCollection 输入到第二个 CollectionViewSource 的构造函数中。有可能还是我从错误的角度解决了这个问题?

4

2 回答 2

2

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

将 Filter 订阅到管理多个谓词的主 FilterHandler 怎么样。为了使其更灵活,您可以将这些谓词添加到您的主 FilterHandler 将取消堆叠的列表或堆栈中。感谢 CollectionViewSources 的刷新过程,我相信任何新的过滤器都会在下一次 Refresh() 时被考虑在内。

于 2013-07-18T09:03:57.447 回答
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 回答