如果你使用过 WPF 框架开发应用程序,我想你一定使用过 ObservableCollection<T>。但 ObservableCollection<T> 的问题在于:它仅能在 Dispacher 线程「这里可以理解为 UI 线程」更新数据。如果你想从另外一个线程更新数据到 ObservableCollection<T> 中时,你需要编写类似于下面的代码:
this.Dispatcher.BeginInvoke(new Action(() =>
{
// 操作 ObservableCollection<T> 对象逻辑
}));
为了不让代码到处充斥着 Dispatcher.BeginInvoke,可以封装了一个 SafeObservableCollection<T>:
[DebuggerDisplay("Count = {Count}")]
[ComVisible(false)]
public class SafeObservableCollection<T> : ObservableCollection<T>
{
private readonly Dispatcher dispatcher;
public SafeObservableCollection() :
this(Enumerable.Empty<T>())
{
}
public SafeObservableCollection(Dispatcher dispatcher) :
this(Enumerable.Empty<T>(),dispatcher)
{
}
public SafeObservableCollection(IEnumerable<T> collection) :
this(collection, Dispatcher.CurrentDispatcher)
{
}
public SafeObservableCollection(IEnumerable<T> collection, Dispatcher currentDispatcher)
{
this.dispatcher = currentDispatcher;
foreach (var item in collection)
{
this.Add(item);
}
}
protected override void SetItem(Int32 index, T item)
{
this.ExecuteOrInvoke(() => this.SetItemBase(index, item));
}
protected override void MoveItem(Int32 oldIndex, Int32 newIndex)
{
this.ExecuteOrInvoke(() => this.MoveItemBase(oldIndex, newIndex));
}
protected override void ClearItems()
{
this.ExecuteOrInvoke(this.ClearItemsBase);
}
protected override void InsertItem(Int32 index, T item)
{
this.ExecuteOrInvoke(() => this.InsertItemBase(index, item));
}
protected override void RemoveItem(Int32 index)
{
this.ExecuteOrInvoke(() => this.RemoveItemBase(index));
}
private void RemoveItemBase(Int32 index)
{
base.RemoveItem(index);
}
private void InsertItemBase(Int32 index, T item)
{
base.InsertItem(index, item);
}
private void ClearItemsBase()
{
base.ClearItems();
}
private void MoveItemBase(Int32 oldIndex, int newIndex)
{
base.MoveItem(oldIndex, newIndex);
}
private void SetItemBase(Int32 index, T item)
{
base.SetItem(index, item);
}
private void ExecuteOrInvoke(Action action)
{
if (this.dispatcher.CheckAccess())
{
action();
}
else
{
this.dispatcher.BeginInvoke(action);
}
}
}
当然,在使用 SafeObservableCollection<T> 时,你应该在 UI 线程创建这个集合对象,不然 UI 也无法更新数据。