当ObservableCollection更改WP7时更新CollectionViewSource

时间:2011-04-15 14:48:52

标签: silverlight windows-phone-7

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

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

虽然我看到了一些非常奇怪的事情。这些项目不会显示在绑定到CVS的ListBox中,或者会显示重复项。如果我在更改Refresh后在CollectionChanged事件之外的CVS上调用ObservableCollection,则一切似乎都正常。我真的希望能够在集合发生变化时进行刷新,而不必担心每次完成更改都需要调用刷新。

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();
}

3 个答案:

答案 0 :(得分:3)

CollectionViewSource未实现INotifyPropertyChanged,因此要将任何基础数据更改纳入UI,您需要在View上调用Refresh,就像您现在所做的那样。 CollectionViewSource也是数据源不可知的,因此源是ObservableCollection引发属性更改通知的事实并不重要,因为CollectionViewSource没有监听。

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

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

}

答案 2 :(得分:0)

问题在于ObservableCollection有其局限性。考虑一下你的代码中的循环,它有多少次调用Add方法?因此,更改的事件将触发多少次以及刷新方法的频率是多少?当快速连续发生如此多的变化时,这段代码会陷入困境,这并不奇怪。

ObservableCollection在最初加载时很好,然后监视其更改事件,并从该点进行相对不频繁的更改。对于大规模更改,可能最好加载一个全新的实例,然后将此新实例分配给属性。

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