0
votes

Using Xamarin Forms 4.0 with the new Shell feature, I have a button on a page .Let's call this page the Start Page.

When I press the button the user is navigated to a Second Page using Shell.Current.GoToAsync.

When the user later navigates back to the Start Page the button is now deactiviated. But why?

Here is the code in the view model:

public class SomeViewModel : ReactiveObject
{
   private ReactiveCommand<Unit, Unit> _someCommand;

   public ReactiveCommand<Unit, Unit> SomeCommand
   {
      get => _someCommand;
      set => this.RaiseAndSetIfChanged(ref _someCommand, value);
   }

   public SomeViewModel
   {

      SomeCommand = ReactiveCommand.CreateFromTask<Unit>(async x =>
      {
          await Shell.Current.GoToAsync("//Root/SomePage");
      }).Subscribe();

}

By trial and error, I found a solution.

Specifically, by making the following change to the definition of SomeCommand, the button will no longer be disabled when the user returns to the Start Page:

[...]
   SomeCommand = ReactiveCommand.CreateFromTask<Unit>(async x =>
      {
          await Task.CompletedTask;
      })
     .Select(_ => Observable.FromAsync(() => Shell.Current.GoToAsync("//Root/SomePage")}")))
     .Concat()
     .Subscribe();
[...]

Can anyone expain what is going on here? Why does the first approach not work, and why does the second approach work? To me the two approaches look more or less identical.

I'm using ReactiveUI version v9.17.4. So far I've only tested this on iOS.

UPDATE: Turned out to be a threading issue.

1
You can simplify approach two with CreateFromObservable instead is using select and stuff. I strongly suspect you got a threading issue happening there.Glenn Watson
Using CreateFromObservable is a nice simplification, that I was not aware of. However, it yields the same issue with the button becoming disabled as the first approach, so it will not work here. I agree that a threading issue could be the issue. I will try and investigate some more.1iveowl
You don't need the .Subscribe(); is another thing I just noticedGlenn Watson

1 Answers

0
votes

Use Interactions

public static class Interactions
{
    public static readonly Interaction<string, Unit> Navigate = new Interaction<string, Unit>();
}

then, in AppShell constructor:

Interactions.Navigate.RegisterHandler(async context =>
{
    await Current.GoToAsync(context.Input);
    context.SetOutput(Unit.Default);
}

and in your ViewModel constructor:

ReactiveCommand<Unit, Unit> NavigateToSettingsCommand = ReactiveCommand.CreateFromObservable(() => Interactions.Navigate.Handle("settings"))