I have a long running process in an mvvmcross viewmodel and wish to make it async (http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx).
The async keyword is currently supported in the beta channel for Xamarin.
Below is an example of how I'm currently implementing async. The IsBusy flag ccould be bound to a UI element and display a loading message.
Is this the correct way?
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;
}
}
You should avoid async void
. When you're dealing with ICommand
, you do need to use async void
, but its scope should be minimized.
This modified code exposes your action as an async Task
, which is unit testable and consumable from other parts of your code:
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; } }
Your use of IsBusy
is fine; that's one common approach in asynchronous UIs.
I did change Task.Factory.StartNew
to Task.Run
; Task.Run
is preferred in async
code for reasons described by Stephen Toub.
MvvmCross now has MvxAsyncCommand
(see GitHub commit).
So instead of doing this
public ICommand MyCommand
{
get
{
return new MvxCommand(async () => await DoMyCommand());
}
}
You can do this
public ICommand MyCommand
{
get
{
return new MvxAsyncCommand(DoMyCommand);
}
}
Looks OK except I would add a try catch finally around that await.
public async void DoMyCommand()
{
IsBusy = true;
try{
await Task.Factory.StartNew(() =>
{
_myService.LongRunningProcess();
});
}catch{
//Log Exception
}finally{
IsBusy = false;
}
}
Further more I have an example on my blog using an MvxCommand with async. Very similar to your example http://deapsquatter.blogspot.com/2013/03/updating-my-mobile-apps-for-async.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With