WPF CollectionViewSource 多个视图?

19

我编写了一个带搜索扩展功能的自定义 WPF 控件,我们将其称为 MyControl。 该控件是 ItemsControl 类的子类。

因此,我像这样向其提供数据源:

控件本身使用

protected override void OnItemsSourceChanged(System.Collections.IEnumerable oldValue, System.Collections.IEnumerable newValue)
{
    if (newValue != null)
    {
        ICollectionView view = CollectionViewSource.GetDefaultView(newValue);
        view.Filter += this.FilterPredicate;
    }

    if (oldValue != null)
    {
        ICollectionView view = CollectionViewSource.GetDefaultView(oldValue);
        view.Filter -= this.FilterPredicate;
    }

    base.OnItemsSourceChanged(oldValue, newValue);
}

过滤源集合的视图(从而在内部ListBox中显示它)。

现在假设我们在XAML中定义了10个这些具有相同DynamicSource的MyControl。 问题是,如果其中一个对源集合应用了过滤器,则也会影响所有其他实例。

您将如何更改控件以避免出现此行为?

2个回答

45

在这种情况下,通常希望为集合的每个不同过滤用途创建单独的 ICollectionView 实例。不应使用特定的 ICollectionView 实现,因为如果 ItemsSource 绑定到不同类型的集合,则需要使用的 CollectionView 类型可能会发生更改。

 ICollectionView filteredView = new CollectionViewSource { Source=newValue }.View;

使用此方法将自动提供正确类型的ICollectionView。

不幸的是,在这种情况下,你可能会发现很难将不同的集合应用于自定义控件的ItemsPresenter上,因为所有这些魔法都由基类ItemsControl类完成,并且依赖于它管理的ItemsSource/Items属性。当使用类似于ItemsControl默认模板的东西时,就会发生这种情况。

如果您实际上使用单独的ListBox控件(并在ControlTemplate中使用TemplateBinding绑定所有的ItemsSource属性,如果需要),那么您应该能够简单地在控件上添加一个新的ICollectionView DP(我建议只读),以保存筛选版本的集合,并将模板ListBox的ItemsSource绑定到该新属性。


1
好的,太棒了,它真的有效。非常感谢!只是一个新手问题——你所说的“readonly”是指.RegisterReadOnly()吗? - theSpyCry
我之所以问这个问题,是因为在ItemsSourceChanged事件中,我正在设置ItemsSourceView = new CollectionViewSource { Source = newValue }.View。其中ItemsSourceView是一个DP,所以我不能简单地删除setter。 - theSpyCry
2
是的。这不仅仅是更改初始化: private static readonly DependencyPropertyKey MyDPPropertyKey = DependencyProperty.RegisterReadOnly(...); public static readonly DependencyProperty MyDPProperty = MyDPPropertyKey.DependencyProperty; public object MyDP { get { return (object)GetValue(MyDPProperty); } private set { SetValue(MyDPPropertyKey, value); } } - John Bowen
我通常尽量不实例化一个新的(Observable)Collection<T>,我总是将集合本身标记为只读,并在需要时清除/重新填充它。 - Michael

7
问题在于对于给定的源,CollectionViewSource.GetDefaultView(object)将始终返回相同的ICollectionView实例,这是任何ItemsControl扩展在显示该源时使用的内容。
您可以通过创建一个新的ICollectionView实例来绕过此问题,以便每个控件都可以独立过滤集合,然后显式地将每个控件的ItemsSource属性绑定到该特定视图。所需的ICollectionView类型取决于您的情况,但通常适用ListCollectionView

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接