【问题标题】:Update CollectionViewSource When ObservableCollection Changes WP7当 ObservableCollection 更改 WP7 时更新 CollectionViewSource
【发布时间】:2020-05-15 21:07:36
【问题描述】:

我的基本项目列表有一个ObservableCollection。我有 2 个CollectionViewSource 是不同的数据过滤器。我希望发生的任何更改都反映在 CollectionViewSource 中。

在我的视图模型构造函数中,我设置了过滤谓词。然后我获取数据并将其添加到ObservableCollection。我订阅了CollectionChanged 事件,并正在那里刷新 CVS。

不过,我看到了一些非常奇怪的事情。要么这些项目没有出现在我绑定到 CVS 的 ListBox 中,要么出现重复项。如果我在更改ObservableCollection 之后在CollectionChanged 事件之外的CVS 上调用Refresh,一切似乎都正常。我真的希望能够在集合更改时刷新,而不必担心每次完成更改它时都必须调用刷新。

public MyViewModel()
{
    oc.CollectionChanged += OcCollectionChanged;

    cvs1.Source = oc;
    cvs1.View.Filter = new Predicate<object>( ... );

    cvs2.Source = oc;
    cvs2.View.Filter = new Predicate<object>( ... );

    foreach( var data in myData )
    {
        oc.Add( data );
    }
}

private void OcCollectionChanged( object sender, NotifyCollectionChangedEventArgs e )
{
    cvs1.View.Refresh();
    cvs2.View.Refresh();
}

【问题讨论】:

    标签: silverlight windows-phone-7


    【解决方案1】:

    CollectionViewSource 没有实现 INotifyPropertyChanged,因此要将任何底层数据更改到 UI 中,您需要在视图上调用 Refresh,就像您已经在做的那样。 CollectionViewSource 也与数据源无关,因此源是引发属性更改通知的 ObservableCollection 的事实并不重要,因为 CollectionViewSource 没有在监听。

    我认为您在集合更改时手动刷新视图的解决方案是您将获得的最佳解决方案,而无需重新考虑您的数据结构。

    【讨论】:

    • 我看到的是将刷新放入CollectionChanged 事件的问题。如果我在更改收藏后致电Refresh,我看不到问题。这是一个已知问题还是我可以做些什么来解决这个问题?从ObservableCollection 添加/删除某些内容后,我可以手动调用Refresh,但我不明白为什么从CollectionChanged 事件调用它时它不应该工作。
    【解决方案2】:

    我正在使用经过修改的ObservableCollection 类,它专门克服了上述限制(CollectionChangedEvent 事件触发多次),发现 here. (ObservableCollectionEx - blocks the CollectionChangedEvent until all are added by adding an AddRange method)

    我已经使用它大约 2 年了,它对于大型集合更改非常有效。

    更新
    链接好像失效了,代码如下:

    public class ObservableCollectionEx<T> : ObservableCollection<T>
    {
        public ObservableCollectionEx()
            : base()
        {
            _suspendCollectionChangeNotification = false;
        }
    
    
        bool _suspendCollectionChangeNotification;
    
        protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            if(!_suspendCollectionChangeNotification)
            {
                base.OnCollectionChanged(e);
            }
        }
    
        public void SuspendCollectionChangeNotification()
        {
            _suspendCollectionChangeNotification = true;
        }
    
        public void ResumeCollectionChangeNotification()
        {
            _suspendCollectionChangeNotification = false;
        }
    
    
        public void AddRange(IEnumerable<T> items)
        {
            this.SuspendCollectionChangeNotification();
            int index = base.Count;
            try
            {
                foreach(var i in items)
                {
                    base.InsertItem(base.Count, i);
                }
            }
            finally
            {
                this.ResumeCollectionChangeNotification();
                var arg = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
                this.OnCollectionChanged(arg);
            }
        }
    
    }
    

    【讨论】:

      【解决方案3】:

      问题在于ObservableCollection 有其局限性。考虑一下您的代码中的那个循环,它调用Add 方法的次数是多少?因此,更改的事件会触发多少次,刷新方法会被调用多少次?当如此多的变化迅速连续发生时,这段代码陷入困境也就不足为奇了。

      ObservableCollection 在最初加载时非常好,然后监视其更改事件,并从那时起进行相对不频繁的较小更改。对于大规模更改,最好加载一个全新的实例,然后将这个新实例分配给一个属性。

      让属性设置器重新分配 CollectionViewSource 对象上的 Source 属性。如果您仍想观察集合,您也可以在 setter 中分离和附加事件处理程序。

      【讨论】:

        猜你喜欢
        • 2013-09-14
        • 2011-08-11
        • 2021-11-26
        • 1970-01-01
        • 2011-11-15
        • 1970-01-01
        • 1970-01-01
        • 2016-08-24
        • 2018-05-18
        相关资源
        最近更新 更多