2016-04-06 11 views
1

私はクロススレッドについて学習しており、作成したクラス(viewmodel)からメインUIスレッドをどのように更新できるかについて質問があります。私が集めたものから、ディスパッチャーは行く道です。メインUIスレッドディスパッチャーをクラス内で使用するにはどうすればよいですか?または、これを行うためのよりよい方法があります。この例では、テキストブロックをCount Valueにデータバインディングしています。これを機能させるためには、私は何をする必要がありますか?ありがとう!Dispatcher ViewModel?

class customVM : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    private void OnPropertyChange(string PropertyName) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(PropertyName)); 
     } 
    } 

    private int _count; 

    public int Count 
    { 
     get { return _count; } 
     set { 
      _count = value; 
      OnPropertyChange(nameof(Count)); 
     } 
    } 

    public async void methodAsync() 
    { 
     await method(); 
    } 

    private Task method() 
    { 

     return Task.Run(() => 
     { 
      for (int i = 0; i < 10; i++) 
      { 
       Task.Delay(1000).Wait(); 
       //************* 
       Count = i; 
       //************* 
      } 
     }); 
    } 
    } 
+0

不明な質問が掲載されたコードでは、通常のバインディングが機能します。他に何をしようとしていますか? – AnjumSKhan

+0

カウントはテキストブロックにバインドされます。クロススレッディングが発生します。 – user3363744

+0

WPFアプリケーションでディスパッチャを直接使用することなく、クロススレッディングが動作するとは限りません。私はさまざまなプラットフォーム間を移動します。 – user3363744

答えて

1

PropertyChangedイベントが自動的にUIディスパッチャに整列化されると、UIスレッドに別のスレッドからPropertyChangedを派遣する必要はありません。 として

private Task method() 
{ 
    //The following code is okay. There is no need to marshal it explicitly   
    return Task.Run(() => 
    { 
     for (int i = 0; i < 10; i++) 
     { 
      Task.Delay(1000).Wait(); 
      //************* 
      Count = i; 
      //************* 
     } 
    }); 
} 

言う:

注意をWPFで、物事が異なっており、図5 に示すコードは、StatusプロパティはデータバインドのTextBlockにある場合でも動作すること。この は、他のすべてのXAMLフレームワークとは異なり、WPFがPropertyChangedイベントをメインスレッドの に自動的にディスパッチするためです。その他のすべての フレームワークでは、ディスパッチ解決策が必要です。

しかし、スカラー特性(すなわちPropertyChangedイベント)に変更通知のためにのみ真です。コレクションの変更通知(INotifyCollectionChanged.CollectionChangedイベント)はそのようには機能しません。UIスレッドで手動で発生させる必要があります。つまり、INotifyCollectionChangedObservableCollectionなど)を使用すると、これらの変更はUIスレッドにマーシャリングされません。つまり、UI以外のスレッドからコレクションを変更すると例外が発生します。私たちはViewModelクラスに属しており、Dispatcherを使用してUIを更新していません。だから私はデビッド・リカードのアプローチを使用するためにあなたに助言する:

public static class DispatchService 
{ 
    public static void Invoke(Action action) 
    { 
     Dispatcher dispatchObject = Application.Current.Dispatcher; 
     if (dispatchObject == null || dispatchObject.CheckAccess()) 
    { 
      action(); 
     } 
     else 
     { 
      dispatchObject.Invoke(action); 
     } 
    } 
} 

と:のみ結合

DispatchService.Invoke(() => 
{ 
    this.MyCollection.Add("new value"); 
}); 

David Rickard article at msdn blog.

2

クロススレッドのスカラプロパティは、WPFで動作します(そしておそらくもXamarin)。他のMVVMプラットフォームではでなく、が動作します。

あなたのコードは一種の進捗報告のようです。適切な解決策はProgress<T>IProgress<T>です:

class customVM : INotifyPropertyChanged 
{ 
    private int _count; 

    public int Count 
    { 
    get { return _count; } 
    set { 
     _count = value; 
     OnPropertyChange(nameof(Count)); 
    } 
    } 

    public async void methodAsync() 
    { 
    var progress = new Progress<int>(count => { Count = count; }); 
    await Task.Run(() => method(progress)); 
    } 

    private void method(IProgress<int> progress) 
    { 
    for (int i = 0; i < 10; i++) 
    { 
     Thread.Sleep(1000); 
     progress.Report(i); 
    } 
    } 
} 

Progress<T>は、ディスパッチャの異なるタイプのもの、およびなどのWinFormsなどにも非MVVMのものも含め、すべてのUIプラットフォーム、と非常にうまく動作します。

関連する問題