public void ObserveAppStateDoesNotThrowInvalidCastException() { var fixture = new SuspensionHost(); Action result = () => fixture.ObserveAppState <DummyAppState>().Subscribe(); result.Should().NotThrow <InvalidCastException>(); }
public void ObserveAppStateDoesNotThrowException() { var fixture = new SuspensionHost(); var result = Record.Exception(() => fixture.ObserveAppState <DummyAppState>().Subscribe()); result.Should().BeNull(); }
public void NullAppStateDoesNotThrowException() { var fixture = new SuspensionHost(); var result = Record.Exception(() => fixture.SetupDefaultSuspendResume()); result.Should().BeNull(); }
public void ObserveAppStateDoesNotThrowInvalidCastException() { var fixture = new SuspensionHost(); var result = Record.Exception(() => fixture.ObserveAppState <DummyAppState>().Subscribe()); result.ShouldNotBeOfType <InvalidCastException>(); }
public void GetAppStateReturns() { var fixture = new SuspensionHost(); fixture.AppState = new DummyAppState(); var result = fixture.GetAppState <DummyAppState>(); result.Should().Be(fixture.AppState); }
static RxApp() { #if !PORTABLE _TaskpoolScheduler = TaskPoolScheduler.Default; #endif // Initialize this to false as most platforms do not support // range notification for INotifyCollectionChanged #if WP8 || NETFX_CORE SupportsRangeNotifications = false; #else SupportsRangeNotifications = true; #endif Locator.RegisterResolverCallbackChanged(() => { if (Locator.CurrentMutable == null) return; Locator.CurrentMutable.InitializeReactiveUI(); }); DefaultExceptionHandler = Observer.Create<Exception>(ex => { // NB: If you're seeing this, it means that an // ObservableAsPropertyHelper or the CanExecute of a // ReactiveCommand ended in an OnError. Instead of silently // breaking, ReactiveUI will halt here if a debugger is attached. if (Debugger.IsAttached) { Debugger.Break(); } RxApp.MainThreadScheduler.Schedule(() => { throw new Exception( "An OnError occurred on an object (usually ObservableAsPropertyHelper) that would break a binding or command. To prevent this, Subscribe to the ThrownExceptions property of your objects", ex); }); }); if (ModeDetector.InUnitTestRunner()) { LogHost.Default.Warn("*** Detected Unit Test Runner, setting MainThreadScheduler to CurrentThread ***"); LogHost.Default.Warn("If we are not actually in a test runner, please file a bug\n\n"); LogHost.Default.Warn("ReactiveUI acts differently under a test runner, see the docs\n"); LogHost.Default.Warn("for more info about what to expect"); _MainThreadScheduler = CurrentThreadScheduler.Instance; return; } else { LogHost.Default.Info("Initializing to normal mode"); } if (_MainThreadScheduler == null) { _MainThreadScheduler = DefaultScheduler.Instance; } SuspensionHost = new SuspensionHost(); }
protected AutoSuspendApplication() { var host = new SuspensionHost(); host.IsLaunchingNew = Observable.FromEventPattern<LaunchingEventArgs>( x => PhoneApplicationService.Current.Launching += x, x => PhoneApplicationService.Current.Launching -= x) .Select(_ => Unit.Default); host.IsUnpausing = Observable.FromEventPattern<ActivatedEventArgs>( x => PhoneApplicationService.Current.Activated += x, x => PhoneApplicationService.Current.Activated -= x) .Where(x => x.EventArgs.IsApplicationInstancePreserved) .Select(_ => Unit.Default); // NB: "Applications should not perform resource-intensive tasks // such as loading from isolated storage or a network resource // during the Activated event handler because it increase the time // it takes for the application to resume" host.IsResuming = Observable.FromEventPattern<ActivatedEventArgs>( x => PhoneApplicationService.Current.Activated += x, x => PhoneApplicationService.Current.Activated -= x) .Where(x => !x.EventArgs.IsApplicationInstancePreserved) .Select(_ => Unit.Default) .ObserveOn(RxApp.TaskpoolScheduler); // NB: No way to tell OS that we need time to suspend, we have to // do it in-process host.ShouldPersistState = Observable.Merge( Observable.FromEventPattern<DeactivatedEventArgs>( x => PhoneApplicationService.Current.Deactivated += x, x => PhoneApplicationService.Current.Deactivated -= x) .Select(_ => Disposable.Empty), Observable.FromEventPattern<ClosingEventArgs>( x => PhoneApplicationService.Current.Closing += x, x => PhoneApplicationService.Current.Closing -= x) .Select(_ => Disposable.Empty)); host.ShouldInvalidateState = Observable.FromEventPattern<ApplicationUnhandledExceptionEventArgs>(x => UnhandledException += x, x => UnhandledException -= x) .Select(_ => Unit.Default); SuspensionHost = host; // // Do the equivalent steps that the boilerplate code does for WP8 apps // if (RootFrame != null) return; RootFrame = new PhoneApplicationFrame(); var currentBackHook = default(IDisposable); var currentViewFor = default(WeakReference<IViewFor>); RootFrame.Navigated += (o, e) => { // Always clear the WP8 Back Stack, we're using our own while (RootFrame.RemoveBackEntry() != null) { } if (currentBackHook != null) currentBackHook.Dispose(); var page = RootFrame.Content as PhoneApplicationPage; if (page != null) { currentBackHook = Observable.FromEventPattern<CancelEventArgs>(x => page.BackKeyPress += x, x => page.BackKeyPress -= x) .Where(_ => ViewModel != null) .Subscribe(x => { if (!ViewModel.Router.NavigateBack.CanExecute(null)) return; x.EventArgs.Cancel = true; ViewModel.Router.NavigateBack.Execute(null); }); var viewFor = page as IViewFor; if (viewFor == null) { throw new Exception("Your Main Page (i.e. the one that is pointed to by WMAppManifest) must implement IViewFor<YourAppBootstrapperClass>"); } currentViewFor = new WeakReference<IViewFor>(viewFor); viewFor.ViewModel = ViewModel; } // Finally make it live RootVisual = RootFrame; }; _viewModelChanged.StartWith(ViewModel).Where(x => x != null).Subscribe(vm => { var viewFor = default(IViewFor); if (currentViewFor != null && currentViewFor.TryGetTarget(out viewFor)) { viewFor.ViewModel = vm; } }); UnhandledException += (o, e) => { if (Debugger.IsAttached) Debugger.Break(); }; RootFrame.NavigationFailed += (o, e) => { if (Debugger.IsAttached) Debugger.Break(); }; }