将BindingOperations与ObservableCollection一起使用

时间:2017-01-15 20:00:12

标签: c# wpf

我正在尝试使用BindingOperations类的静态方法为ObservableCollection创建一个异步包装器,但是很难找到如何使用它的任何好例子。

在包装器的构造函数中简单地调用BindingOperations.EnableCollectionSynchronization(this,_lock)似乎工作得很好,因为我能够从UI线程以外的线程向集合添加项目而没有问题。

但是,我也尝试使用BindingOperations.AccessCollection(this,()=> {...},true)来对集合进行排序并限制项目数量但我得到的例外情况就像它一样在被认为被锁定的其他地方被修改过。

例如:

  

RemoveAt(Count - 1); 随机提供 ArgumentOutOfRangeException

  

MoveItem(oldIndex,newIndex); 有时会产生 InvalidOperationException:集合已被修改

很明显,尽管msdn说:

,但它并没有锁定
  

“通过使用同步提供对集合的访问   应用程序在调用时指定的机制   EnableCollectionSynchronization“。

https://msdn.microsoft.com/en-us/library/system.windows.data.bindingoperations.accesscollection(v=vs.110).aspx

知道我错过了什么吗?

public class AsyncObservableCollection<T> : ObservableCollection<T>
{
    private object _collectionLock = new object();
    private int _maxLength = 0;
    private bool _reversed = false;
    private Func<T, object> _sortOrder = null;

    public AsyncObservableCollection()
        : this(0, null)
    {
    }
    public AsyncObservableCollection(int maxLength)
        : this(maxLength, null)
    {
    }
    public AsyncObservableCollection(int maxLength, bool reversed)
        : this(maxLength, reversed, null)
    {
    }
    public AsyncObservableCollection(int maxLength, Func<T, object> sortOrder)
        : this(maxLength, false, sortOrder)
    {
    }
    public AsyncObservableCollection(int maxLength, bool reversed, Func<T, object> sortOrder)
    {
        BindingOperations.EnableCollectionSynchronization(this, _collectionLock);

        if (maxLength > 0)
            _maxLength = maxLength;
        _reversed = reversed;
        _sortOrder = sortOrder;
    }

    public new void Add(T item)
    {
        BindingOperations.AccessCollection(this, () => {
            if (!_reversed)
                base.Add(item);
            else
                Insert(0, item);
        }, true);

        Sort();
        Limit();
    }

    public void Limit()
    {
        Limit(_maxLength);
    }
    public void Limit(int maxLength)
    {
        if (maxLength > 0)
        {
            BindingOperations.AccessCollection(this, () => {
                while (Count > 0 && Count > maxLength)
                    if (!_reversed)
                        RemoveAt(0);
                    else
                        RemoveAt(Count - 1);
            }, true);
        }
    }

    public void Sort()
    {
        Sort(_sortOrder);
    }
    public void Sort(Func<T, object> order)
    {
        if (order != null)
        {
            BindingOperations.AccessCollection(this, () => {
                List<T> list = this.ToList();
                List<T> sortedList = !_reversed ? list.OrderBy(order).ToList() : list.OrderByDescending(order).ToList();

                foreach (T item in list)
                {
                    int oldIndex = list.IndexOf(item);
                    int newIndex = sortedList.IndexOf(item);
                    if (oldIndex != newIndex)
                        MoveItem(oldIndex, newIndex);
                }
            }, true);
        }
    }
}

解决方案(不是关于BindingOperations类的实际问题的答案):

使用提供给BindingOperations.EnableCollectionSynchronization()的相同锁对象进行简单锁定解决了问题:

public class AsyncObservableCollection<T> : ObservableCollection<T>
{
    private object _collectionLock = new object();
    private int _maxLength = 0;
    private bool _reversed = false;
    private Func<T, object> _sortOrder = null;

    public AsyncObservableCollection()
        : this(0, null)
    {
    }
    public AsyncObservableCollection(int maxLength)
        : this(maxLength, null)
    {
    }
    public AsyncObservableCollection(int maxLength, bool reversed)
        : this(maxLength, reversed, null)
    {
    }
    public AsyncObservableCollection(int maxLength, Func<T, object> sortOrder)
        : this(maxLength, false, sortOrder)
    {
    }
    public AsyncObservableCollection(int maxLength, bool reversed, Func<T, object> sortOrder)
    {
        BindingOperations.EnableCollectionSynchronization(this, _collectionLock);

        if (maxLength > 0)
            _maxLength = maxLength;
        _reversed = reversed;
        _sortOrder = sortOrder;
    }

    public void AddSortLimit(T item)
    {
        lock (_collectionLock)
            if (!_reversed)
                Add(item);
            else
                Insert(0, item);

        Sort();
        Limit();
    }

    public void Limit()
    {
        Limit(_maxLength);
    }
    public void Limit(int maxLength)
    {
        if (maxLength > 0)
        {
            lock (_collectionLock)
                while (Count > 0 && Count > maxLength)
                    if (!_reversed)
                        RemoveAt(0);
                    else
                        RemoveAt(Count - 1);
        }
    }

    public void Sort()
    {
        Sort(_sortOrder);
    }
    public void Sort(Func<T, object> order)
    {
        if (order != null)
        {
            lock (_collectionLock)
            {
                List<T> list = this.ToList();
                List<T> sortedList = !_reversed ? list.OrderBy(order).ToList() : list.OrderByDescending(order).ToList();

                foreach (T item in list)
                {
                    int oldIndex = IndexOf(item);
                    int newIndex = sortedList.IndexOf(item);
                    if (oldIndex != newIndex)
                        MoveItem(oldIndex, newIndex);
                }
            }
        }
    }
}

1 个答案:

答案 0 :(得分:0)

  

1)MoveItem(oldIndex,newIndex);有时会产生InvalidOperationException:&gt;集合已被修改。

您正在收到错误,因为您正在修改要迭代的相同列表。因此,对排序列表进行迭代,移动项目是列表集合。

  

2)RemoveAt(Count-1);随机给出一个ArgumentOutOfRangeException

设置检查条件(Count-1)小于list.Count。