Skip to content

Commit

Permalink
Merge pull request #6198 from AvaloniaUI/fixes/6190-check-parent-wind…
Browse files Browse the repository at this point in the history
…ow-on-show

Validate parent/owner when showing windows.
  • Loading branch information
maxkatz6 authored and danwalmsley committed Aug 16, 2021
1 parent 442e845 commit 9c2da62
Show file tree
Hide file tree
Showing 2 changed files with 166 additions and 9 deletions.
39 changes: 37 additions & 2 deletions src/Avalonia.Controls/Window.cs
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,14 @@ public override void Hide()
owner.RemoveChild(this);
}

if (_children.Count > 0)
{
foreach (var child in _children.ToArray())
{
child.child.Hide();
}
}

Owner = null;

PlatformImpl?.Hide();
Expand Down Expand Up @@ -635,6 +643,22 @@ private void ShowCore(Window parent)
throw new InvalidOperationException("Cannot re-show a closed window.");
}

if (parent != null)
{
if (parent.PlatformImpl == null)
{
throw new InvalidOperationException("Cannot show a window with a closed parent.");
}
else if (parent == this)
{
throw new InvalidOperationException("A Window cannot be its own parent.");
}
else if (!parent.IsVisible)
{
throw new InvalidOperationException("Cannot show window with non-visible parent.");
}
}

if (IsVisible)
{
return;
Expand Down Expand Up @@ -708,11 +732,22 @@ public Task<TResult> ShowDialog<TResult>(Window owner)
{
throw new ArgumentNullException(nameof(owner));
}

if (IsVisible)
else if (owner.PlatformImpl == null)
{
throw new InvalidOperationException("Cannot show a window with a closed owner.");
}
else if (owner == this)
{
throw new InvalidOperationException("A Window cannot be its own owner.");
}
else if (IsVisible)
{
throw new InvalidOperationException("The window is already being shown.");
}
else if (!owner.IsVisible)
{
throw new InvalidOperationException("Cannot show window with non-visible parent.");
}

RaiseEvent(new RoutedEventArgs(WindowOpenedEvent));

Expand Down
136 changes: 129 additions & 7 deletions tests/Avalonia.Controls.UnitTests/WindowTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -279,10 +279,11 @@ public void ShowDialog_Should_Start_Renderer()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var parent = Mock.Of<Window>();
var parent = new Window();
var renderer = new Mock<IRenderer>();
var target = new Window(CreateImpl(renderer));

parent.Show();
target.ShowDialog<object>(parent);

renderer.Verify(x => x.Start(), Times.Once);
Expand All @@ -294,10 +295,11 @@ public void ShowDialog_Should_Raise_Opened()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var parent = Mock.Of<Window>();
var parent = new Window();
var target = new Window();
var raised = false;

parent.Show();
target.Opened += (s, e) => raised = true;

target.ShowDialog<object>(parent);
Expand Down Expand Up @@ -326,14 +328,15 @@ public async Task ShowDialog_With_ValueType_Returns_Default_When_Closed()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var parent = new Mock<Window>();
var parent = new Window();
var windowImpl = new Mock<IWindowImpl>();
windowImpl.SetupProperty(x => x.Closed);
windowImpl.Setup(x => x.DesktopScaling).Returns(1);
windowImpl.Setup(x => x.RenderScaling).Returns(1);

parent.Show();
var target = new Window(windowImpl.Object);
var task = target.ShowDialog<bool>(parent.Object);
var task = target.ShowDialog<bool>(parent);

windowImpl.Object.Closed();

Expand Down Expand Up @@ -366,27 +369,145 @@ public async Task Calling_ShowDialog_On_Closed_Window_Should_Throw()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var parent = new Mock<Window>();
var parent = new Window();
var windowImpl = new Mock<IWindowImpl>();
windowImpl.SetupProperty(x => x.Closed);
windowImpl.Setup(x => x.DesktopScaling).Returns(1);
windowImpl.Setup(x => x.RenderScaling).Returns(1);

parent.Show();

var target = new Window(windowImpl.Object);
var task = target.ShowDialog<bool>(parent.Object);
var task = target.ShowDialog<bool>(parent);

windowImpl.Object.Closed();
await task;

var openedRaised = false;
target.Opened += (s, e) => openedRaised = true;

var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => target.ShowDialog<bool>(parent.Object));
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => target.ShowDialog<bool>(parent));
Assert.Equal("Cannot re-show a closed window.", ex.Message);
Assert.False(openedRaised);
}
}

[Fact]
public void Calling_Show_With_Closed_Parent_Window_Should_Throw()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var parent = new Window();
var target = new Window();

parent.Close();

var ex = Assert.Throws<InvalidOperationException>(() => target.Show(parent));
Assert.Equal("Cannot show a window with a closed parent.", ex.Message);
}
}

[Fact]
public async Task Calling_ShowDialog_With_Closed_Parent_Window_Should_Throw()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var parent = new Window();
var target = new Window();

parent.Close();

var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => target.ShowDialog(parent));
Assert.Equal("Cannot show a window with a closed owner.", ex.Message);
}
}

[Fact]
public void Calling_Show_With_Invisible_Parent_Window_Should_Throw()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var parent = new Window();
var target = new Window();

var ex = Assert.Throws<InvalidOperationException>(() => target.Show(parent));
Assert.Equal("Cannot show window with non-visible parent.", ex.Message);
}
}

[Fact]
public async Task Calling_ShowDialog_With_Invisible_Parent_Window_Should_Throw()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var parent = new Window();
var target = new Window();

var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => target.ShowDialog(parent));
Assert.Equal("Cannot show window with non-visible parent.", ex.Message);
}
}

[Fact]
public void Calling_Show_With_Self_As_Parent_Window_Should_Throw()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var target = new Window();

var ex = Assert.Throws<InvalidOperationException>(() => target.Show(target));
Assert.Equal("A Window cannot be its own parent.", ex.Message);
}
}

[Fact]
public async Task Calling_ShowDialog_With_Self_As_Parent_Window_Should_Throw()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var target = new Window();

var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => target.ShowDialog(target));
Assert.Equal("A Window cannot be its own owner.", ex.Message);
}
}

[Fact]
public void Hiding_Parent_Window_Should_Close_Children()
{
using (UnitTestApplication.Start(TestServices.MockWindowingPlatform))
{
var parent = new Window();
var child = new Window();

parent.Show();
child.Show(parent);

parent.Hide();

Assert.False(parent.IsVisible);
Assert.False(child.IsVisible);
}
}

[Fact]
public void Hiding_Parent_Window_Should_Close_Dialog_Children()
{
using (UnitTestApplication.Start(TestServices.MockWindowingPlatform))
{
var parent = new Window();
var child = new Window();

parent.Show();
child.ShowDialog(parent);

parent.Hide();

Assert.False(parent.IsVisible);
Assert.False(child.IsVisible);
}
}

[Fact]
public void Window_Should_Be_Centered_When_WindowStartupLocation_Is_CenterScreen()
{
Expand Down Expand Up @@ -686,6 +807,7 @@ public class DialogSizingTests : SizingTests
protected override void Show(Window window)
{
var owner = new Window();
owner.Show();
window.ShowDialog(owner);
}
}
Expand Down

0 comments on commit 9c2da62

Please sign in to comment.