method - why using async and await in c#



Come posso usare async in un modello di vista mvvmcross? (3)

È inoltre possibile utilizzare il plugin MethodBinding per evitare il codice della piastra di caldaia (comandi) e collegare l'interfaccia utente direttamente al metodo asincrono.

Inoltre, se usi Fody PropertyChanged , il tuo codice sarà simile a questo:

[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;
    }
}

È possibile rendere l'associazione come: "Fare clic su DoSomething".

D'altra parte, invece di usare await Task.Factory.StartNew() , perché non creare _myService.LongRunningProcess async? Sembrerebbe molto meglio:

public async Task DoSomething()
{
    IsBusy = true;
    await _myService.LongRunningProcess();
    IsBusy = false;
}

Ho un lungo processo in esecuzione in un viewmodel mvvmcross e desidero renderlo async ( http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx ).

La parola chiave async è attualmente supportata nel canale beta di Xamarin.

Di seguito è riportato un esempio di come sto attualmente implementando async. Il flag IsBusy potrebbe essere associato a un elemento dell'interfaccia utente e visualizzare un messaggio di caricamento.

È questo il modo corretto?

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;
    }

}

Answer #1

Dovresti evitare il async void . Quando hai a che fare con ICommand , devi usare async void , ma il suo ambito dovrebbe essere minimizzato.

Questo codice modificato espone l'azione come un'attività async Task , che è unità verificabile e utilizzabile da altre parti del codice:

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;
  }
}

Il tuo uso di IsBusy va bene; questo è un approccio comune nelle interfacce utente asincrone.

Ho fatto cambiare Task.Factory.StartNew a Task.Run ; Task.Run è preferito nel codice async per le ragioni descritte da Stephen Toub .


Answer #2

Sembra OK, tranne che vorrei aggiungere una cattura try finalmente in attesa.

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

Inoltre ho un esempio sul mio blog usando un MvxCommand con async. Molto simile al tuo esempio http://deapsquatter.blogspot.com/2013/03/updating-my-mobile-apps-for-async.html





mvvmcross