在ObservableCollection上实现AddRange,并对DataBinding提供适当的支持

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在ObservableCollection上实现AddRange,并对DataBinding提供适当的支持相关的知识,希望对你有一定的参考价值。

我想我自己的ObservableCollection后代支持AddRange方法。这是我目前拥有的:

public class ObservableCollectionPlus<T> : ObservableCollection<T>
{
    public void InsertRange(IEnumerable<T> items)
    {
        this.CheckReentrancy();
        foreach (var item in items) Items.Add(item);

        var type = NotifyCollectionChangedAction.Reset;
        var colChanged = new NotifyCollectionChangedEventArgs(type);
        var countChanged = new PropertyChangedEventArgs("Count");

        OnPropertyChanged(countChanged);
        OnCollectionChanged(colChanged);
    }
}

我对这里发生的事情并不了解,为什么这些事件会被提升。这是我在对google和stackoverflow进行一些研究后组装的一个解决方案。

现在,如果我将我的类的一个实例绑定到LongListSelector然后,在通过InsertRange动态添加项目到ObservableCollectionPlus之后,绑定的LongListSelector的滚动位置被发送到它的顶部。

如果我以这种标准方式添加项目:foreach (var item in items) collection.Add(item);然后LongListSelector的位置不会被移位。但是当然这样我得到的DataBinding通知开销是不受欢迎的。

显然,在我目前的解决方案中出现了问题。我怎样才能实现InsertRange,它的行为与foreach (var item in items) collection.Add(item);完全相同,但只会触发一次DataBinding通知,并且不会对绑定对象的滚动位置做出奇怪的事情?

答案

这可能是因为你发送NotifyCollectionChangedAction.Reset通知,也许只是NotifyCollectionChangedAction.Add将工作,也许:)

public class ObservableRangeCollection<T> : ObservableCollection<T>
{
    public void AddRange(IEnumerable<T> collection)
    {
        foreach (var i in collection)
        {
            Items.Add(i);
        }
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, collection.ToList()));
    }
}
另一答案

我最近在一个项目中使用过这个......

public class RangeObservableCollection<T> : ObservableCollection<T>
{
    private bool _suppressNotification = false;

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        if (!_suppressNotification)
            base.OnCollectionChanged(e);
    }

    public void AddRange(IEnumerable<T> list)
    {
        if (list == null)
            throw new ArgumentNullException("list");

        _suppressNotification = true;

        foreach (T item in list)
        {
            Add(item);
        }
        _suppressNotification = false;
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }
}
另一答案

您在使用DataBinding时遇到的问题可能与您没有为Indexer(属性名称“Item []”)引发PropertyChanged这一事实有关,因为它发生在ObservableCollection according to the source code中。

您还可以查看James Montemagno here on GitHub对ObservableRangeCollection的一个很好的实现,它继承自ObservableColection,并包含AddRange和ReplaceRange方法以及DataBinding所需的所有PropertyChaged和CollectionChanged通知。

另一答案

它花了我很多年,麻烦总是与传递给NotifyCollectionChangedEventArgs ctor的参数。根据行动,有许多不同的ctors采取不同的论点。以下似乎最终对我有用:https://github.com/lolluslollus/Utilz/blob/master/Utilz/SwitchableObservableCollection.cs

以上是关于在ObservableCollection上实现AddRange,并对DataBinding提供适当的支持的主要内容,如果未能解决你的问题,请参考以下文章

在python中,我应该如何在元组列表上实现最小堆?

如何在 i5 上实现 20 倍的 Python 运行速度?

在MJRefresh的基础上实现动画的自定义和自动下拉刷新

使用 Python 在 Linux 上实现一键回归测试

使用 Python 在 Linux 上实现一键回归测试

WebView上实现Java与JavaScript交互