When removing ConductorOneActive's ActiveItem, don't Close then Deactivate

Closing and then Deactivating causes the ActiveItem to be reactivated, in order
to deactivate it. Not good.

Fixes #27
This commit is contained in:
Antony Male 2017-05-15 13:04:07 +01:00
parent 2c2466e611
commit e4941c1c66
2 changed files with 72 additions and 4 deletions

View File

@ -50,20 +50,26 @@ namespace Stylet
break;
case NotifyCollectionChangedAction.Remove:
this.CloseAndCleanUp(e.OldItems, this.DisposeChildren);
// ActiveItemMayHaveBeenRemovedFromItems may deactivate the ActiveItem; CloseAndCleanUp may close it.
// Call the methods in this order to avoid closing then deactivating (which causes reactivation)
this.ActiveItemMayHaveBeenRemovedFromItems();
this.CloseAndCleanUp(e.OldItems, this.DisposeChildren);
break;
case NotifyCollectionChangedAction.Replace:
this.SetParentAndSetActive(e.NewItems, false);
this.CloseAndCleanUp(e.OldItems, this.DisposeChildren);
// ActiveItemMayHaveBeenRemovedFromItems may deactivate the ActiveItem; CloseAndCleanUp may close it.
// Call the methods in this order to avoid closing then deactivating (which causes reactivation)
this.ActiveItemMayHaveBeenRemovedFromItems();
this.CloseAndCleanUp(e.OldItems, this.DisposeChildren);
this.SetParentAndSetActive(e.NewItems, false);
break;
case NotifyCollectionChangedAction.Reset:
// ActiveItemMayHaveBeenRemovedFromItems may deactivate the ActiveItem; CloseAndCleanUp may close it.
// Call the methods in this order to avoid closing then deactivating (which causes reactivation)
this.ActiveItemMayHaveBeenRemovedFromItems();
this.CloseAndCleanUp(this.itemsBeforeReset.Except(this.items), this.DisposeChildren);
this.SetParentAndSetActive(this.items.Except(this.itemsBeforeReset), false);
this.ActiveItemMayHaveBeenRemovedFromItems();
this.itemsBeforeReset = null;
break;
}

View File

@ -369,6 +369,68 @@ namespace StyletUnitTests
screen2.Verify(x => x.Close());
screen2.Verify(x => x.Dispose());
}
[Test]
public void ClosingDoesNotCloseThenDeactivateActiveItem()
{
// If it calls Close then Deactivate, this causes OnInitialActivate to be called again (in order to
// activate the screen before deactivating it again).
var screen = new Mock<IMyScreen>();
this.conductor.ActivateItem(screen.Object);
screen.ResetCalls();
int sequence = 0;
screen.Setup(x => x.Deactivate()).Callback(() => Assert.AreEqual(0, sequence++));
screen.Setup(x => x.Close()).Callback(() => Assert.AreEqual(1, sequence++));
((IScreenState)this.conductor).Close();
Assert.AreEqual(2, sequence);
}
[Test]
public void ReplacingActiveItemDoesNotCloseThenDeactivate()
{
// If it calls Close then Deactivate, this causes OnInitialActivate to be called again (in order to
// activate the screen before deactivating it again).
var screen1 = new Mock<IMyScreen>();
var screen2 = new Mock<IMyScreen>();
this.conductor.ActivateItem(screen1.Object);
screen1.ResetCalls();
int sequence = 0;
screen1.Setup(x => x.Deactivate()).Callback(() => Assert.AreEqual(0, sequence++));
screen1.Setup(x => x.Close()).Callback(() => Assert.AreEqual(1, sequence++));
this.conductor.Items[0] = screen2.Object;
Assert.AreEqual(2, sequence);
}
[Test]
public void RemovingActiveItemDoesNotCloseThenDeactivate()
{
// If it calls Close then Deactivate, this causes OnInitialActivate to be called again (in order to
// activate the screen before deactivating it again).
var screen1 = new Mock<IMyScreen>();
var screen2 = new Mock<IMyScreen>();
this.conductor.ActivateItem(screen1.Object);
screen1.ResetCalls();
int sequence = 0;
screen1.Setup(x => x.Deactivate()).Callback(() => Assert.AreEqual(0, sequence++));
screen1.Setup(x => x.Close()).Callback(() => Assert.AreEqual(1, sequence++));
this.conductor.Items.RemoveAt(0);
Assert.AreEqual(2, sequence);
}
}
}