Attempt to change Deactivate(true) to Close()

Probably needs a bit more testing and verifying, but the tests pass
This commit is contained in:
Antony Male 2014-03-26 08:36:19 +00:00
parent 31c9844c47
commit 0f6994721a
13 changed files with 189 additions and 135 deletions

View File

@ -30,24 +30,31 @@ namespace Stylet
}
/// <summary>
/// Deactive the given item, optionally closing it as well
/// Deactive the given item
/// </summary>
/// <param name="item">Item to deactivate</param>
/// <param name="close">True to also close the item</param>
public override async void DeactivateItem(T item, bool close)
public override void DeactivateItem(T item)
{
if (item == null || !item.Equals(this.ActiveItem))
return;
if (close)
ScreenExtensions.TryDeactivate(this.ActiveItem);
}
/// <summary>
/// Close the given item
/// </summary>
/// <param name="item">Item to close</param>
public override async void CloseItem(T item)
{
if (item == null || !item.Equals(this.ActiveItem))
return;
if (await this.CanCloseItem(item))
{
if (await this.CanCloseItem(item))
this.ChangeActiveItem(default(T), close);
}
else
{
ScreenExtensions.TryDeactivate(this.ActiveItem, false);
this.ChangeActiveItem(default(T), true);
}
}
public override Task<bool> CanCloseAsync()

View File

@ -65,15 +65,18 @@ namespace Stylet
}
}
protected override void OnDeactivate(bool close)
protected override void OnDeactivate()
{
foreach (var item in this.items.OfType<IDeactivate>())
{
item.Deactivate(close);
item.Deactivate();
}
}
if (close)
items.Clear();
protected override void OnClose()
{
// We've already been deactivated by this point
items.Clear();
}
public override Task<bool> CanCloseAsync()
@ -97,26 +100,23 @@ namespace Stylet
}
/// <summary>
/// Deactive the given item, optionally closing it as well, and remove from the Items collection
/// Deactive the given item
/// </summary>
/// <param name="item">Item to deactivate</param>
/// <param name="close">True to close the item as well</param>
public override async void DeactivateItem(T item, bool close)
public override async void DeactivateItem(T item)
{
ScreenExtensions.TryDeactivate(item);
}
public async override void CloseItem(T item)
{
if (item == null)
return;
if (close)
if (await this.CanCloseItem(item))
{
if (await this.CanCloseItem(item))
{
ScreenExtensions.TryDeactivate(item, true);
this.items.Remove(item);
}
}
else
{
ScreenExtensions.TryDeactivate(item, false);
ScreenExtensions.TryClose(item);
this.items.Remove(item);
}
}

View File

@ -21,11 +21,16 @@ namespace Stylet
public abstract void ActivateItem(T item);
/// <summary>
/// Deactivate the given item, and optionally close it as well
/// Deactivate the given item
/// </summary>
/// <param name="item">Item to deactivate</param>
/// <param name="close">True to also close the item</param>
public abstract void DeactivateItem(T item, bool close);
public abstract void DeactivateItem(T item);
/// <summary>
/// Deactivate the given item
/// </summary>
/// <param name="item">Item to deactivate</param>
public abstract void CloseItem(T item);
/// <summary>
/// Ensure an item is ready to be activated

View File

@ -36,9 +36,12 @@ namespace Stylet
/// </summary>
protected virtual void ChangeActiveItem(T newItem, bool closePrevious)
{
ScreenExtensions.TryDeactivate(this.ActiveItem, closePrevious);
ScreenExtensions.TryDeactivate(this.ActiveItem);
if (closePrevious)
{
ScreenExtensions.TryClose(this.ActiveItem);
this.CleanUpAfterClose(this.ActiveItem);
}
newItem = this.EnsureItem(newItem);
@ -58,11 +61,19 @@ namespace Stylet
}
/// <summary>
/// When we're deactivate, also deactivate the ActiveItem
/// When we're deactivated, also deactivate the ActiveItem
/// </summary>
protected override void OnDeactivate(bool close)
protected override void OnDeactivate()
{
ScreenExtensions.TryDeactivate(this.ActiveItem, close);
ScreenExtensions.TryDeactivate(this.ActiveItem);
}
/// <summary>
/// When we're closed, also close the ActiveItem
/// </summary>
protected override void OnClose()
{
ScreenExtensions.TryClose(this.ActiveItem);
}
/// <summary>

