Calling an asynchronous method from the ViewModel Constructor Xamarin.Forms

I cannot find a direct example from az on how to safely implement an async method call from a constructor. Below is what I came up with, but I don't understand the concepts very well, so I have no idea if this is actually correct or not. Can someone bless this format?

Create IAsyncInitialization inteface:

/// <summary>
/// The result of the asynchronous initialization of this instance.
/// see http://blog.stephencleary.com/2013/01/async-oop-2-constructors.html
/// </summary>
Task Initialization { get; }

      

Hang the interface on this ViewModel, then ...:

public GotoViewModel() // constructor
{
    Initialization = InitializeAsync();
}

public Task Initialization { get; private set; }
private async Task InitializeAsync()
{
    //call some async service and get data
}

      

From the xaml.cs code using this ViewModel:

public partial class GotoPage : ContentPage, IAsyncInitialization
{
    IGotoViewModel VM;
    public GotoPage()
    {
         InitializeComponent();
         VM = App.Container.Resolve<IGotoViewModel>();
         Initialization = InitializeAsync();
     }

     public Task Initialization { get; private set; }

     private async Task InitializeAsync()
     {
          await VM.Initialization;
          this.BindingContext = VM;
     }
}

      

This code works great, but I know it means little.

+3


source to share


2 answers


Perhaps a future version in C # is the ability to create asynchronous constructors, but until we reach this awesome future, you can specify your options.

you can use

.Wait()

      

However, you need to be aware of which streams you are using. If the virtual machine is called on the UI thread, you block the UI until the asynchronous tasks complete. If the asynchronous task is also using something on the UI thread, then this is where you get a dead end.

A way to alleviate this in some conditions is to do

Task.Run(async () => { await Initialize(); }).Wait();

      

But then again, his reliable and possible dead ends do not await.

Another option is to do some very advanced stuff that even I don't quite understand what this code does, but it works.

If you look at Exrin ThreadHelper.cs it contains the method



public static void RunOnUIThread(Func<Task> action)

      

This allows you to run a task in the same UIThread without blocking it. Because sometimes you need to start an asynchronous task, on the UI thread, and wait for it. It is difficult, but possible.

Now that you know why it is really hard to do async from the constructor. Here's an easy way.

Since your page is bound to a ViewModel, the best way is to pass the OnAppearing method to it. Hence, in your page, you do

public async void OnAppearing()
{
    await MyViewModelInstance.OnAppearing();
}

      

Then in your ViewModel you can do

public async Task OnAppearing()
{
    await InitializeAsync();
}

      

async void is perfectly acceptable as long as you are sure that the invoking method does not need a task to wait for the event to complete.

This way, initialization starts when the view appears, not its construct. This approach is applied in App.xaml.cs where you do it in OnStart and not in the constructor.

+2


source


Instead of calling it in your constructor or using the OnAppearing method that Adam Pedley mentioned, you can also use a simple MVVM Framework like FreshMvvm . In FreshMVVM, you can override the init () method to initialize your objects.



In my current project, I initialize my ViewModels with Autofac as an IoC-Container, and load stuff into the ViewModel after Autofac has instantiated it.

0


source







All Articles