1

I am trying to find some 'best practice' sample how to use Xamarin.Forms, ReactiveUI and Akavache in realworld scenario. Lets say there is simple page representing Customer Detail. It should retrieve data from server when activated (navigated to). I like the idea of GetAndFetchLatest extension method from Akavache so I would like to use it.

I ended up with something like this:

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

DTOs

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

View binding

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

But I think this is not 100% bullet proof. There are some possible problems with this:

  1. Is it ok to call this.ViewModel?.GetDataCommand.Execute().Subscribe(); in this.WhenActivated(d => ...) on the view when I want to load data on activation?
  2. Binding to CustomerDetail.Description can cause NullReferenceException am I right? Or is it safe?
  3. I want to do somethin like: "If there is CustomerDetail, show CustomerDetail.Name. When its not loaded yet, show Customer.Name". Do I need to make specific Property on ViewModel because of it?
  4. How to indicate loading?
  5. Am I missing something important here? Some other problems I can have with this?
alesdvorak.cz
  • 133
  • 1
  • 10

1 Answers1

0
  1. You could use the WhenActivated in your ViewModel, there is a interface you can implement ISupportActivation. You can then invoke or run GetData from your ViewModel. There is also a helper extension method called InvokeCommand()
  2. We deliberately don't propogate down. We use our own form of null propagation.
  3. You could potentially set the text on your control in that case is one way. The WhenActivated won't happen until your View is shown.
  4. I usually have done this as a boolean property on the ViewModel, the ViewModel can take into account different commands etc. You could potentially do a ObservableAsPropertyHelper to a command calling StartsWith(false)
  5. Potentially I would use a ObservableAsPropertyHelper on your BlobCache but looks reasonable code.
Glenn Watson
  • 2,758
  • 1
  • 20
  • 30
  • 1. Ok thanks 2. Dont understand your question. So is it safe to do it? I think my app behave weirdly when I do this 3. OK 4. Can you show me some example how to do it with GetAndFetchLatest? It returns IObservable 5. OK – alesdvorak.cz Apr 19 '19 at 19:07