【问题标题】:CollectionViewSource Filter not refreshed when Source is changed更改源时未刷新 CollectionViewSource 过滤器
【发布时间】:2010-10-14 06:45:21
【问题描述】:

我有一个绑定到 CollectionViewSource 的 WPF ListView。它的来源绑定到一个属性,如果用户选择一个选项,它可以改变。

当列表视图源由于属性更改事件而更新时,所有内容都会正确更新,但不会刷新视图以考虑 CollectionViewSource 过滤器中的任何更改。

如果我将处理程序附加到 Source 属性绑定到的 Changed 事件,我可以刷新视图,但这仍然是旧视图,因为绑定尚未更新列表。

当源发生变化时,是否有一种不错的方法来刷新视图并重新评估过滤器?

干杯

【问题讨论】:

  • 万一有人发现这个,它现在有点过时了。在 WPF 4.5 中,添加了新功能以允许“实时”排序、过滤和分组。见jonathanantoine.com/2011/10/05/…

标签: wpf filter collections


【解决方案1】:

您是在更改分配给CollectionViewSource.Source 的实际集合实例,还是只是在它绑定到的属性上触发PropertyChanged?

如果设置了Source 属性,则应该为新源集合中的每个项目调用过滤器,所以我认为正在发生其他事情。您是否尝试过手动设置Source,而不是使用绑定并查看您是否仍能得到您的行为?

编辑:

您使用的是CollectionViewSource.View.Filter 属性,还是CollectionViewSource.Filter 事件?当你设置一个新的Source 时,CollectionView 会被吹走,所以如果你在CollectionView 上设置了一个Filter,它将不再存在。

【讨论】:

  • 是的,我正在更改集合,并且列表视图中的项目会更新以反映新集合。但是过滤器不会重新评估。手动操作没有帮助: ((CollectionViewSource)this.Resources["logEntryViewSource"]).Source = _application.CurrentLog.Entries.ObservableCollection
【解决方案2】:

框架不支持基于 PropertyChanged 事件更新 CollectionView.Filter。 有很多解决方案。

1) 在集合内的对象上实现 IEditableObject 接口,并在更改过滤器所基于的属性时调用 BeginEdit 和 EndEdit。 您可以在 Dr.WPF 的优秀博客上阅读更多相关信息:Editable Collections by Dr.WPF

2) 创建以下类并在更改的对象上使用 RefreshFilter 函数。

public class FilteredObservableCollection<T> : ObservableCollection<T>
{
    public void RefreshFilter(T changedobject)
    {
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, changedobject, changedobject));
    }        
}

例子:

public class TestClass : INotifyPropertyChanged
{
    private string _TestProp;
    public string TestProp
    {
        get{ return _TestProp; }
        set
        { 
            _TestProp = value;
            RaisePropertyChanged("TestProp");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged(string propertyName)
    {
        var handler = this.PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }
}


FilteredObservableCollection<TestClass> TestCollection = new FilteredObservableCollection<TestClass>();

void TestClass_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    switch (e.PropertyName)
    {
        case "TestProp":
            TestCollection.RefreshFilter(sender as TestClass);
            break;
    }
}

在创建TestClass对象的时候订阅它的PropertyChanged事件,但不要忘记在对象被移除时解开事件处理程序,否则可能会导致内存泄漏

或

将 TestCollection 注入 TestClass 并在 TestProp 设置器中使用 RefreshFilter 函数。 无论如何,这里的魔法是由 NotifyCollectionChangedAction.Replace 完成的,它完全更新了项目。

【讨论】:

  • 我目前被 .NET 4.0 困住,而 IEditableObject 解决方案就像一个魅力。
  • 我无法让 IEditableObject 工作。但是 FilteredObservableCollection 效果很好。感谢您的解决方案
【解决方案3】:

我找到了一种特定的解决方案,可以将 ObservableCollection 类扩展为监视它所包含的对象的属性变化的类 here。

这是我对代码进行了一些修改:

namespace Solution
{
public class ObservableCollectionEx<T> : ObservableCollection<T> where T : INotifyPropertyChanged
    {
        protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            if (e != null)  // There's been an addition or removal of items from the Collection
            {
                Unsubscribe(e.OldItems);
                Subscribe(e.NewItems);
                base.OnCollectionChanged(e);
            }
            else
            {
                // Just a property has changed, so reset the Collection.
                base.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));

            }

        }

        protected override void ClearItems()
        {
            foreach (T element in this)
                element.PropertyChanged -= ContainedElementChanged;

            base.ClearItems();
        }

        private void Subscribe(IList iList)
        {
            if (iList != null)
            {
                foreach (T element in iList)
                    element.PropertyChanged += ContainedElementChanged;
            }
        }

        private void Unsubscribe(IList iList)
        {
            if (iList != null)
            {
                foreach (T element in iList)
                    element.PropertyChanged -= ContainedElementChanged;
            }
        }

        private void ContainedElementChanged(object sender, PropertyChangedEventArgs e)
        {
            OnPropertyChanged(e);
            // Tell the Collection that the property has changed
            this.OnCollectionChanged(null);

        }
    }
}

【讨论】:

    【解决方案4】:

    聚会可能有点晚了,但以防万一

    您也可以使用CollectionViewSource.LiveSortingProperties 我是通过this 博文找到的。

    public class Message : INotifyPropertyChanged
    {
        public string Text { get; set; }
        public bool Read { get; set; }
    
        /* for simplicity left out implementation of INotifyPropertyChanged */
    }
    
    public ObservableCollection<Message> Messages {get; set}
    
    ListCollectionView listColectionView = (ListCollectionView)CollectionViewSource.GetDefaultView(Messages);
    listColectionView.IsLiveSorting = true;
    listColectionView.LiveSortingProperties.Add(nameof(Message.Read));
    listColectionView.SortDescriptions.Add(new SortDescription(nameof(Message.Read), ListSortDirection.Ascending));
    

    【讨论】:

      【解决方案5】:

      我找到了一个相对简单的方法来做到这一点。 我将只读的 ICollectionView 属性更改为 get/set 并添加了引发的属性事件:

         Property TypeFilteredCollection As ICollectionView
              Get
                  Dim returnVal As ICollectionView = Me.TypeCollection.View
                  returnVal.SortDescriptions.Add(New SortDescription("KeyName", ListSortDirection.Ascending))
                  Return returnVal
              End Get
              Set(value As ICollectionView)
      
                  RaisePropertyChanged(NameOf(TypeFilteredCollection))
              End Set
          End Property
      

      然后更新,我只是用:

          Me.TypeFilteredCollection = Me.TypeFilteredCollection
      

      如果你没有地方触发更新,这显然是行不通的。

      【讨论】:

        猜你喜欢
        • 2020-06-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多