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();
        }
Esempio n. 4
0
        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);
        }
Esempio n. 6
0
        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();
            };
        }