问题描述
我有一个MVVM设置.
I've got a MVVM setup.
我的模型定期调用一些服务,然后在ViewModel上调用一个操作,然后更新暴露给View的一些变量.
My model periodically calls some service and then invokes an action on the ViewModel which then updates some variables exposed to the View.
该变量是一个ReadOnlyObservableCollection<T>
,它具有一个要侦听的ObservableCollection<T>
.
The variable is an ReadOnlyObservableCollection<T>
, which has an ObservableCollection<T>
it listens on.
问题在于模型从另一个线程调用回调,因此不允许我在另一个线程上清除ObservableCollection<T>
.
The problem is that the Model calls the callback from a different thread, and thus it doesn't allow me to clear the ObservableCollection<T>
on a different thread.
所以我想:使用调度程序,如果我们不在正确的线程上,请调用它:
So I thought: use the dispatcher, if we aren't on the correct thread, invoke it:
private void OnNewItems(IEnumerable<Slot> newItems)
{
if(!Dispatcher.CurrentDispatcher.CheckAccess())
{
Dispatcher.CurrentDispatcher.Invoke(new Action(() => this.OnNewItems(newItems)));
return;
}
this._internalQueue.Clear();
foreach (Slot newItem in newItems)
{
this._internalQueue.Add(newItem);
}
}
我认为代码非常简单
问题是,即使我在正确的线程上执行它(我认为),它仍会在.Clear();
The problem is that, even though I execute it on the correct thread (I think) it still throws me an exception on the .Clear();
为什么会这样?如何在不创建自定义ObservableCollection<T>
的情况下解决该问题?
Why is this occuring? How can I work around it without creating my custom ObservableCollection<T>
?
推荐答案
我通常会在通用视图模型库中初始化我的视图模型使用的调度程序,以帮助确保它是UI线程调度程序,如Will所述.
I typically initialize the dispatcher used by my view models in a common view model base to help ensure it is the UI thread dispatcher, as Will mentions.
#region ViewModelBase()
/// <summary>
/// Initializes a new instance of the <see cref="ViewModelBase"/> class.
/// </summary>
protected ViewModelBase()
{
_dispatcher = Dispatcher.CurrentDispatcher;
}
#endregion
#region Dispatcher
/// <summary>
/// Gets the dispatcher used by this view model to execute actions on the thread it is associated with.
/// </summary>
/// <value>
/// The <see cref="System.Windows.Threading.Dispatcher"/> used by this view model to
/// execute actions on the thread it is associated with.
/// The default value is the <see cref="System.Windows.Threading.Dispatcher.CurrentDispatcher"/>.
/// </value>
protected Dispatcher Dispatcher
{
get
{
return _dispatcher;
}
}
private readonly Dispatcher _dispatcher;
#endregion
#region Execute(Action action)
/// <summary>
/// Executes the specified <paramref name="action"/> synchronously on the thread
/// the <see cref="ViewModelBase"/> is associated with.
/// </summary>
/// <param name="action">The <see cref="Action"/> to execute.</param>
protected void Execute(Action action)
{
if (this.Dispatcher.CheckAccess())
{
action.Invoke();
}
else
{
this.Dispatcher.Invoke(DispatcherPriority.DataBind, action);
}
}
#endregion
然后您可以像这样在视图模型调度程序上调用一个动作:
You could then invoke an action on the view model dispatcher like this:
this.Execute(
() =>
{
this.OnNewItems(newItems);
}
);
这篇关于WPF ObservableCollection线程安全的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!