2011-01-07 17 views
15

MVVM環境では、私はバックグラウンドスレッドであり、UIコントロールで更新を実行したいと思います。だから、通常は私はmyButton.Dispatcher.BeginInvoke(blabla)に行きましたが、私はmyButtonへのアクセスを持っていません(viewmodelはビューのコントロールにアクセスできないためです)。だからこれを行うための通常のパターンは何ですか?WPF /マルチスレッド:MVVMのUIディスパッチャ

(私は常に結合そこだと思うが、私は、ディスパッチャ経由でそれを行う方法を知りたい)

+2

重複したhttp://stackoverflow.com/questions/486758/is-wpf-dispatcher-the-solution-of-multi-threading-problems? –

+0

重複していません...彼はViewModel(通常はディスパッチャにアクセスできない)によって起動されたバックグラウンドスレッドからディスパッチャを取得する方法を尋ねています。 –

答えて

36

のようにそれを使用することができます:

+7

そしてアプリケーションオブジェクトなしでビューモデルを単体テストする方法は? –

+2

@Geert van Horrikあなたのビューモデルを単体テストするためのアプリケーションオブジェクトをモックできます。 necroのコメントで申し訳ありません - マルチスレッドプログラミングのための有効なMVVMソリューションを探しているうちに、このSOの記事を見つけました。 – SRM

0

あなたは、おそらくそれが起こっているのを示すために、命名規則を使用して(あなたのビューモデルにイベントを発生させることができ非UIスレッド(例えば、NotifyProgressChangedAsync)から呼び出されます。イベントに添付されているビューは、ディスパッチャを適切に処理できます。

または、(ビューからの)ビューモデルに同期関数にデリゲートを渡すことができます。 Application.Currentですので:あなたはUIスレッドからExecute.InitializeWithDispatcher()を呼び出す必要があります

public static class Execute 
{ 
    private static Action<System.Action> executor = action => action(); 

    /// <summary> 
    /// Initializes the framework using the current dispatcher. 
    /// </summary> 
    public static void InitializeWithDispatcher() 
    { 
#if SILVERLIGHT 
     var dispatcher = Deployment.Current.Dispatcher; 
#else 
     var dispatcher = Dispatcher.CurrentDispatcher; 
#endif 
     executor = action =>{ 
      if(dispatcher.CheckAccess()) 
       action(); 
      else dispatcher.BeginInvoke(action); 
     }; 
    } 

    /// <summary> 
    /// Executes the action on the UI thread. 
    /// </summary> 
    /// <param name="action">The action to execute.</param> 
    public static void OnUIThread(this System.Action action) 
    { 
     executor(action); 
    } 
} 

それを使用する前に、あなたが、私は通常Application.Current.Dispatcherを使用して、このExecute.OnUIThread(()=>SomeMethod())

13

Caliburn Microソースコードから静的な場合、コントロールへの参照は不要

+0

Dispatcher.CurrentDispatcherを使用してもエラーは発生します。 Application.Current.Dispatcherを使用すると正しく動作します。 –

0

UIスレッドのディスパッチャをViewModelのコンストラクタに渡し、VMに格納します。

各スレッドに独自のディスパッチャがあることに注意してください。 UIスレッドが必要になります!

4

ViewModelBase Catelには、使用できるDispatcherプロパティがあります。

+0

DispatcherHelperクラスのGetCurrentDispatcherメソッド。https://catel.codeplex.com/SourceControl/latest#src/Catel.MVVM/Catel.MVVM.NET40/Windows/Threading/Helpers/Dispatcherhelper.cs –

4

私は自分のViewModelをDependencyObjectから継承し、UIスレッド上に構築されていることを保証します。UIスレッドのディスパッチャに対応するDispatcherプロパティを持っています。次に、ViewModelの実装の詳細でビューを汚染する必要はありません。

いくつかの他のプラス:

  • ユニットテスト容易性:ビュー& ViewModelに
  • 間のことができますユニットテストこれらの実行中のアプリケーション(というよりもApplication.Current.Dispatcherに頼ら)なし
  • 疎結合あなたは、依存関係プロパティを定義することができますあなたのViewModelには、これらのプロパティが変更されたときにビューを更新するコードは書き込まれません。