在我的wpf应用程序中,使用单独的线程调用viewmodel中的耗时操作。但是,此函数访问视图模型中绑定到视图中对象的多个属性。我尝试直接访问它们,我看不到有关它们归UI线程所有的投诉。我很想知道在线程之间直接使用它们的后果。
答案 0 :(得分:5)
您可以从任何线程中自由使用ViewModel - 包括读写。一个主要的例外是处理集合 - 必须在用户界面线程上写入数据绑定集合,因为绑定不会自动封送到UI线程(就像简单的绑定一样)。
但是,您仍应考虑对任何写入进行适当的同步。正常的线程同步问题将会发生,因为ViewModel只是另一个类。
话虽如此,通常情况下,您希望处理同步的方式与在许多情况下略有不同。锁通常不在ViewModel上工作,因为WPF数据绑定不会锁定对象。因此,在ViewModel中需要同步时,通常应使用Dispatcher.Invoke
/ BeginInvoke
来根据需要将回调编组回用户界面线程。
答案 1 :(得分:1)
除了通常的线程安全问题之外,没有任何后果。 VM特性通常存在问题的唯一问题是ObservableCollections
,它具有线程关联性。
答案 2 :(得分:0)
如果你使用扩展你的ObservableCollection,你可以从一个单独的线程更新:
/// <summary>
/// Source: New Things I Learned
/// Title: Have worker thread update ObservableCollection that is bound to a ListCollectionView
/// http://geekswithblogs.net/NewThingsILearned/archive/2008/01/16/have-worker-thread-update-observablecollection-that-is-bound-to-a.aspx
/// Note: Improved for clarity and the following of proper coding standards.
/// </summary>
/// <param name="e"></param>
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
// Use BlockReentrancy
using (BlockReentrancy())
{
var eventHandler = CollectionChanged;
// Only proceed if handler exists.
if (eventHandler != null)
{
Delegate[] delegates = eventHandler.GetInvocationList();
// Walk thru invocation list
foreach (NotifyCollectionChangedEventHandler handler in delegates)
{
var currentDispatcher = handler.Target as DispatcherObject;
// If the subscriber is a DispatcherObject and different thread
if ((currentDispatcher != null) &&
(currentDispatcher.CheckAccess() == false))
{
// Invoke handler in the target dispatcher's thread
currentDispatcher.Dispatcher.Invoke(
DispatcherPriority.DataBind, handler, this, e);
}
else
{
handler(this, e);
}
}
}
}
}
/// <summary>
/// Overridden NotifyCollectionChangedEventHandler event.
/// </summary>
public override event NotifyCollectionChangedEventHandler CollectionChanged;