Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ClosingBehavior api to Window #14621

Merged
merged 1 commit into from
Feb 18, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 62 additions & 17 deletions src/Avalonia.Controls/Window.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,25 @@ public enum SystemDecorations
Full = 2
}

/// <summary>
/// Describes how the <see cref="Window.Closing"/> event behaves in the presence of child windows.
/// </summary>
public enum WindowClosingBehavior
{
/// <summary>
/// When the owner window is closed, the child windows' <see cref="Window.Closing"/> event
/// will be raised, followed by the owner window's <see cref="Window.Closing"/> events. A child
/// canceling the close will result in the owner Window's close being cancelled.
/// </summary>
OwnerAndChildWindows,

/// <summary>
/// When the owner window is closed, only the owner window's <see cref="Window.Closing"/> event
/// will be raised. This behavior is the same as WPF's.
/// </summary>
OwnerWindowOnly,
Comment on lines +70 to +81
Copy link
Contributor

@jp2masa jp2masa Feb 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the Closing and Closed events are a bit mixed in the XML comments, at least for OwnerAndChildWindows. According to the PR description, it doesn't raise the Closing event for child windows. Is that right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When set to OwnerAndChildWindows which is the default and is the current behavior as of master, Closing will be raised on all child windows before being raised on the parent. Closed event is raised at the point that it's decided the window will be closed, i.e. all Closing handlers that were raised didn't cancel Closing event.

}

/// <summary>
/// A top-level window.
/// </summary>
Expand Down Expand Up @@ -127,6 +146,12 @@ public class Window : WindowBase, IFocusScope, ILayoutRoot
public static readonly StyledProperty<bool> ShowInTaskbarProperty =
AvaloniaProperty.Register<Window, bool>(nameof(ShowInTaskbar), true);

/// <summary>
/// Defines the <see cref="ClosingBehavior"/> property.
/// </summary>
public static readonly StyledProperty<WindowClosingBehavior> ClosingBehaviorProperty =
AvaloniaProperty.Register<Window, WindowClosingBehavior>(nameof(ClosingBehavior));

/// <summary>
/// Represents the current window state (normal, minimized, maximized)
/// </summary>
Expand Down Expand Up @@ -347,6 +372,16 @@ public bool ShowInTaskbar
set => SetValue(ShowInTaskbarProperty, value);
}

/// <summary>
/// Gets or sets a value indicating how the <see cref="Closing"/> event behaves in the presence
/// of child windows.
/// </summary>
public WindowClosingBehavior ClosingBehavior
{
get => GetValue(ClosingBehaviorProperty);
set => SetValue(ClosingBehaviorProperty, value);
}

/// <summary>
/// Gets or sets the minimized/maximized state of the window.
/// </summary>
Expand Down Expand Up @@ -487,31 +522,41 @@ private void CloseInternal()

private bool ShouldCancelClose(WindowClosingEventArgs args)
{
bool canClose = true;

if (_children.Count > 0)
switch (ClosingBehavior)
{
var childArgs = args.CloseReason == WindowCloseReason.WindowClosing ?
new WindowClosingEventArgs(WindowCloseReason.OwnerWindowClosing, args.IsProgrammatic) :
args;
case WindowClosingBehavior.OwnerAndChildWindows:
bool canClose = true;

foreach (var (child, _) in _children.ToArray())
{
if (child.ShouldCancelClose(childArgs))
if (_children.Count > 0)
{
canClose = false;
var childArgs = args.CloseReason == WindowCloseReason.WindowClosing ?
new WindowClosingEventArgs(WindowCloseReason.OwnerWindowClosing, args.IsProgrammatic) :
args;

foreach (var (child, _) in _children.ToArray())
{
if (child.ShouldCancelClose(childArgs))
{
canClose = false;
}
}
}
}
}

if (canClose)
{
OnClosing(args);
if (canClose)
{
OnClosing(args);

return args.Cancel;
return args.Cancel;
}

return true;
case WindowClosingBehavior.OwnerWindowOnly:
OnClosing(args);

return args.Cancel;
}

return true;
return false;
}

private void HandleWindowStateChanged(WindowState state)
Expand Down