首页 > 解决方案 > 这种模式是否可以通过 Akavache 在 ViewModel 中加载和缓存数据并将它们绑定到 Xamarin.Forms 中的 UI?

问题描述

我试图找到一些“最佳实践”示例,如何在现实场景中使用 Xamarin.Forms、ReactiveUI 和 Akavache。假设有一个代表客户详细信息的简单页面。它应该在激活(导航到)时从服务器检索数据。我喜欢 Akavache 的 GetAndFetchLatest 扩展方法的想法,所以我想使用它。

我最终得到了这样的结果:

public class CustomerDetailViewModel : ViewModelBase //(ReactiveObject, ISupportsActivation) 
{
  private readonly IWebApiClient webApiClient;

  public Customer Customer { get; }
  public ReactiveCommand<Unit, Unit> GetDataCommand { get; }

  public CustomerDetailViewModel(Customer customer, IWebApiClient webApiClient = null) 
  {
    this.Customer = customer;
    this.webApiClient = webApiClient ?? Locator.Current.GetService<IWebApiClient>();

    GetDataCommand = ReactiveCommand.CreateFromTask(GetData);
  }

  private Task GetData()
  {
    BlobCache.LocalMachine.GetAndFetchLatest($"customer_{Customer.Id.ToString()}",
      () => webApiClient.GetCustomerDetail(Customer.Id))
      .Subscribe(data =>
      {
        CustomerDetail = data;
      });

    return Task.CompletedTask;
  }

  private CustomerDetail customerDetail;
  public CustomerDetail CustomerDetail
  {
    get => customerDetail;
    set => this.RaiseAndSetIfChanged(ref customerDetail, value);
  }
}

DTO

public class Customer 
{
  public Guid Id { get; set; }
  public string Name { get; set; }
}

public class CustomerDetail 
{
  public Guid Id { get; set; }
  public string Name { get; set; }
  public string Description { get; set; }
}

查看绑定

this.WhenActivated(disposables =>
{
  this.OneWayBind(this.ViewModel, x => x.Customer.Name, x => x.nameLabel.Text)
    .DisposeWith(disposables);

  this.OneWayBind(this.ViewModel, x => x.CustomerDetail.Description, x => x.descriptionLabel.Text)
    .DisposeWith(disposables);

  this.ViewModel?.GetDataCommand.Execute().Subscribe();
}

但我认为这不是 100% 防弹的。这有一些可能的问题:

  1. 当我想在激活时加载数据时可以调用视图this.ViewModel?.GetDataCommand.Execute().Subscribe();吗?this.WhenActivated(d => ...)
  2. 绑定到CustomerDetail.Description会导致NullReferenceException我是对的吗?或者它安全吗?
  3. 我想做一些类似的事情:“如果有CustomerDetail,显示CustomerDetail.Name。当它还没有加载时,显示Customer.Name”。因为它,我需要在 ViewModel 上创建特定的属性吗?
  4. 如何指示加载?
  5. 我在这里错过了一些重要的事情吗?我还有其他一些问题吗?

标签: c#xamarin.formsreactiveuiakavache

解决方案


  1. 您可以在 ViewModel 中使用 WhenActivated,您可以实现一个接口ISupportActivationGetData然后,您可以从您的 ViewModel调用或运行。还有一个辅助扩展方法称为InvokeCommand()
  2. 我们故意不向下传播。我们使用我们自己的空传播形式。
  3. 在这种情况下,您可能会在控件上设置文本是一种方法。在显示您的视图之前,WhenActivated 不会发生。
  4. 我通常将其作为 ViewModel 上的布尔属性来完成,ViewModel 可以考虑不同的命令等。您可能会对ObservableAsPropertyHelper命令调用执行StartsWith(false)
  5. 我可能会ObservableAsPropertyHelper在您的 BlobCache 上使用 a 但看起来很合理的代码。

推荐阅读