View File

@ -80,28 +80,22 @@ namespace Stylet
}
/// <summary>
/// Deactive the given item, and choose another item to set as the ActiveItem, optionally closing this item
/// Deactive the given item, and choose another item to set as the ActiveItem
/// </summary>
/// <param name="item">Item to deactivate</param>
/// <param name="close">True to close the item as well</param>
public override async void DeactivateItem(T item, bool close)
public override async void DeactivateItem(T item)
{
ScreenExtensions.TryDeactivate(item);
}
public override async void CloseItem(T item)
{
if (item == null)
return;
if (close)
{
if (await this.CanCloseItem(item))
this.CloseItem(item);
}
else
{
ScreenExtensions.TryDeactivate(item, false);
}
}
if (!await this.CanCloseItem(item))
return;
private void CloseItem(T item)
{
if (item.Equals(this.ActiveItem))
{
var index = this.items.IndexOf(item);
@ -110,7 +104,7 @@ namespace Stylet
}
else
{
ScreenExtensions.TryDeactivate(item, true);
ScreenExtensions.TryClose(item);
}
this.items.Remove(item);
@ -136,19 +130,12 @@ namespace Stylet
return this.CanAllItemsCloseAsync(this.items);
}
protected override void OnDeactivate(bool close)
protected override void OnClose()
{
if (close)
{
foreach (var item in this.items.OfType<IDeactivate>())
item.Deactivate(true);
this.items.Clear();
}
else
{
base.OnDeactivate(false);
}
// We've already been deactivated by this point
foreach (var item in this.items.OfType<IClose>())
item.Close();
this.items.Clear();
}
protected override T EnsureItem(T newItem)

View File

@ -21,6 +21,8 @@ namespace Stylet
{
void ActivateItem(T item);
void DeactivateItem(T item, bool close);
void DeactivateItem(T item);
void CloseItem(T item);
}
}

View File

@ -26,7 +26,7 @@ namespace Stylet
public interface IDeactivate : IHasActivationState
{
void Deactivate(bool close);
void Deactivate();
event EventHandler<DeactivationEventArgs> Deactivated;
}
@ -40,17 +40,23 @@ namespace Stylet
object Parent { get; set; }
}
public interface IClose
public interface IDialogClose
{
void TryClose();
}
public interface IGuardClose : IClose
public interface IClose
{
void Close();
event EventHandler<CloseEventArgs> Closed;
}
public interface IGuardClose
{
Task<bool> CanCloseAsync();
}
public interface IScreen : IViewAware, IHaveDisplayName, IActivate, IDeactivate, IChild, IGuardClose
public interface IScreen : IViewAware, IHaveDisplayName, IActivate, IDeactivate, IChild, IDialogClose, IClose, IGuardClose
{
}
@ -61,6 +67,9 @@ namespace Stylet
public class DeactivationEventArgs : EventArgs
{
public bool WasClosed;
}
public class CloseEventArgs : EventArgs
{
}
}

View File

@ -84,24 +84,43 @@ namespace Stylet
public event EventHandler<DeactivationEventArgs> Deactivated;
void IDeactivate.Deactivate(bool close)
void IDeactivate.Deactivate()
{
if (!this.IsActive && !close)
if (!this.IsActive)
return;
this.IsActive = false;
this.OnDeactivate(close);
this.OnDeactivate();
var handler = this.Deactivated;
if (handler != null)
handler(this, new DeactivationEventArgs() { WasClosed = close });
if (close)
this.View = null;
handler(this, new DeactivationEventArgs());
}
protected virtual void OnDeactivate(bool close) { }
protected virtual void OnDeactivate() { }
#endregion
#region IClose
public event EventHandler<CloseEventArgs> Closed;
void IClose.Close()
{
// This will early-exit if it's already deactive
((IDeactivate)this).Deactivate();
this.View = null;
this.OnClose();
var handler = this.Closed;
if (handler != null)
handler(this, new CloseEventArgs());
}
protected virtual void OnClose() { }
#endregion
@ -145,12 +164,7 @@ namespace Stylet
#endregion
#region IGuardClose
public virtual Task<bool> CanCloseAsync()
{
return Task.FromResult(true);
}
#region IDialogClose
public void TryClose()
{
@ -158,5 +172,14 @@ namespace Stylet
}
#endregion
#region IGuardClose
public virtual Task<bool> CanCloseAsync()
{
return Task.FromResult(true);
}
#endregion
}
}

