Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Async await in MVVM XAML Applications

I try to understand how should I receive initial data in my ViewModels with async/await pattern. Let's look at the code:

public interface IPeopleService
{
     Task<IEnumerable<Person> GetPeopleAsync();
}


public MainViewModel
{
    public ObservableCollection<Person> People{get;set;}

  public MainViewModel(IPeopleService peopleService)
  {
       LoadMyData(peopleService);
  }

    public async Task LoadMyData(IPeopleService peopleService)
    {
       try
       {
          People = await peopleService.GetPeopleAsync();
       }
       catch(Exception e)
       {
         //log       
         //notify user    
       }
    }

}

There is a PeopleService which contains asynchronous method to People Data. It is injected with IOC (whatever). After that I invoke asynchronous operation LoadMyData (to prevent blocking UI, so no await keyword) and inside that method I invoke asynchronous operation from service catching all exceptions and notyfying user. What's wrong with this approach?

I read article from msdn: https://msdn.microsoft.com/en-us/magazine/dn605875.aspx and when I noticed creating a generic class for this kind of Tasks and changing all my properties to use that class as generic parameter, change XAML Bindings to receive a Property.Result property, I think it's crazy and creates a big mess in the project. Furthermore properties in ViewModel specifies that this property is asynchronous which in my opinion is bad design. What is the EASIEST way to solve my problem? Is my solution acceptable to keep everything simple?

like image 567
MistyK Avatar asked Feb 09 '15 13:02

MistyK


1 Answers

After that I invoke asynchronous operation LoadMyData (to prevent blocking UI, so no await keyword) and inside that method I invoke asynchronous operation from service catching all exceptions and notyfying user. What's wrong with this approach?

Your UI is not blocked while loading the data. That's good. But asynchronous data loading brings up some questions: What does the UI show while the data is loading? How does the UI show errors to the user?

In your current code, the UI list is just empty while the data is loading. IMO there should be at the very least a "loading" kind of state so the user can distinguish between an empty result set and an operation still in progress. Also, your notify user code I assume is bringing up a dialog box or something - via code, not via data binding. IMO an error indicator is better than a modal dialog.

The purpose behind NotifyTaskCompletion<T> is that it acts as a data-bindable asynchronous operation. So you can use its properties to change to/from the "loading" and "error" states. This is why your bindings have to change to .Result - because you're binding to the result of the asynchronous operation. If you don't want to display a "loading" indicator and you don't want to display errors via data-binding, then yes, NotifyTaskCompletion<T> would be overkill.

It depends on how much you want to do data-binding. If you're happy with it all being in code, then that's fine:

public async Task LoadMyData(IPeopleService peopleService)
{
   try
   {
      ... // Hide people display
      ... // Show loading indicator
      People = await peopleService.GetPeopleAsync();
      ... // Show people display
   }
   catch(Exception e)
   {
      ... // Show error indicator
   }
   finally
   {
      ... // Hide loading indicator
   }
}

Or, you can do it all with data binding, which makes your code simpler:

// (wrapped in NotifyTaskCompletion)
public async Task LoadMyData(IPeopleService peopleService)
{
    People = await peopleService.GetPeopleAsync();
}

I've done it both ways, but I lean towards NotifyTaskCompletion<T> if I have a project that does a lot of asynchronous operations.

like image 73
Stephen Cleary Avatar answered Oct 13 '22 17:10

Stephen Cleary