简体   繁体   中英

MVVMCross async and await method in PCL

I am having a little problem with my binding of my MvxSpinner and my ViewModel. It doesn't seem to display any data in my spinner.

My ViewModel calls a service which actually returns data so I can populate my ViewModel and then my ViewModel populates my View.

The problem is that my service calls are async and it seems to me that the view gets loaded first while my service is still trying to get data.

This all happens when my View is loading so the spinner is bound to my ViewModel. This did work before I decided to make the services async. How can I make sure that my view gets the latest ViewModel data?

Here is my ViewModel

public class HomeViewModel
    : MvxViewModel
{

    string PracticeName = string.Empty;

    private readonly IMvxMessenger _messenger;
    private readonly IHomeService _homeService;
    public HomeViewModel(IHomeService homeService, IMvxMessenger messenger)
    {
        _homeService = homeService;
        _messenger = messenger;
        GetPractice ();
        _homeService.GetReportList(this);
    }

    public HomeViewModel()
    {

    }


    private async void GetPractice()
    {
        try 
        {
            _practiceItems = await _homeService.GetPracticeList(this);
        } 
        catch (Exception ex) 
        {
            //return null;
        }
    }

    public class Practices
    {
        public string ErrorMessage { get; set; }

        public List<string> Practice { get; set; }
    }

    private List<string> _practiceItems;
    public List<string> PracticeItems
    {
        get { return _practiceItems; }
        set { _practiceItems = value; RaisePropertyChanged(() => PracticeItems); }
    }
}

Here is my service

public class HomeService : IHomeService
{
    public HomeService()
    {

    }

    public async Task<List<string>> GetPracticeList(HomeViewModel viewModel)
    {
        HomeViewModel.Practices rootobject = null;
        var client = ClientHandler.Client;

        client.BaseAddress = new Uri("http://10.1.20.106/sdf");

        HttpResponseMessage msg = await client.GetAsync (string.Format ("api/practice?username={0}", ClientHandler.Username));
        if(msg.IsSuccessStatusCode)
        {
            var res = await msg.Content.ReadAsStringAsync();
            rootobject = JsonConvert.DeserializeObject<HomeViewModel.Practices>(res);
            if (!string.IsNullOrEmpty (rootobject.ErrorMessage)) 
            {
                return null;
            }
            //return rootobject.Practice;
        }

        return rootobject.Practice;
    }   
}

Also to note that this View only comes after a previous View has click on a button to navigate to this View.

Please call RaisePropertyChanged forcefully after the await keyword like below.

private async void GetPractice()
{
    try 
    {
        _practiceItems = await _homeService.GetPracticeList(this);
        RaisePropertyChanged(() => PracticeItems); 
    } 
    catch (Exception ex) 
    {
        //return null;
    }
}

I believe that modern (at least since the 5th major version) way of doing this is (1) using SetProperty() base class' method in property setter to set the property backing field value and (2) overriding async Initialize() with your code with setting the property value:

private List<string> _practiceItems;
public List<string> PracticeItems
{
    get => _practiceItems;
    set => SetProperty(ref _practiceItems, value);
}

public override async Task Initialize()
{
    await base.Initialize();        
    PracticeItems = await _homeService.GetPracticeList(this);
}

The benefit of this approach is that SetProperty() takes care of NotifyPropertyChanged if the new value was different from the current one and that you use a proper place to call an async method from (because it's definitely not a good practice to call async method from constructor).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM