2011-12-15 24 views
6

私のwpfアプリケーションでは、ビューモデルで時間のかかる操作が別のスレッドを使用して呼び出されます。ただし、この関数はビュー内のオブジェクトにバインドされているビューモデル内のいくつかのプロパティにアクセスします。直接アクセスしようとしましたが、UIスレッドが所有しているとの苦情はありません。私はスレッド間で直接それらを使用することの結果を知ることに興味があります。別のスレッドからViewModelプロパティにアクセス

+0

あなたは 'ViewModel'を変更するか、単にそれを別のスレッドを読んでいますか? – SliverNinja

+0

単体のスレッド – Aks

答えて

5

あなたはViewModelを自由に読み込みや書き込みを含むどのスレッドからでも使用できます。 1つの主な例外はコレクションを扱うことです - データバインディングコレクションはユーザーインターフェイススレッドに書き込まれる必要があります。バインディングは単純なバインディングのようにUIスレッドに自動的にマーシャリングされないためです。

ただし、書き込みのために適切な同期をとることを検討する必要があります。 ViewModelは単なる別のクラスなので、通常のスレッド同期の問題が発生します。

通常、あなたは多くの場合とは少し異なる方法で同期を処理したいと言われています。 WPFデータバインディングはオブジェクトをロックしないため、通常はViewModelではロックが機能しません。そのため、ViewModelで同期が必要な場合は、通常、Dispatcher.Invoke/BeginInvokeを使用して、コールを必要に応じてユーザーインターフェイススレッドにマーシャリングします。あなたはこれであなたのObservableCollectionを延長使用している場合

+0

たとえば、VMの 'bool'にバインドされた' ToggleButton'を持っているとします。私は別のスレッドで '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

通常のスレッドの安全性に関する懸念とは別に、結果はありません。通常、VM適合性に問題があるのは、スレッド親和性を持つObservableCollectionsです。

+0

ロックを実際に使用するのであれば、UIスレッドがハングする可能性はありますか? – Aks

+0

これは当てはまりますが、WPFは使用しようとしているロックや標準的なスレッドの同期を無視するため、通常のスレッドの安全上の懸念には珍しい回避策が必要になりがちです。 –

0

、あなたは別のスレッドから更新することができます。

/// <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;