PCL中的MVVMCross异步和等待方法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PCL中的MVVMCross异步和等待方法相关的知识,希望对你有一定的参考价值。

我对MvxSpinner和ViewModel的绑定有点问题。它似乎没有在我的微调器中显示任何数据。

我的ViewModel调用一个实际返回数据的服务,这样我可以填充我的ViewModel,然后我的ViewModel填充我的View。

问题是我的服务调用是异步的,在我看来,当我的服务仍在尝试获取数据时,视图首先被加载。

这一切都发生在我的View加载时,因此微调器绑定到我的ViewModel。在我决定使服务异步之前,这确实有效。如何确保我的视图获取最新的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); }
    }
}

这是我的服务

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;
    }   
}

另请注意,此View仅在上一个View单击按钮导航到此视图后才会出现。

答案

请在RaisePropertyChanged关键字后强行拨打await,如下所示。

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

我认为现代(至少从第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);
}

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

以上是关于PCL中的MVVMCross异步和等待方法的主要内容,如果未能解决你的问题,请参考以下文章

MvvmCross Android 片段添加到后台堆栈

无法解析 MvxFramentActivity 中的 SupportFragmentManager

使单元测试等待另一个方法中的异步调用

如何在 mvvmcross 视图模型中使用异步?

关于其活动的片段生命周期

MvvmCross 4 和 Xamarin.iOS -> 使用 Storyboard 时如何从 Core 加载视图控制器?