2016-12-29 21 views
1

私のビューにバインドされたプロパティを持つクラスがあります。私のビューを最新の状態に保つために、私はINotifyPropertyChangedを実装し、プロパティの変更ごとにイベントを発生させます。非同期を実装する方法INotifyPropertyChanged

今、アプリケーションをフリーズする重い機能があります。私はそれらをバックグラウンドタスクに入れたいと思う。

:まず、ここで(ボタンをクリックしたときに、例えば)私の現在のアプローチ

private async void HeavyFunc() 
{ 
    foreach (var stuff) 
    { 
     count += await Task.Run(() => stuff.Fetch()); 
    } 

    if (count == 0) 
     //... 
} 

スタッフクラス

public async Task<int> Fetch() 
{ 
    //network stuff 

    RaisePropertyChanged("MyProperty"); 
} 

public async void RaisePropertyChanged(string pChangedProperty) 
{ 
    await Application.Current.Dispatcher.BeginInvoke(
     System.Windows.Threading.DispatcherPriority.Normal, 
     new ThreadStart(() => 
     { 
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(pChangedProperty); 
     } 
    ); 
} 

上記のコードは、( "DependencySourceは" で作成されなければならない例外を与えます"DependencyObject"のような同じスレッド)。

AFAIK、新しいスレッドを作成して実行する必要があります(待っている間)。 'await Task.Run(...); 'はこのジョブを実行する必要があります。

PropertyChangedイベントはUIに直接影響するため、UIスレッドで呼び出すとよい判断になります。これがDispatcher.BeginInvokeを呼び出す理由です。

私が理解できないこと:上記の例外は、異なるスレッドがデータの原因である場合に発生します。しかし、私は明示的に私のUIスレッドとイベントオブジェクトをUIスレッドで作成する必要があります。だから私はなぜ例外を取得するのですか?

私の主な質問は、上記のような非同期プログラミングの問題のほとんどを回避または処理するために、一般にINotifyPropertyChangedインターフェイスのイベントを実装する方法です。どのような機能を構築する際に考慮する必要がありますか?

+0

スレッドでpropertychangedイベントを発生させているため、ui要素が作成されていない場合はアクセスできません。 – CodingYoshi

+0

実際にどのコードがuiスレッドと別のスレッドで実行されているかを理解するには[this](http://stackoverflow.com/questions/41271185/interface-freeze-when-trying-to-update-datagridview/41272238#41272238) – CodingYoshi

+0

プロパティ自体はビットマップのようなDepedencyObjectですか? –

答えて

4

今、アプリケーションをフリーズする重い機能があります。

あなたが本当に非同期の「ネットワークのもの」をやっているなら、アプリケーションをフリーズしてはいけません。

私の主な質問は:どのように私は、一般的に上記のような非同期プログラミングの問題のほとんどを回避または処理するためにINotifyPropertyChangedインターフェイスのためのイベントを実施していますか?私が好む

アプローチは、コードを上げるイベントでこれを処理にではありません。代わりに、のコードを構造化して、UIレイヤーを尊重します。言い換えれば

、それはこのように動作するように、あなたの「サービス」(または「ビジネスロジック」)あなたの「UI」のコードからコードを分割:

// In StuffService class: 
public async Task<Result> FetchAsync() 
{ 
    //network stuff 
    return result; 
} 

// In StuffViewModel class: 
public async void ButtonClicked() 
{ 
    foreach (var stuff) 
    { 
    var result = await Task.Run(() => _stuffService.FetchAsync()); 
    MyProperty = result.MyProperty; 
    count += result.Count; 
    } 

    if (count == 0) 
    //... 
} 

public Property MyProperty 
{ 
    get { return _myProperty; } 
    set 
    { 
    _myProperty = value; 
    RaisePropertyChanged(); 
    } 
} 
private void RaisePropertyChanged([CallerMemberName] string pChangedProperty = null) 
{ 
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(pChangedProperty)); 
} 

この方法は、手作業によるスレッドのジャンプは、ありません

をすべてのプロパティは、標準のViewModelの実装を持っているコードはよりシンプルかつ保守性である、など私はあなたのネットワーク呼び出しが本当に非同期である場合には、この余分する必要がありますが、Task.Runへの呼び出しに残しました。

関連する問題