View File

@ -16,11 +16,18 @@ namespace Stylet
screenAsActivate.Activate();
}
public static void TryDeactivate(object screen, bool close)
public static void TryDeactivate(object screen)
{
var screenAsDeactivate = screen as IDeactivate;
if (screenAsDeactivate != null)
screenAsDeactivate.Deactivate(close);
screenAsDeactivate.Deactivate();
}
public static void TryClose(object screen)
{
var screenAsClose = screen as IClose;
if (screenAsClose != null)
screenAsClose.Close();
}
public static void ActivateWith(this IActivate child, IActivate parent)
@ -30,15 +37,21 @@ namespace Stylet
public static void DeactivateWith(this IDeactivate child, IDeactivate parent)
{
WeakEventManager<IDeactivate, DeactivationEventArgs>.AddHandler(parent, "Deactivated", (o, e) => child.Deactivate(e.WasClosed));
WeakEventManager<IDeactivate, DeactivationEventArgs>.AddHandler(parent, "Deactivated", (o, e) => child.Deactivate());
}
public static void CloseWith(this IClose child, IClose parent)
{
WeakEventManager<IClose, CloseEventArgs>.AddHandler(parent, "Closed", (o, e) => child.Close());
}
public static void ConductWith<TChild, TParent>(this TChild child, TParent parent)
where TChild : IActivate, IDeactivate
where TParent : IActivate, IDeactivate
where TChild : IActivate, IDeactivate, IClose
where TParent : IActivate, IDeactivate, IClose
{
child.ActivateWith(parent);
child.DeactivateWith(parent);
child.CloseWith(parent);
}
}
}

View File

@ -81,36 +81,33 @@ namespace Stylet
if (viewModelAsActivate != null)
viewModelAsActivate.Activate();
var viewModelAsDeactivate = viewModel as IDeactivate;
if (viewModelAsDeactivate != null)
var viewModelAsClose = viewModel as IClose;
if (viewModelAsClose != null)
{
window.Closed += this.Closed;
viewModelAsDeactivate.Deactivated += this.Deactivated;
window.Closed += this.WindowClosed;
viewModelAsClose.Closed += this.ViewModelClosed;
}
if (viewModel is IGuardClose)
window.Closing += this.Closing;
}
private void Closed(object sender, EventArgs e)
private void WindowClosed(object sender, EventArgs e)
{
var viewModelAsDeactivate = (IDeactivate)this.viewModel;
var viewModelAsClose = (IClose)this.viewModel;
this.window.Closed -= this.Closed;
this.window.Closed -= this.WindowClosed;
this.window.Closing -= this.Closing; // Not sure this is required
viewModelAsDeactivate.Deactivated -= this.Deactivated;
viewModelAsClose.Closed -= this.ViewModelClosed;
viewModelAsDeactivate.Deactivate(true);
viewModelAsClose.Close();
}
private void Deactivated(object sender, DeactivationEventArgs e)
private void ViewModelClosed(object sender, CloseEventArgs e)
{
if (!e.WasClosed)
return;
this.window.Closed -= this.Closed;
this.window.Closed -= this.WindowClosed;
this.window.Closing -= this.Closing;
((IDeactivate)this.window).Deactivated -= this.Deactivated;
((IClose)this.viewModel).Closed -= this.ViewModelClosed;
this.window.Close();
}

View File

