Don of the Day

Don of the Day


Adventures in software development with Xamarin and UWP.

Software developer, building things with code in sunny Scottsdale, AZ.

Share


Twitter


Xamarin.Forms, MVVM async Constructor

Don FitzsimmonsDon Fitzsimmons

I had a problem. You see, I'm working on a Xamarin.Forms app using MVVM and I have a list view that needs to make a network call to load data when the view becomes visible. Not an uncommon scenario. Tap an icon, navigate to a page, which instantiates its corresponding view model, load data into the list. Simple.

When using MVVM, this presents a bit of an asynchronous dilemma. Where do you make the async call to load your data? Ultimately that network call has to be made from the constructor within the view model, but a constructor can't make an async call. You may be tempted to do something nasty like this inside your constructor:


Task.Run(async () => await LoadDataAsync()).Wait();

But, this will block your UI while that LoadData method is making the network call because you're forcing it to wait. It's effectively a synchronous call. There are a few other approaches that I have tried to resolve the issue of async calls in a constructor, but nothing really worked well.

But then, after a series of Google searches, forum browsing and failed experiments, I came across this magnificent MSDN blog post that solved the problem and did it quite elegantly. The post is full of details about different approaches to this problem, but ultimately it comes down to the use of a custom class called NotifyTaskCompletion that's data binding friendly. If you scroll down in that post, you can copy the code, but here's what it looks like in action:


public class MainViewModel
{
  public MainViewModel()
  {
    MyDataBoundList = new NotifyTaskCompletion<List<MyCustomType>>(LoadDataAsync());
  }
  public NotifyTaskCompletion MyDataBoundList { get; private set; }
}

And the corresponding XAML in your view would look something like this:



    <ListView ItemSource="{Binding MyDataBoundList.Result}"/>

Your view will fully render and display and empty list while your network call loads the data (from the constructor of your view model) asynchronously. In my case I show a loading overlay while this happens, then, the list is populated once the async task is completed. It's really nice and made my day. Again, take a look at the full blog post for details.

Software developer, building things with code in sunny Scottsdale, AZ.

Comments