2011-12-15 63 views
6

在我的wpf应用程序中,我的viewmodel中耗时的操作是使用单独的线程调用的。然而,该函数访问视图模型中与视图中的对象绑定的多个属性。我试图直接访问它们,我没有看到它们被UI线程所拥有。我很想知道在线程之间直接使用它们的后果。从单独线程访问ViewModel属性

+0

你改变'ViewModel'或只是阅读它单独的线程? – SliverNinja

+0

只是单独的线程 – Aks

回答

5

您可以自由使用您的ViewModel从任何线程 - 包括阅读和写作。一个主要的例外是处理集合 - 数据绑定集合必须写在用户界面线程上,因为绑定不会自动封送到UI线程(就像简单的绑定一样)。

但是,您仍然应该考虑在任何写入的位置进行适当的同步。正常的线程同步问题会发生,因为ViewModel只是另一个类。

这就是说,通常情况下,您会想要在许多情况下处理稍微不同的同步。锁通常不在ViewModel上工作,因为WPF数据绑定不会锁定对象。因此,在ViewModel中需要同步时,通常应使用Dispatcher.Invoke/BeginInvoke将呼叫封送回用户界面线程。

+0

作为一个例子,如果我有一个'ToggleButton'绑定到虚拟机中的'bool'。而且我在一个单独的线程中执行'if(bool)',我需要做些什么来保持同步,以便用户设置切换和if条件执行之间没有冲突。 – Aks

+0

@Aks号如果你只是读取这样的值,那么你就没有问题。话虽如此,你应该(技术上)标记布尔易变性。有关详细信息,请参阅:http://stackoverflow.com/questions/458173/can-ac-sharp-thread-really-cache-a-value-and-ignore-changes-to-that-value-on-ot/458193 #458193 –

1

除了通常的线程安全问题之外,没有任何后果。虚拟机性能通常存在问题的唯一因素是ObservableCollections,它们具有线程关联性。

+0

如果我真的要使用锁,是不是很可能UI线程挂起? – Aks

+0

这是真的 - 但“通常的线程安全问题”往往需要不寻常的解决方法,因为WPF将忽略您尝试使用的任何锁定或标准线程同步。 –

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; 
相关问题