@ -57,8 +57,8 @@ namespace StyletUnitTests
var screen = new Mock<IScreen>();
((IActivate)this.conductor).Activate();
this.conductor.ActivateItem(screen.Object);
((IDeactivate)this.conductor).Deactivate(false);
screen.Verify(x => x.Deactivate(false));
((IDeactivate)this.conductor).Deactivate();
screen.Verify(x => x.Deactivate());
}
[Test]
@ -67,8 +67,8 @@ namespace StyletUnitTests
var screen = new Mock<IScreen>();
((IActivate)this.conductor).Activate();
this.conductor.ActivateItem(screen.Object);
((IDeactivate)this.conductor).Deactivate(true);
screen.Verify(x => x.Deactivate(true));
((IClose)this.conductor).Close();
screen.Verify(x => x.Close());
Assert.AreEqual(0, this.conductor.Items.Count);
}
@ -129,8 +129,8 @@ namespace StyletUnitTests
{
var screen = new Mock<IScreen>();
this.conductor.ActivateItem(screen.Object);
this.conductor.DeactivateItem(screen.Object, false);
screen.Verify(x => x.Deactivate(false));
this.conductor.DeactivateItem(screen.Object);
screen.Verify(x => x.Deactivate());
Assert.That(this.conductor.Items, Is.EquivalentTo(new[] { screen.Object }));
}
@ -139,8 +139,8 @@ namespace StyletUnitTests
{
var screen = new Mock<IScreen>();
this.conductor.ActivateItem(screen.Object);
this.conductor.DeactivateItem(screen.Object, true);
screen.Verify(x => x.Deactivate(true), Times.Never);
this.conductor.CloseItem(screen.Object);
screen.Verify(x => x.Close(), Times.Never);
Assert.That(this.conductor.Items, Is.EquivalentTo(new[] { screen.Object }));
}
@ -150,8 +150,8 @@ namespace StyletUnitTests
var screen = new Mock<IScreen>();
screen.Setup(x => x.CanCloseAsync()).Returns(Task.FromResult(true));
this.conductor.ActivateItem(screen.Object);
this.conductor.DeactivateItem(screen.Object, true);
screen.Verify(x => x.Deactivate(true));
this.conductor.CloseItem(screen.Object);
screen.Verify(x => x.Close());
Assert.AreEqual(0, this.conductor.Items.Count);
}
}

View File

@ -48,7 +48,7 @@ namespace StyletUnitTests
this.conductor.ActivateItem(screen1.Object);
this.conductor.ActivateItem(screen2.Object);
screen1.Verify(x => x.Deactivate(false));
screen1.Verify(x => x.Deactivate());
screen2.Verify(x => x.Activate());
Assert.AreEqual(screen2.Object, this.conductor.ActiveItem);
@ -68,7 +68,7 @@ namespace StyletUnitTests
screen2.Setup(x => x.CanCloseAsync()).Returns(Task.FromResult(true));
this.conductor.DeactivateItem(screen2.Object, true);
this.conductor.CloseItem(screen2.Object);
Assert.AreEqual(screen1.Object, this.conductor.ActiveItem);
Assert.AreEqual(new[] { screen1.Object, screen3.Object }, this.conductor.Items);
}
@ -86,7 +86,7 @@ namespace StyletUnitTests
screen3.Setup(x => x.CanCloseAsync()).Returns(Task.FromResult(true));
this.conductor.DeactivateItem(screen3.Object, true);
this.conductor.CloseItem(screen3.Object);
Assert.AreEqual(screen2.Object, this.conductor.ActiveItem);
Assert.AreEqual(new[] { screen1.Object, screen2.Object }, this.conductor.Items);
}
@ -114,8 +114,8 @@ namespace StyletUnitTests
var screen = new Mock<IScreen>();
((IActivate)this.conductor).Activate();
this.conductor.ActivateItem(screen.Object);
((IDeactivate)this.conductor).Deactivate(false);
screen.Verify(x => x.Deactivate(false));
((IDeactivate)this.conductor).Deactivate();
screen.Verify(x => x.Deactivate());
}
[Test]
@ -124,8 +124,8 @@ namespace StyletUnitTests
var screen = new Mock<IScreen>();
((IActivate)this.conductor).Activate();
this.conductor.ActivateItem(screen.Object);
((IDeactivate)this.conductor).Deactivate(true);
screen.Verify(x => x.Deactivate(true));
((IClose)this.conductor).Close();
screen.Verify(x => x.Close());
Assert.AreEqual(0, this.conductor.Items.Count);
}
@ -186,8 +186,8 @@ namespace StyletUnitTests
{
var screen = new Mock<IScreen>();
this.conductor.ActivateItem(screen.Object);
this.conductor.DeactivateItem(screen.Object, false);
screen.Verify(x => x.Deactivate(false));
this.conductor.DeactivateItem(screen.Object);
screen.Verify(x => x.Deactivate());
Assert.That(this.conductor.Items, Is.EquivalentTo(new[] { screen.Object }));
}
@ -196,8 +196,8 @@ namespace StyletUnitTests
{
var screen = new Mock<IScreen>();
this.conductor.ActivateItem(screen.Object);
this.conductor.DeactivateItem(screen.Object, true);
screen.Verify(x => x.Deactivate(true), Times.Never);
this.conductor.CloseItem(screen.Object);
screen.Verify(x => x.Close(), Times.Never);
Assert.That(this.conductor.Items, Is.EquivalentTo(new[] { screen.Object }));
}
@ -207,8 +207,8 @@ namespace StyletUnitTests
var screen = new Mock<IScreen>();
screen.Setup(x => x.CanCloseAsync()).Returns(Task.FromResult(true));
this.conductor.ActivateItem(screen.Object);
this.conductor.DeactivateItem(screen.Object, true);
screen.Verify(x => x.Deactivate(true));
this.conductor.CloseItem(screen.Object);
screen.Verify(x => x.Close());
Assert.AreEqual(0, this.conductor.Items.Count);
}
}

