简体   繁体   English

PCL中的MVVMCross异步和等待方法

[英]MVVMCross async and await method in PCL

I am having a little problem with my binding of my MvxSpinner and my ViewModel. 我对MvxSpinner和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. 我的ViewModel调用一个实际返回数据的服务,这样我可以填充我的ViewModel,然后我的ViewModel填充我的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. 这一切都发生在我的View加载时,因此微调器绑定到我的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? 如何确保我的视图获取最新的ViewModel数据?

Here is my ViewModel 这是我的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. 另请注意,此View仅在上一个View单击按钮导航到此视图后才会出现。

Please call RaisePropertyChanged forcefully after the await keyword like below. 请在await关键字后强行调用RaisePropertyChanged ,如下所示。

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: 我认为现代(至少从第5个主要版本开始)这样做的方法是(1)在属性设置器中使用SetProperty()基类'方法来设置属性支持字段值,以及(2 用你的覆盖async Initialize()设置属性值的代码:

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). 这种方法的好处是,如果新值与当前值不同,SetProperty()会处理NotifyPropertyChanged,并且您使用适当的位置来调用异步方法(因为调用异步方法绝对不是一个好习惯)构造函数)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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