C# 如何在mvvmcross视图模型中使用async?

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

我在mvvmcross-viewmodel中有一个长时间运行的流程,希望使其异步()

Xamarin的beta频道目前支持async关键字

下面是我目前如何实现异步的一个示例。IsBusy标志C可以绑定到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;
    }

}

看起来还可以,不过我会在等待的时候添加一个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)