【发布时间】:2018-07-15 12:45:44
【问题描述】:
我正在使用 here 描述的 SortableObservableCollection。现在我想从 UI 或非 UI 线程操作它,所以我尝试了 here 描述的解决方案:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Runtime;
using System.Windows.Data;
public class SortableObservableCollection<T> : ObservableCollection<T>
{
private object _itemsLock = new object();
public SortableObservableCollection()
: base()
{
BindingOperations.EnableCollectionSynchronization(this, _itemsLock);
}
public SortableObservableCollection(List<T> l) : base(l)
{
BindingOperations.EnableCollectionSynchronization(this, _itemsLock);
}
public SortableObservableCollection(IEnumerable<T> l) : base(l)
{
BindingOperations.EnableCollectionSynchronization(this, _itemsLock);
}
#region Sorting
public void Sort<TKey>(Func<T, TKey> keySelector)
{
InternalSort(Items.OrderBy(keySelector));
}
public void SortDescending<TKey>(Func<T, TKey> keySelector)
{
InternalSort(Items.OrderByDescending(keySelector));
}
public void Sort<TKey>(Func<T, TKey> keySelector, IComparer<TKey> comparer)
{
InternalSort(Items.OrderBy(keySelector, comparer));
}
private void InternalSort(IEnumerable<T> sortedItems)
{
var sortedItemsList = sortedItems.ToList();
foreach (var item in sortedItemsList)
{
Move(IndexOf(item), sortedItemsList.IndexOf(item));
}
}
#endregion // Sorting
public new void Add(T item)
{
base.Add(item);
}
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
public new void Clear()
{
base.Clear();
}
public new bool Remove(T item)
{
return base.Remove(item);
}
}
但是.Net 4.5.2中的这个解决方案,WPF桌面应用,在Remove、Add、Clear方法中抛出异常:System.NotSupportedException: '这种类型的CollectionView不支持修改从与 Dispatcher 线程不同的线程到其 SourceCollection。'
所以,我重新使用 Application.Current.Dispatcher 方法(见下文),因为 BindingOperations.EnableCollectionSynchronization(this, _itemsLock); 机制不像链接的博客文章中所宣传的那样工作以上。
我的问题是:我在第一个清单中做错了什么,还是博客文章声称线程边界总是可以通过这种机制成功跨越?下面的清单是最好的,还是有更好的解决方案来管理跨线程绑定的 observablecollection?
public class SortableObservableCollection<T> : ObservableCollection<T>
{
public SortableObservableCollection()
: base()
{
}
public SortableObservableCollection(List<T> l) : base(l)
{
}
public SortableObservableCollection(IEnumerable<T> l) : base(l)
{
}
#region Sorting
public void Sort<TKey>(Func<T, TKey> keySelector)
{
InternalSort(Items.OrderBy(keySelector));
}
public void SortDescending<TKey>(Func<T, TKey> keySelector)
{
InternalSort(Items.OrderByDescending(keySelector));
}
public void Sort<TKey>(Func<T, TKey> keySelector, IComparer<TKey> comparer)
{
InternalSort(Items.OrderBy(keySelector, comparer));
}
private void InternalSort(IEnumerable<T> sortedItems)
{
var sortedItemsList = sortedItems.ToList();
foreach (var item in sortedItemsList)
{
Move(IndexOf(item), sortedItemsList.IndexOf(item));
}
}
#endregion // Sorting
public new void Add(T item)
{
Application.Current.Dispatcher.Invoke(() =>
{
base.Add(item);
}, System.Windows.Threading.DispatcherPriority.DataBind);
}
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
public new void Clear()
{
Application.Current.Dispatcher.Invoke(() =>
{
base.Clear();
}, System.Windows.Threading.DispatcherPriority.DataBind);
}
public new bool Remove(T item)
{
return Application.Current.Dispatcher.Invoke(() =>
{
return base.Remove(item);
}, System.Windows.Threading.DispatcherPriority.DataBind);
}
}
【问题讨论】:
-
Move 方法似乎不是线程安全的
-
那么,这是什么意思?我可以让它线程安全吗?是使用 Dispaytcher 的第二个解决方案,因此,更好的方法?
-
我无法决定哪个更好,也不是发表意见的地方。在处理多线程应用程序时,您应该始终采取额外措施以避免此异常。您应该清楚地了解每个线程上发生的事情,并在必要时放置
invoke。 -
我认为
BindingOperations.EnableCollectionSynchronization应该只使用一次
标签: c# .net wpf multithreading observablecollection