diff --git a/src/Caliburn.Micro.Core.Tests/ConductorWithCollectionOneActiveTests.cs b/src/Caliburn.Micro.Core.Tests/ConductorWithCollectionOneActiveTests.cs index 6e3371cd0..a176a56a3 100644 --- a/src/Caliburn.Micro.Core.Tests/ConductorWithCollectionOneActiveTests.cs +++ b/src/Caliburn.Micro.Core.Tests/ConductorWithCollectionOneActiveTests.cs @@ -24,6 +24,45 @@ protected override async Task OnDeactivateAsync(bool close, CancellationToken ca } } + private class AsyncActivationScreen : Screen + { + private readonly bool _simulateAsyncOnActivate; + + private readonly bool _simulateAsyncOnDeactivate; + + private readonly TimeSpan _simulateAsyncTaskDuration; + + public AsyncActivationScreen(bool simulateAsyncOnActivate, bool simulateAsyncOnDeactivate, + TimeSpan simulateAsyncTaskDuration) + { + _simulateAsyncOnActivate = simulateAsyncOnActivate; + _simulateAsyncOnDeactivate = simulateAsyncOnDeactivate; + _simulateAsyncTaskDuration = simulateAsyncTaskDuration; + } + + protected override async Task OnActivateAsync(CancellationToken cancellationToken) + { + await base.OnActivateAsync(cancellationToken); + + if (_simulateAsyncOnActivate) + { + // Task.Delay doesn't run within captured context + await Task.Delay(_simulateAsyncTaskDuration, cancellationToken); + } + } + + protected override async Task OnDeactivateAsync(bool close, CancellationToken cancellationToken) + { + if (_simulateAsyncOnDeactivate) + { + // Task.Delay doesn't run within captured context + await Task.Delay(_simulateAsyncTaskDuration, cancellationToken); + } + + await base.OnDeactivateAsync(close, cancellationToken); + } + } + [Fact] public void AddedItemAppearsInChildren() { @@ -150,5 +189,33 @@ public void ParentItemIsUnsetOnReplaceConductedItem() Assert.NotEqual(conductor, conducted.Parent); Assert.Equal(conductor, conducted2.Parent); } + + [Fact] + public async Task ActiveItemSetterShouldSetThePropertySynchronouslyWhenOnActivateIsLongRunningTask() + { + var conductor = new Conductor.Collection.OneActive(); + var conducted = new AsyncActivationScreen(true, false, TimeSpan.FromSeconds(1)); + conductor.Items.Add(conducted); + await ((IActivate)conductor).ActivateAsync(CancellationToken.None); + conductor.ActiveItem = conducted; + Assert.NotNull(conductor.ActiveItem); + Assert.Equal(conducted, conductor.ActiveItem); + } + + [Fact] + public async Task ActiveItemSetterShouldSetThePropertySynchronouslyWhenOnDeactivateIsLongRunningTask() + { + var conductor = new Conductor.Collection.OneActive(); + var conducted1 = new AsyncActivationScreen(false, true, TimeSpan.FromSeconds(1)); + conductor.Items.Add(conducted1); + var conducted2 = new Screen(); + conductor.Items.Add(conducted2); + await((IActivate)conductor).ActivateAsync(CancellationToken.None); + conductor.ActiveItem = conducted1; + conductor.ActiveItem = conducted2; + Assert.NotNull(conductor.ActiveItem); + Assert.NotEqual(conducted1, conductor.ActiveItem); + Assert.Equal(conducted2, conductor.ActiveItem); + } } } diff --git a/src/Caliburn.Micro.Core/ConductorBaseWithActiveItem.cs b/src/Caliburn.Micro.Core/ConductorBaseWithActiveItem.cs index 1249eac40..e2005495f 100644 --- a/src/Caliburn.Micro.Core/ConductorBaseWithActiveItem.cs +++ b/src/Caliburn.Micro.Core/ConductorBaseWithActiveItem.cs @@ -39,12 +39,13 @@ object IHaveActiveItem.ActiveItem /// A task that represents the asynchronous operation. protected virtual async Task ChangeActiveItemAsync(T newItem, bool closePrevious, CancellationToken cancellationToken) { - await ScreenExtensions.TryDeactivateAsync(_activeItem, closePrevious, cancellationToken); newItem = EnsureItem(newItem); _activeItem = newItem; NotifyOfPropertyChange(nameof(ActiveItem)); + await ScreenExtensions.TryDeactivateAsync(_activeItem, closePrevious, cancellationToken); + if (IsActive) await ScreenExtensions.TryActivateAsync(newItem, cancellationToken);