2013-05-31 10 views
6

Voglio usare async/await sul mio Windows Phone 8 progetto MVVM e sto faticando a trovare un buon modo per implementare i miei ICommands usando questa api. Ho letto alcuni articoli sull'argomento e mi sono imbattuto in questo da MSDN in basso, che afferma che devo evitare vuoti asincroni poiché diventa difficile rilevare eccezioni non gestite: http://msdn.microsoft.com/en-us/magazine/jj991977.aspx In un'altra domanda ho chiesto informazioni soggetto, qualcuno ha anche detto che non dovrei usare vuoti asincroni. A meno che non ci siano eventi.async/await in MVVM senza metodi di annullamento

Ma il problema è che tutti gli esempi che posso trovare su internet utilizzano vuoti asincroni. Questi due articoli che ho trovato sono esempi: http://richnewman.wordpress.com/2012/12/03/tutorial-asynchronous-programming-async-and-await-for-beginners/ e http://blog.mycupof.net/2012/08/23/mvvm-asyncdelegatecommand-what-asyncawait-can-do-for-uidevelopment/

L'ultimo è un'implementazione di iCommand usando async/attendono, ma utilizza anche vuoti asincrone. sto cercando di trovare una soluzione per questo, così ho scritto questa implementazione di ICommand sulla base del RelayCommand:

public delegate Task AsyncAction(); 

public class RelayCommandAsync : ICommand 
{ 
    private AsyncAction _handler; 
    public RelayCommandAsync(AsyncAction handler) 
    { 
     _handler = handler; 
    } 

    private bool _isEnabled; 
    public bool IsEnabled 
    { 
     get { return _isEnabled; } 
     set 
     { 
      if (value != _isEnabled) 
      { 
       _isEnabled = value; 
       if (CanExecuteChanged != null) 
       { 
        CanExecuteChanged(this, EventArgs.Empty); 
       } 
      } 
     } 
    } 

    public bool CanExecute(object parameter) 
    { 
     return IsEnabled; 
    } 

    public event EventHandler CanExecuteChanged; 

    public void Execute(object parameter) 
    { 
     ExecuteAsync(); 
    } 

    private Task ExecuteAsync() 
    { 
     return _handler(); 
    } 
} 

e sto cercando di usare in questo modo: nel costruttore:

saveCommand = new RelayCommandAsync(SaveSourceAsync); 

poi:

private async Task SaveSourceAsync() 
{ 
    await Task.Run(() => { Save(); }); 
} 

private void Save() 
{ 
    // Slow operation 
} 

il problema è che non mi sento bene con questo e qualsiasi altra applicazione come io non so quale sia la migliore e ottimale

Qualcuno può dare un po 'di luce su come dovrei usarlo, preferibilmente con MVVM?

risposta

21

Nell'articolo si fa riferimento, mi fece notare che ICommand.Execute è praticamente un gestore di eventi, quindi sarebbe considerato un'eccezione alla linea guida "evitare async void":

Per riassumere questa prima linea guida, si dovrebbe preferisci async Task async void ... L'eccezione a questa linea guida è costituita da gestori di eventi asincroni, che devono restituire void. Questa eccezione include metodi che sono logicamente gestori di eventi anche se non sono letteralmente gestori di eventi (ad esempio, implementazioni ICommand.Execute).

quanto riguarda la tua ICommand implementazione, in realtà introduce un difetto da non utilizzando async void: l'attuazione ICommand.Execute scarterà la Task senza osservare le sue eccezioni. Pertanto, l'implementazione ignorerà qualsiasi eccezione sollevata dal delegato async.

Al contrario, il post del blog si è collegato al ha un async void ICommand.Execute che await s il Task, permettendo l'eccezione di propagare il contesto di sincronizzazione UI. Quale - in questo caso - è il comportamento desiderato perché è lo stesso comportamento che si ottiene quando un valore sincrono di ICommand.Execute genera un'eccezione.

Se si dispone di inclinazione, mi piacerebbe provare uno ICommand o due che ho scritto per l'inclusione futura possibile nel mio AsyncEx library. Il first one è un comando semplice molto simile a quello del blog che hai pubblicato.Lo second one è un'implementazione "comando asincrono" molto più completo che include cancellazione, rapporti di avanzamento e gestione automatica di CanExecute. Apprezzerei qualsiasi feedback.

+0

Sto dando un'occhiata alla tua libreria e alle implementazioni. Quindi dimmi qualcosa, con l'implementazione ICommand per il post del blog che ho inserito qui, se si verifica un'eccezione, se si solleva l'evento di eccezione non gestito in Windows Phone App.xaml? Lo proverò più tardi. –

+0

Stavo dando un'occhiata a 'SimpleAsyncCommand', sembra che funzioni dai miei scopi, voglio solo sapere: il mio nethod che' ExecuteAsync' chiamerà sta per essere eseguito nei contesti UI e dovrei usa 'aspetta Task.Run' all'interno di questo metodo, giusto? Perderò eventuali eccezioni lavorando in questo modo? Se no, penso che userò la tua lib! –

+0

Le eccezioni da "ICommand's verranno generate nell'interfaccia utente di WP, quindi verranno inviate a" Application.UnhandledException ". 'ExecuteAsync' sarà eseguito sul thread dell'interfaccia utente (quindi il tuo delegato' async' inizierà a girare sul thread dell'interfaccia utente). Puoi usare 'await Task.Run' se hai dei blocchi da fare per quel comando; se hai un lavoro asincrono da fare, non avresti bisogno di 'Task.Run' e puoi semplicemente usare' await'. E non è ancora parte della mia lib ora; per ora dovrai solo copiare il codice sorgente. –

Problemi correlati