View File

@ -69,8 +69,8 @@ namespace StyletUnitTests
((IActivate)this.conductor).Activate();
var screen = new Mock<IScreen>();
this.conductor.ActivateItem(screen.Object);
((IDeactivate)this.conductor).Deactivate(false);
screen.Verify(x => x.Deactivate(false));
((IDeactivate)this.conductor).Deactivate();
screen.Verify(x => x.Deactivate());
}
[Test]
@ -82,7 +82,7 @@ namespace StyletUnitTests
this.conductor.ActivateItem(screen1.Object);
screen1.Setup(x => x.CanCloseAsync()).Returns(Task.FromResult(true));
this.conductor.ActivateItem(screen2.Object);
screen1.Verify(x => x.Deactivate(true));
screen1.Verify(x => x.Close());
}
[Test]
@ -95,7 +95,7 @@ namespace StyletUnitTests
screen1.Setup(x => x.CanCloseAsync()).Returns(Task.FromResult(false));
this.conductor.ActivateItem(screen2.Object);
screen1.Verify(x => x.Deactivate(true), Times.Never);
screen1.Verify(x => x.Close(), Times.Never);
screen2.Verify(x => x.Activate(), Times.Never);
}
@ -107,7 +107,7 @@ namespace StyletUnitTests
this.conductor.ActivateItem(screen.Object);
this.conductor.ActivateItem(screen.Object);
screen.Verify(x => x.Activate(), Times.Exactly(2));
screen.Verify(x => x.Deactivate(true), Times.Never);
screen.Verify(x => x.Close(), Times.Never);
}
[Test]
@ -117,9 +117,9 @@ namespace StyletUnitTests
var screen2 = new Mock<IScreen>();
((IActivate)this.conductor).Activate();
this.conductor.ActivateItem(screen1.Object);
this.conductor.DeactivateItem(screen2.Object, true);
this.conductor.CloseItem(screen2.Object);
screen1.Verify(x => x.Deactivate(true), Times.Never);
screen1.Verify(x => x.Close(), Times.Never);
screen2.Verify(x => x.Activate(), Times.Never);
}
@ -129,9 +129,9 @@ namespace StyletUnitTests
var screen = new Mock<IScreen>();
((IActivate)this.conductor).Activate();
this.conductor.ActivateItem(screen.Object);
this.conductor.DeactivateItem(screen.Object, false);
this.conductor.DeactivateItem(screen.Object);
screen.Verify(x => x.Deactivate(false));
screen.Verify(x => x.Deactivate());
Assert.AreEqual(this.conductor.ActiveItem, screen.Object);
}
@ -150,7 +150,7 @@ namespace StyletUnitTests
screen.Setup(x => x.CanCloseAsync()).Returns(Task.FromResult(true));
screen.Setup(x => x.Parent).Returns(this.conductor);
this.conductor.ActivateItem(screen.Object);
this.conductor.DeactivateItem(screen.Object, true);
this.conductor.CloseItem(screen.Object);
screen.VerifySet(x => x.Parent = null);
}