3

I started experimenting with Reactive UI in Xamarin iOS and i'm confused to how I should handle routing.

Let's take the typical 'LoginViewModel' which has something like:

public class LoginViewModel : ReactiveObject
{
    private readonly ReactiveCommand loginCommand;
    public ReactiveCommand LoginCommand => this.loginCommand;

    string username;
    public string Username
    {
        get { return username; }
        set { this.RaiseAndSetIfChanged(ref username, value); }
    }

    string password;
    public string Password
    {
        get { return password; }
        set { this.RaiseAndSetIfChanged(ref password, value); }
    }

    public LoginViewModel()
    {
        var canLogin = this.WhenAnyValue(
            x => x.Username,
            x => x.Password,
            (u, p) => !string.IsNullOrEmpty(u) && !string.IsNullOrEmpty(p)
        );

        this.loginCommand = ReactiveCommand.CreateFromTask(async () =>
        {
            //Simulate login
            await Task.Delay(2000);
            return true;
        }, canLogin);
    }
}

And the ViewDidLoad (Controller):

this.WhenActivated(d =>
{
    this.Bind(this.ViewModel, x => x.Username, x => x.Username.Text).DisposeWith(d);
    this.Bind(this.ViewModel, x => x.Password, x => x.Password.Text).DisposeWith(d);
    this.BindCommand(this.ViewModel, x => x.LoginCommand, x => x.LoginButton).DisposeWith(d);
});

This effectively binds the values of those UITextFields and Login button enable states + OnTouchUpInside

Now, in de documentation you can find the following about vm-routing: Android, iOS Native: Very difficult to make work

So what would be my options here ?

Expose a DidLogIn property (bool) and listen (in the view) on that with:

this.WhenAnyValue(x => x.ViewModel.DidLogIn)
    .ObserveOn(RxApp.MainThreadScheduler)
    .Subscribe(() => {
        //Routing logic here
    });

Are there other ways to handle view-routing (not vm-routing), I can find very little information about this

RVandersteen
  • 2,067
  • 2
  • 25
  • 46

1 Answers1

5

ReactiveUI's routing on Xamarin Forms is very easy, Xamarin Android/iOS is different history, but you can try ReactiveUI's interactions here is an example:

public class LoginViewModel : ReactiveObject
{

    private readonly Interaction<Unit, Unit> _navigate;
    public Interaction<Unit, Unit> Navigate => Navigate;

    public ReactiveCommand<Unit,bool> LoginCommand { get; set; }


    public LoginViewModel()
    {
        var canLogin = this.WhenAnyValue(
        x => x.Username,
        x => x.Password,
        (u, p) => !string.IsNullOrEmpty(u) && !string.IsNullOrEmpty(p));

        _navigate = new Interaction<Unit, Unit>();

        LoginCommand = ReactiveCommand.CreateFromTask<Unit, bool>(async _ =>
        {
            /*Logic here*/
            return true;
        }, canLogin);

       LoginCommand.Subscribe(async result => 
        {
            if (result)//this logic gets executed on your view by registering a handler :D
                await await _navigate.Handle(Unit.Default) ;
            else
                {}
        });
    }
}

So in your view

this.WhenActivated(disposables =>
{
   //bindings...
   //Register a handler:
   ViewModel.Navigate.RegisterHandler(async interaction =>
   {
       await NavigationLogic();
       interaction.SetOutput(Unit.Default);
   }).DisposeWith(disposables);
});

The example is not perfect, but is one way to do it.

I hope this helps you, you can find more on interactions in: https://reactiveui.net/docs/handbook/interactions/

Also there is an example in Xamarin Android + ReactiveUI: https://github.com/bl8/ReactivePhoneword

Regards

Adrián Romero
  • 620
  • 7
  • 17