28

我在 mvvmcross 视图模型中有一个长时间运行的过程,并希望使其异步(http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx)。

Xamarin 的 beta 通道当前支持 async 关键字。

下面是我当前如何实现异步的示例。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;
    }

}
4

4 回答 4

32

你应该避免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 中的一种常见方法。

我确实改成Task.Factory.StartNewTask.Run由于 Stephen Toub 描述的原因,在代码中Task.Run是首选。async

于 2013-06-19T11:06:55.337 回答
6

MvvmCross 现在有MvxAsyncCommand(参见 GitHub提交)。

所以而不是这样做

public ICommand MyCommand
{
  get
  {
    return new MvxCommand(async () => await DoMyCommand());
  }
}

你可以这样做

public ICommand MyCommand
{
  get
  {
    return new MvxAsyncCommand(DoMyCommand);
  }
}
于 2016-06-22T13:41:30.337 回答
3

看起来不错,除了我最终会在那个等待周围添加一个尝试捕获。

    public async void DoMyCommand()
    {
        IsBusy = true;
        try{
            await Task.Factory.StartNew(() =>
                                        {
                _myService.LongRunningProcess();
            });
        }catch{
            //Log Exception
        }finally{
            IsBusy = false;
        }
    }

此外,我的博客上有一个使用异步 MvxCommand 的示例。与您的示例非常相似http://deapsquatter.blogspot.com/2013/03/updating-my-mobile-apps-for-async.html

于 2013-06-19T10:33:09.130 回答
1

您还可以使用MethodBinding 插件来避免样板代码(命令),并将您的 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;
}
于 2016-07-05T19:57:37.740 回答