C# 如何在mvvmcross视图模型中使用async?
我在mvvmcross-viewmodel中有一个长时间运行的流程,希望使其异步() Xamarin的beta频道目前支持async关键字 下面是我目前如何实现异步的一个示例。IsBusy标志C可以绑定到UI元素并显示加载消息 这是正确的方法吗C# 如何在mvvmcross视图模型中使用async?,c#,async-await,xamarin,mvvmcross,C#,Async Await,Xamarin,Mvvmcross,我在mvvmcross-viewmodel中有一个长时间运行的流程,希望使其异步() Xamarin的beta频道目前支持async关键字 下面是我目前如何实现异步的一个示例。IsBusy标志C可以绑定到UI元素并显示加载消息 这是正确的方法吗 public class MyModel: MvxViewModel { private readonly IMyService _myService; private bool _isBusy; public bool IsB
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;
}
}
看起来还可以,不过我会在等待的时候添加一个try-catch-finally
public async void DoMyCommand()
{
IsBusy = true;
try{
await Task.Factory.StartNew(() =>
{
_myService.LongRunningProcess();
});
}catch{
//Log Exception
}finally{
IsBusy = false;
}
}
此外,我在我的博客上有一个例子,它使用了带有异步的MvxCommand。与您的示例非常相似您应该避免
异步无效
。当您处理ICommand
时,确实需要使用async void
,但其范围应该最小化
此修改后的代码将您的操作公开为一个异步任务
,该任务是可从代码的其他部分进行单元测试和消耗的:
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中的一种常见方法
我确实将
Task.Factory.StartNew
更改为Task.Run
<代码>任务.Run在async
代码中是首选。MvvmCross现在有MvxAsyncCommand
(请参阅GitHub)
因此,与其这样做
public ICommand MyCommand
{
get
{
return new MvxCommand(async () => await DoMyCommand());
}
}
你可以这样做
public ICommand MyCommand
{
get
{
return new MvxAsyncCommand(DoMyCommand);
}
}
您还可以使用避免使用锅炉板代码(命令),并将UI直接绑定到异步方法
此外,如果您使用,您的代码将如下所示:
[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”
另一方面,与其使用wait Task.Factory.StartNew()
,为什么不使\u myService.LongRunningProcess
异步呢?
这样看起来会更好:
public async Task DoSomething()
{
IsBusy = true;
await _myService.LongRunningProcess();
IsBusy = false;
}
自从我发布此消息后,我已经删除了IsBusy标志,并添加了对IAlertsService的调用。这有助于集中加载/警报逻辑,并将其从各个视图中删除;
async
lambda为您提供了稍微不同的错误处理。使用()=>domaycommand()
,来自domaycommand
的任何异常都会被默默地吞没。使用async()=>wait-DoMyCommand()
,来自DoMyCommand
的任何异常都将被视为未处理的异常。@ChrisKoiak,你能举一个例子,说明你如何在博客文章或文章中实现和使用IAlertService,或者只是一个概念性的解释吗?@Vackup:我倾向于遵循这个答案中的简单模式,直到我需要更复杂的东西。自定义“异步命令”可以更好地处理某些用例:繁忙的微调器/执行时禁用、取消命令、数据绑定结果/错误。按照Async
方法命名约定的建议使用Async
:返回新的MvxAsyncCommand(DoMyCommandAsync)代码>