Mvvmcrossビューモデルで長時間実行されているプロセスがあり、非同期にしたい( http://msdn.Microsoft.com/en-us/library/vstudio/hh191443.aspx )。
Asyncキーワードは現在、Xamarinのベータチャネルでサポートされています。
以下は、私が現在非同期を実装している方法の例です。 IsBusyフラグをUI要素にバインドして、読み込みメッセージを表示することができます。
これは正しい方法ですか?
public class MyModel: MvxViewModel
{
private readonly IMyService _myService;
private bool _isBusy;
public bool IsBusy
{
get { return _isBusy; }
set { _isBusy = value; RaisePropertyChanged(() => IsBusy); ; }
}
public ICommand MyCommand
{
get
{
return new MvxCommand(DoMyCommand);
}
}
public MyModel(IMyService myService)
{
_myService = myService;
}
public async void DoMyCommand()
{
IsBusy = true;
await Task.Factory.StartNew(() =>
{
_myService.LongRunningProcess();
});
IsBusy = false;
}
}
async void
は避けてください。 ICommand
を扱う場合は、async void
を使用する必要がありますが、その範囲は最小限に抑える必要があります。
この変更されたコードは、アクションをasync Task
として公開します。これは、ユニットテスト可能であり、コードの他の部分から消費できます。
public class MyModel: MvxViewModel
{
private readonly IMyService _myService;
private bool _isBusy;
public bool IsBusy
{
get { return _isBusy; }
set { _isBusy = value; RaisePropertyChanged(() => IsBusy); ; }
}
public ICommand MyCommand
{
get
{
return new MvxCommand(async () => await DoMyCommand());
}
}
public MyModel(IMyService myService)
{
_myService = myService;
}
public async Task DoMyCommand()
{
IsBusy = true;
await Task.Run(() =>
{
_myService.LongRunningProcess();
});
IsBusy = false;
}
}
IsBusy
の使用は問題ありません。これは、非同期UIの一般的なアプローチの1つです。
Task.Factory.StartNew
をTask.Run
に変更しました。 Task.Run
は、 Stephen Toubによって説明された理由 のasync
コードで優先されます。
MvvmCrossにMvxAsyncCommand
が追加されました(GitHub commit を参照)。
だからこれをする代わりに
public ICommand MyCommand
{
get
{
return new MvxCommand(async () => await DoMyCommand());
}
}
あなたはこれを行うことができます
public ICommand MyCommand
{
get
{
return new MvxAsyncCommand(DoMyCommand);
}
}
最終的にその待機の周りにトライキャッチを追加することを除いて、問題ないように見えます。
public async void DoMyCommand()
{
IsBusy = true;
try{
await Task.Factory.StartNew(() =>
{
_myService.LongRunningProcess();
});
}catch{
//Log Exception
}finally{
IsBusy = false;
}
}
さらに、asyncでMvxCommandを使用した例がブログにあります。あなたの例と非常によく似ています http://deapsquatter.blogspot.com/2013/03/updating-my-mobile-apps-for-async.html
MethodBindingplugin を使用して、ボイラープレートコード(コマンド)を回避し、非同期メソッドに直接UI。
また、 Fody PropertyChanged を使用すると、コードは次のようになります。
_[ImplementPropertyChanged]
public class MyModel: MvxViewModel
{
private readonly IMyService _myService;
public bool IsBusy { get; set; }
public MyModel(IMyService myService)
{
_myService = myService;
}
public async Task DoSomething()
{
IsBusy = true;
await Task.Factory.StartNew(() =>
{
_myService.LongRunningProcess();
});
IsBusy = false;
}
}
_
「DoSomethingをクリック」のようにバインディングを作成できます。
一方、await Task.Factory.StartNew()
を使用するのではなく、__myService.LongRunningProcess
_を非同期にしてみませんか?それははるかに良く見えるでしょう:
_public async Task DoSomething()
{
IsBusy = true;
await _myService.LongRunningProcess();
IsBusy = false;
}
_