diff --git a/src/ReactiveUI.XamForms/RoutedViewHost.cs b/src/ReactiveUI.XamForms/RoutedViewHost.cs
index 1d6c114352..dfe370c53b 100644
--- a/src/ReactiveUI.XamForms/RoutedViewHost.cs
+++ b/src/ReactiveUI.XamForms/RoutedViewHost.cs
@@ -6,13 +6,13 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Reactive;
+using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reactive.Threading.Tasks;
using System.Reflection;
using Splat;
using Xamarin.Forms;
-#pragma warning disable RCS1090 // Call 'ConfigureAwait(false)'.
namespace ReactiveUI.XamForms
{
///
@@ -20,7 +20,8 @@ namespace ReactiveUI.XamForms
///
///
///
- public class RoutedViewHost : NavigationPage, IActivatableView
+ [SuppressMessage("Readability", "RCS1090: Call 'ConfigureAwait(false)", Justification = "This class interacts with the UI thread.")]
+ public class RoutedViewHost : NavigationPage, IActivatableView, IEnableLogger
{
///
/// The router bindable property.
@@ -38,13 +39,13 @@ public class RoutedViewHost : NavigationPage, IActivatableView
/// You *must* register an IScreen class representing your App's main Screen.
public RoutedViewHost()
{
- this.WhenActivated(new Action>(d =>
+ this.WhenActivated(disposable =>
{
bool currentlyPopping = false;
bool popToRootPending = false;
bool userInstigated = false;
- d(this.WhenAnyObservable(x => x.Router.NavigationChanged)
+ this.WhenAnyObservable(x => x.Router.NavigationChanged)
.Where(_ => Router.NavigationStack.Count == 0)
.Select(x =>
{
@@ -54,21 +55,25 @@ public RoutedViewHost()
popToRootPending = true;
return x;
})
- .Subscribe());
-
- var previousCount =
- this.WhenAnyObservable(x => x.Router.NavigationChanged)
- .CountChanged()
- .ObserveOn(Router.Scheduler)
- .Select(_ => Router.NavigationStack.Count)
- .StartWith(Router.NavigationStack.Count);
-
- var currentCount = previousCount.Skip(1);
+ .Subscribe()
+ .DisposeWith(disposable);
+
+ Router.NavigationChanged
+ .CountChanged()
+ .Select(_ => Router.NavigationStack.Count)
+ .StartWith(Router.NavigationStack.Count)
+ .Buffer(2, 1)
+ .Select(counts => new
+ {
+ Delta = counts[0] - counts[1],
+ Current = counts[1],
- d(Observable.Zip(previousCount, currentCount, (previous, current) => new { Delta = previous - current, Current = current })
+ // cache current viewmodel as it might change if some other Navigation command is executed midway
+ CurrentViewModel = Router.GetCurrentViewModel()
+ })
.Where(_ => !userInstigated)
.Where(x => x.Delta > 0)
- .SelectMany(
+ .Select(
async x =>
{
// XF doesn't provide a means of navigating back more than one screen at a time apart from navigating right back to the root page
@@ -94,14 +99,20 @@ public RoutedViewHost()
finally
{
currentlyPopping = false;
- ((IViewFor)CurrentPage).ViewModel = Router.GetCurrentViewModel();
+ if (CurrentPage is IViewFor page && x.CurrentViewModel != null)
+ {
+ page.ViewModel = x.CurrentViewModel;
+ }
}
return Unit.Default;
})
- .Subscribe());
+ .Concat()
+ .Subscribe()
+ .DisposeWith(disposable);
- d(this.WhenAnyObservable(x => x.Router.Navigate)
+ Router
+ .Navigate
.SelectMany(_ => PageForViewModel(Router.GetCurrentViewModel()))
.SelectMany(async page =>
{
@@ -125,20 +136,21 @@ public RoutedViewHost()
popToRootPending = false;
return page;
})
- .Subscribe());
+ .Subscribe()
+ .DisposeWith(disposable);
var poppingEvent = Observable.FromEvent, Unit>(
- eventHandler =>
- {
- void Handler(object sender, NavigationEventArgs e) => eventHandler(Unit.Default);
- return Handler;
- },
- x => Popped += x,
- x => Popped -= x);
+ eventHandler =>
+ {
+ void Handler(object sender, NavigationEventArgs e) => eventHandler(Unit.Default);
+ return Handler;
+ },
+ x => Popped += x,
+ x => Popped -= x);
// NB: Catch when the user hit back as opposed to the application
// requesting Back via NavigateBack
- d(poppingEvent
+ poppingEvent
.Where(_ => !currentlyPopping && Router != null)
.Subscribe(_ =>
{
@@ -146,19 +158,23 @@ public RoutedViewHost()
try
{
- if (Router.NavigationStack.Count > 1)
- {
- Router.NavigationStack.RemoveAt(Router.NavigationStack.Count - 1);
- }
+ Router.NavigationStack.RemoveAt(Router.NavigationStack.Count - 1);
}
finally
{
userInstigated = false;
}
- ((IViewFor)CurrentPage).ViewModel = Router.GetCurrentViewModel();
- }));
- }));
+ var vm = Router.GetCurrentViewModel();
+ if (CurrentPage is IViewFor page && vm != null)
+ {
+ // don't replace view model if vm is null
+ page.ViewModel = vm;
+ }
+ })
+ .DisposeWith(disposable);
+ });
+
var screen = Locator.Current.GetService();
if (screen == null)
{
@@ -169,8 +185,8 @@ public RoutedViewHost()
this.WhenAnyValue(x => x.Router)
.SelectMany(router =>
- router
- .NavigationStack
+ {
+ return router.NavigationStack
.ToObservable()
.Select(x => (Page)ViewLocator.Current.ResolveView(x))
.SelectMany(x => PushAsync(x).ToObservable())
@@ -184,7 +200,8 @@ public RoutedViewHost()
((IViewFor)CurrentPage).ViewModel = vm;
CurrentPage.Title = vm.UrlPathSegment;
- }))
+ });
+ })
.Subscribe();
}
@@ -227,4 +244,3 @@ protected IObservable PageForViewModel(IRoutableViewModel vm)
}
}
}
-#pragma warning restore RCS1090 // Call 'ConfigureAwait(false)'.