public async Task ViewIsOnlyActivatedWhenViewModelActivationHasCompleted()
        {
            var scheduler     = new TestScheduler();
            var screen        = new DelayedScreen(scheduler);
            var screenView    = new FakeDelayedScreenView(screen);
            var conductor     = new DelayedConductor(scheduler);
            var conductorView = new FakeDelayedConductorView(conductor);

            conductor.ActiveItem = screen;

            Assert.Equal(false, screenView.IsActivated);
            Assert.Equal(false, conductorView.IsActivated);

            // WPF raises the ViewLoaded event.
            // Note this event will be raised on root and will then be raised successively on all children.
            // Ref MSDN https://docs.microsoft.com/en-us/dotnet/framework/wpf/advanced/object-lifetime-events
            conductorView.Loaded.OnNext(Unit.Default);
            screenView.Loaded.OnNext(Unit.Default);

            Assert.Equal(false, screenView.IsActivated);
            Assert.Equal(false, conductorView.IsActivated);

            // The Conductor's Conductor triggers ActivateAsync
            await((IActivate)conductor).ActivateAsync(CancellationToken.None);

            Assert.Equal(true, screenView.IsActivated);
            Assert.Equal(true, conductorView.IsActivated);

            screenView.Unloaded.OnNext(Unit.Default);
            conductorView.Unloaded.OnNext(Unit.Default);
            screenView.Dispose();
            conductorView.Dispose();
        }
        public async Task ActivationCompletesWhenAllPartsHaveCompleted()
        {
            var scheduler = new TestScheduler();
            var screen    = new DelayedScreen(scheduler);
            var conductor = new DelayedConductor(scheduler);

            conductor.ActiveItem = screen;
            await((IActivate)conductor).ActivateAsync(CancellationToken.None);

            // scheduler is passed as a stopwatch
            Assert.Equal(610, conductor.WhenInitializedScopeStartTime);
            // Diff is conductor's scopes (2 * 5)
            Assert.Equal(620, scheduler.Clock);
        }
        public async Task ConductorScopesAreOnlyExecutedAfterActiveItemIsFullyActivated()
        {
            var scheduler  = new TestScheduler();
            var screen     = new DelayedScreen(scheduler);
            var screenView = new FakeDelayedScreenView(screen);
            var conductor  = new DelayedConductor(scheduler)
            {
                ActiveItem = screen
            };

            long screenFullyActivatedTime = 0; // Incl scopes
            long conductorActivationTime  = 0; // Only async

            var disposables = new CompositeDisposable();

            screen
            .WhenAnyValue(x => x.IsFullyActivated)
            .Do(_ => screenFullyActivatedTime = scheduler.Clock)
            .Subscribe()
            .DisposeWith(disposables);
            conductor
            .WhenAnyValue(x => x.IsActive)
            .Do(_ => conductorActivationTime = scheduler.Clock)
            .Subscribe()
            .DisposeWith(disposables);

            // WPF raises the ViewLoaded event.
            screenView.Loaded.OnNext(Unit.Default);
            // The Conductor's Conductor triggers ActivateAsync
            await((IActivate)conductor).ActivateAsync(CancellationToken.None);

            Assert.Equal(610, screenFullyActivatedTime);
            Assert.Equal(610, conductorActivationTime);
            Assert.Equal(610, conductor.WhenInitializedScopeStartTime);

            disposables.Dispose();
            screenView.Unloaded.OnNext(Unit.Default);
            screenView.Dispose();
        }