【问题标题】:When to load the ViewModel for asynchronous data in a Xamarin Android app?何时在 Xamarin Android 应用程序中加载异步数据的 ViewModel?
【发布时间】:2017-09-06 02:39:14
【问题描述】:

如果服务是异步的,我什么时候可以加载视图模型数据?

我在 Xamarin Android 应用程序中使用 MVVM Light。视图模型需要以异步操作从 SqlLite 加载数据。类似的东西

class MyViewModel
{
     public Task Initialize()
     {
          Records = await _database.LoadData();
     }
     ...

我不清楚何时需要调用 Initialize() 以及是否需要等待加载完成。

【问题讨论】:

    标签: c# mvvm xamarin.android async-await mvvm-light


    【解决方案1】:

    假设您了解 ObservableCollection 以及使用 async void 的后果(请参阅下面的我的 cmets),我会推荐以下方法之一:

    更简单的方法是在构造函数中调用InitializeAsync() 方法开始加载:

    class MyViewModel
    {
        public MyViewModel()
        {
            InitializeAsync();
        }
    
        //warning: async void! 
        public async void InitializeAsync()
        {
            Records = await _database.LoadData();
        }
    }
    

    或者你可以调整_database服务来做延迟加载(我推荐这种方法,因为它保持ViewModel干净):

    class MyViewModel
    {
        public MyViewModel()
        {
            Records = _database.LoadData();
        }
    }
    
    class Database
    {
        private ObservableCollection<Record> _data = new ObservableCollection<Record>();
        public ObservableCollection<Record> LoadData()
        {
            EnsureLoaded();
            return _data;
        }
    
        private bool _isLoaded = false;
        private async void EnsureLoaded()
        {
            lock (this)
            {
                if (_isLoaded)
                    return;
    
                _isLoaded = true;
            }
    
            //do the actual loading here
            var myResultList = await DoLoadingAsync();
            foreach (myResultList as item)
            {
                _data.Add(item);
            }
        }
    }
    

    关于async void的说明:

    您可以使用 void(而不是 Task)作为异步方法的返回类型。这将导致“即发即弃”操作:

    public void DoStuff()
    {
        FireAndForgetAsync();
    }
    
    private async void FireAndForgetAsync()
    {
        await Task.Delay(1000);
        throw new Exception(); //will be swallowed
    }
    

    当您返回 void 时,您不能等待 FireAndForgetAsync。您将无法知道该方法何时结束,并且在 async void 方法中引发的任何异常都将被吞没。

    关于ObservableCollection的说明:

    这种类型的List 在您添加/删除/替换项目后引发事件。您可以使用此事件来填充您的视图,而无需在每次更改时重新加载整个列表。 如果你正确地实现了这一点,你可以在完成加载后立即向用户显示每个项目,而不是让他等到所有内容都完全加载。

    【讨论】:

      【解决方案2】:

      您可以使用 Xamarin.CommunityToolkit 尝试这种方式:

      MyViewModel.cs:

      using Xamarin.CommunityToolkit.ObjectModel;
      ...
      
      
      public ICommand LoadCommand { get; protected set; }
      
      public MyViewModel()
      {
          LoadCommand = new AsyncCommand(async () =>
          {
              // load data async
          });
      }
      

      Page.xaml:

      <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                   xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                   xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
                   xmlns:vm="clr-namespace:MyProject.ViewModels">
      
      <ContentPage.BindingContext>
          <vm:MyViewModel />
      </ContentPage.BindingContext>
      
      <ContentPage.Behaviors>
          <xct:EventToCommandBehavior EventName="Appearing" Command="{Binding LoadCommand}" />
      </ContentPage.Behaviors>
      
      ...
      
      

      【讨论】:

        【解决方案3】:

        另一个好方法是使用EventToCommandBehavior。 假设您想从 Web 服务器加载数据。

        在您的视图模型中创建命令,例如

        LoadCommand = new Command(async () =>
        {
            var result =  await service.GetYourObjectsAsync();
            Items = new ObservableCollection<YourObject>(result);
        });
        
        
        <ContentPage>
          <ContentPage.Behaviors>
            <local:EventToCommandBehavior EventName="Appearing" Command="{Binding LoadCommand }">
            </local:EventToCommandBehavior>
         </ContentPage.Behaviors>
        </ContentPage>
        

        当页面将引发出现事件时,您的加载命令会引发,您可以在命令操作中做任何您想做的事情...

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多