Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Xamarin Forms populate data async on create

I have a Xamarin Form that is bound to a ViewModel. When this ViewModel is created I want it go get data from the DB asynchronously. My issue is I'm not sure how I to call the async method as the constructor cannot call an async method and the getter cannot call an async method.

I'm using pure XAML for the UI, is it possible for the XAML to call a method on initialisation?

My ViewModel:

public class DonorViewModel : BaseViewModel
{
    public DonorViewModel (IRepository<Donor> donorRepository)
    {
        _donorRepository = donorRepository;
    }

    private string _name;

    public string Name { 
        get {               
            return _name;
        }
        set {
            if (_name != value) {
                _name = value;
                OnPropertyChanged ("Name");
            }
        }
    }

    private IRepository<Donor> _donorRepository;

    private async Task GetName()
    {
        var donor = await _donorRepository.Get(d => d.Id == 1);
        Name = donor.Name;
    }
}

My XAML:

<?xml version="1.0" encoding="UTF-8"?>
<d:ViewPage xmlns="http://xamarin.com/schemas/2014/forms"       
            xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
            x:Class="DonationExample.DonorView"
            xmlns:d="clr-namespace:DonationExample;assembly=DonationExample" 
            x:TypeArguments="local:DonorViewModel"
            xmlns:local="clr-namespace:DonationExample">
    <ContentPage.BindingContext>

    </ContentPage.BindingContext>

    <StackLayout Spacing="10"
           VerticalOptions="End"
           Orientation="Horizontal"
           HorizontalOptions="Start">
        <Label x:Name="lblName" Font="20" Text="{Binding Name}" />

    </StackLayout>

</d:ViewPage>

XAML codebehind:

public partial class DonorView : ViewPage<DonorViewModel>
{
    public DonorView ()
    {
        InitializeComponent ();
    }
}

I thought maybe I could call it in the XAML code behind, but again this is in the constructor.

Any suggestions?

Thanks

like image 436
ADringer Avatar asked Jan 20 '16 22:01

ADringer


Video Answer


2 Answers

OnAppearing is a possible way to do it because you can legitimately use

public async void OnAppearing()
{

}

However it causes many issues such as when you come back from page in front it will run again.

Depending upon what navigation service or style you are using, I created a new event that gets call only when you first get to the page.

In my BaseViewModel.cs the OnNavigated event https://github.com/adamped/xarch-starter/blob/master/Mobile/Base/BaseViewModel.cs

Which is called when you Push the page on to the stack. Basically call this method when you push the page to your NavigationPage.

Alternatively if you want a quick way, use the OnAppearing method but put a flag/bool in there so you can tell when it has already run once and then won't run again.

like image 124
Adam Avatar answered Sep 27 '22 19:09

Adam


I get around this by calling the async code in my view model in OnAppearing of the page instead of the constructor. Constructors are for memory allocation not retrieve data asynchronously.

However, if you really wanted to, you could call .Wait() on your task and block the thread. I would NOT recommend this.

like image 39
valdetero Avatar answered Sep 27 '22 19:09

valdetero