diff --git a/source/Components/AvalonDock/Controls/LayoutAnchorableFloatingWindowControl.cs b/source/Components/AvalonDock/Controls/LayoutAnchorableFloatingWindowControl.cs
index b9d6e0a4..dde5c521 100644
--- a/source/Components/AvalonDock/Controls/LayoutAnchorableFloatingWindowControl.cs
+++ b/source/Components/AvalonDock/Controls/LayoutAnchorableFloatingWindowControl.cs
@@ -208,20 +208,14 @@ protected override void OnInitialized(EventArgs e)
///
protected override void OnClosed(EventArgs e)
{
- var root = Model.Root;
- if (root != null)
- {
- if (root is LayoutRoot layoutRoot) layoutRoot.Updated -= OnRootUpdated;
- root.Manager.RemoveFloatingWindow(this);
- root.CollectGarbage();
- }
+ if (Model.Root is LayoutRoot layoutRoot) layoutRoot.Updated -= OnRootUpdated;
+
if (_overlayWindow != null)
{
_overlayWindow.Close();
_overlayWindow = null;
}
base.OnClosed(e);
- if (!CloseInitiatedByUser) root?.FloatingWindows.Remove(_model);
// We have to clear binding instead of creating a new empty binding.
BindingOperations.ClearBinding(_model, VisibilityProperty);
@@ -235,11 +229,143 @@ protected override void OnClosed(EventArgs e)
}
///
- protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
+ protected override void OnClosing(CancelEventArgs e)
+ {
+ // Allow base Window class and attached Closing event handlers to potentially cancel first.
+ base.OnClosing(e);
+
+ if (e.Cancel) // If already cancelled by base or others, do nothing.
+ return;
+
+ // If closed programmatically by AvalonDock (e.g., dragging last anchorable out), skip user checks.
+ if (!CloseInitiatedByUser)
+ return;
+
+ // Handle user-initiated close (Taskbar, Alt+F4, Window's 'X' button).
+ var manager = Model?.Root?.Manager;
+ if (manager == null)
+ return;
+
+ var anchorablesToProcess = Model.Descendents().OfType().ToArray();
+
+ // Phase 1: Validate if ALL anchorables can be processed (closed or hidden)
+ // This checks properties, internal events, manager events, and command CanExecute
+ // before deciding if the window closing can proceed.
+ // Priority: Try Close Path
+ // - Check internal Closing
+ // - Check manager AnchorableClosing event
+ // - Check command CanExecute
+ // Fallback: Try Hide Path
+ // - Check internal Hiding
+ // - Check manager AnchorableHiding event
+ // - Check command CanExecute
+ // Fallback 2: Cannot Close AND Cannot Hide
+ var cancelAll = anchorablesToProcess.Any(anch =>
+ {
+ var closeCommand = manager.GetLayoutItemFromModel(anch)?.CloseCommand;
+ var hideCommand = (manager.GetLayoutItemFromModel(anch) as LayoutAnchorableItem)?.HideCommand;
+ return anch.CanClose && (!anch.TestCanClose() || !ManagerTestCanClose(anch) || closeCommand?.CanExecute(null) is false) ||
+ anch.CanHide && (!anch.TestCanHide() || !ManagerTestCanHide(anch) || hideCommand?.CanExecute(null) is false) ||
+ !anch.CanClose && !anch.CanHide;
+ });
+
+ if (cancelAll)
+ {
+ e.Cancel = true;
+ return;
+ }
+
+ // Phase 2: Execute actions based on the validated priority (Close > Hide)
+ // We use the compromise: execute user command if provided, otherwise execute default logic directly.
+ var wasAnyContentHidden = false;
+ foreach (var anch in anchorablesToProcess.ToList()) // Use ToList() as actions might modify the underlying collection.
+ {
+ var layoutItem = manager.GetLayoutItemFromModel(anch) as LayoutAnchorableItem;
+ bool useDefaultLogic = layoutItem == null; // Should not happen, but safe default
+
+ if (anch.CanClose) // Priority Action: Close
+ {
+ if (!useDefaultLogic) useDefaultLogic = layoutItem.IsDefaultCloseCommand;
+
+ if (!useDefaultLogic)
+ {
+ // User Custom Command Path
+ layoutItem.CloseCommand?.Execute(null);
+ }
+ else
+ {
+ // Default AvalonDock Logic Path
+ anch.CloseInternal(); // Does NOT raise manager's Closing/Closed events again
+ if (layoutItem?.IsViewExists() == true)
+ manager.InternalRemoveLogicalChild(layoutItem.View);
+ manager.RaiseAnchorableClosed(anch); // Raise final event
+ }
+ }
+ else if (anch.CanHide) // Fallback Action: Hide
+ {
+ if (!useDefaultLogic) useDefaultLogic = layoutItem.IsDefaultHideCommand;
+
+ if (!useDefaultLogic)
+ {
+ // User Custom Command Path
+ layoutItem.HideCommand?.Execute(null);
+ }
+ else
+ {
+ // Default AvalonDock Logic Path
+ // Use 'false' to bypass internal cancel checks already done in Phase 1.
+ if (anch.HideAnchorable(false)) // Does NOT raise manager's Hiding/Hidden events again
+ {
+ // View removal for Hide is typically handled by DockingManager logic or CollectGarbage.
+ manager.RaiseAnchorableHidden(anch); // Raise final event
+ }
+ }
+
+ wasAnyContentHidden = true;
+ }
+ // If neither CanClose nor CanHide, do nothing (already validated in Phase 1).
+ }
+
+ if (wasAnyContentHidden)
+ {
+ // Close the window only if all anchorables were closed
+ e.Cancel = true;
+ }
+ }
+
+ ///
+ /// Helper method to check DockingManager's AnchorableClosing event for cancellation.
+ ///
+ private bool ManagerTestCanClose(LayoutAnchorable anch)
{
- var canHide = HideWindowCommand.CanExecute(null);
- if (CloseInitiatedByUser && !KeepContentVisibleOnClose && !canHide) e.Cancel = true;
- base.OnClosing(e);
+ var ancClosingArgs = new AnchorableClosingEventArgs(anch);
+ Model?.Root?.Manager.RaiseAnchorableClosing(ancClosingArgs);
+ return !ancClosingArgs.Cancel;
+ }
+
+ ///
+ /// Helper method to check DockingManager's AnchorableHiding event for cancellation,
+ /// including the CloseInsteadOfHide request when CanClose is false.
+ ///
+ private bool ManagerTestCanHide(LayoutAnchorable anch)
+ {
+ var hidingArgs = new AnchorableHidingEventArgs(anch);
+ Model?.Root?.Manager.RaiseAnchorableHiding(hidingArgs);
+
+ // If the Hiding event itself was cancelled, prevent the action.
+ if (hidingArgs.Cancel)
+ return false;
+
+ // If Hiding requests Close instead, but CanClose is false (which it must be
+ // to reach this point), then the requested action cannot be performed, so cancel.
+ if (hidingArgs.CloseInsteadOfHide)
+ {
+ // Log warning maybe? "CloseInsteadOfHide requested for an anchorable where CanClose=false."
+ return false;
+ }
+
+ // Hiding was not cancelled and not replaced by an impossible Close action.
+ return true;
}
///
diff --git a/source/Components/AvalonDock/Controls/LayoutAnchorableItem.cs b/source/Components/AvalonDock/Controls/LayoutAnchorableItem.cs
index 67e5f0dd..afb6fa8d 100644
--- a/source/Components/AvalonDock/Controls/LayoutAnchorableItem.cs
+++ b/source/Components/AvalonDock/Controls/LayoutAnchorableItem.cs
@@ -69,6 +69,9 @@ public ICommand HideCommand
set => SetValue(HideCommandProperty, value);
}
+ /// Gets a value indicating whether the is the default value.
+ internal bool IsDefaultHideCommand => HideCommand == _defaultHideCommand;
+
/// Handles changes to the property.
private static void OnHideCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) => ((LayoutAnchorableItem)d).OnHideCommandChanged(e);
diff --git a/source/Components/AvalonDock/Controls/LayoutDocumentFloatingWindowControl.cs b/source/Components/AvalonDock/Controls/LayoutDocumentFloatingWindowControl.cs
index e75d1aa6..7274b0fd 100644
--- a/source/Components/AvalonDock/Controls/LayoutDocumentFloatingWindowControl.cs
+++ b/source/Components/AvalonDock/Controls/LayoutDocumentFloatingWindowControl.cs
@@ -69,6 +69,28 @@ internal LayoutDocumentFloatingWindowControl(LayoutDocumentFloatingWindow model)
#endregion Constructors
+ #region Public Methods
+
+ ///
+ public override void EnableBindings()
+ {
+ _model.PropertyChanged += Model_PropertyChanged;
+ _model.IsVisibleChanged += _model_IsVisibleChanged;
+
+ base.EnableBindings();
+ }
+
+ ///
+ public override void DisableBindings()
+ {
+ _model.PropertyChanged -= Model_PropertyChanged;
+ _model.IsVisibleChanged -= _model_IsVisibleChanged;
+
+ base.DisableBindings();
+ }
+
+ #endregion
+
#region Overrides
///
@@ -105,16 +127,10 @@ protected override void OnInitialized(EventArgs e)
base.OnInitialized(e);
var manager = _model.Root.Manager;
Content = manager.CreateUIElementForModel(_model.RootPanel);
- // TODO IsVisibleChanged
+ EnableBindings();
//SetBinding(SingleContentLayoutItemProperty, new Binding("Model.SinglePane.SelectedContent") { Source = this, Converter = new LayoutItemFromLayoutModelConverter() });
_model.RootPanel.ChildrenCollectionChanged += RootPanelOnChildrenCollectionChanged;
}
-
- private void Model_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
- {
- if (e.PropertyName == nameof(LayoutDocumentFloatingWindow.RootPanel) && _model.RootPanel == null) InternalClose();
- }
-
///
protected override IntPtr FilterMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
@@ -150,17 +166,6 @@ protected override IntPtr FilterMessage(IntPtr hwnd, int msg, IntPtr wParam, Int
}
}
break;
-
- case Win32Helper.WM_CLOSE:
- if (CloseInitiatedByUser)
- {
- // We want to force the window to go through our standard logic for closing.
- // So, if the window close is initiated outside of our code (such as from the taskbar),
- // we cancel that close and trigger our close logic instead.
- this.CloseWindowCommand.Execute(null);
- handled = true;
- }
- break;
}
return base.FilterMessage(hwnd, msg, wParam, lParam, ref handled);
}
@@ -168,20 +173,12 @@ protected override IntPtr FilterMessage(IntPtr hwnd, int msg, IntPtr wParam, Int
///
protected override void OnClosed(EventArgs e)
{
- var root = Model.Root;
- // MK sometimes root is null, prevent crash, or should it always be set??
- if (root != null)
- {
- root.Manager.RemoveFloatingWindow(this);
- root.CollectGarbage();
- }
if (_overlayWindow != null)
{
_overlayWindow.Close();
_overlayWindow = null;
}
base.OnClosed(e);
- if (!CloseInitiatedByUser) root?.FloatingWindows.Remove(_model);
_model.PropertyChanged -= Model_PropertyChanged;
}
@@ -189,6 +186,28 @@ protected override void OnClosed(EventArgs e)
#region Private Methods
+ private void _model_IsVisibleChanged(object sender, EventArgs e)
+ {
+ if (!IsVisible && _model.IsVisible) Show();
+ }
+
+ private void Model_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
+ {
+ switch (e.PropertyName)
+ {
+ case nameof(LayoutDocumentFloatingWindow.RootPanel):
+ if (_model.RootPanel == null) InternalClose();
+ break;
+
+ case nameof(LayoutDocumentFloatingWindow.IsVisible):
+ if (_model.IsVisible != IsVisible)
+ {
+ Visibility = _model.IsVisible ? Visibility.Visible : Visibility.Hidden;
+ }
+ break;
+ }
+ }
+
private void RootPanelOnChildrenCollectionChanged(object sender, EventArgs e)
{
if (_model.RootPanel == null || _model.RootPanel.Children.Count == 0) InternalClose();
@@ -208,15 +227,192 @@ private bool OpenContextMenu()
///
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
- // TODO
- if (CloseInitiatedByUser && !KeepContentVisibleOnClose)
+ // Allow base Window class and attached Closing event handlers to potentially cancel first.
+ base.OnClosing(e);
+
+ if (e.Cancel) // If already cancelled by base or others, do nothing.
+ return;
+
+ // If closed programmatically by AvalonDock (e.g., dragging last doc out), skip user checks.
+ if (!CloseInitiatedByUser)
+ return;
+
+ // Handle user-initiated close (Taskbar, Alt+F4, Window's 'X' button).
+ var manager = Model?.Root?.Manager;
+ if (manager == null)
+ return;
+
+ var documentsToClose = this.Model.Descendents().OfType().ToArray();
+ var anchorablesToProcess = Model.Descendents().OfType().ToArray();
+
+ // Phase 1.1: Validate if ALL documents can be closed
+ // This checks properties and fires Closing events without actually closing yet.
+ // - Check explicit property first.
+ // - Check internal LayoutContent.Closing event subscribers.
+ // - Check external DockingManager.DocumentClosing event subscribers.
+ // - Check command CanExecute.
+ var cancelAllFromDocuments = documentsToClose.Any(
+ doc => !doc.CanClose
+ || !doc.TestCanClose()
+ || !ManagerTestCanClose(doc)
+ || !(manager.GetLayoutItemFromModel(doc)?.CloseCommand?.CanExecute(null) ?? false));
+
+ // Phase 1.2: Validate if ALL anchorables can be processed (closed or hidden)
+ // Priority: Try Close Path
+ // Fallback: Try Hide Path
+ // Fallback 2: Cannot Close AND Cannot Hide
+ var cancelAllFromAnchorables = anchorablesToProcess.Any(anch =>
+ {
+ var closeCommand = manager.GetLayoutItemFromModel(anch)?.CloseCommand;
+ var hideCommand = (manager.GetLayoutItemFromModel(anch) as LayoutAnchorableItem)?.HideCommand;
+ return anch.CanClose && (!anch.TestCanClose() || !ManagerTestCanClose(anch) || closeCommand?.CanExecute(null) is false) ||
+ anch.CanHide && (!anch.TestCanHide() || !ManagerTestCanHide(anch) || hideCommand?.CanExecute(null) is false) ||
+ !anch.CanClose && !anch.CanHide;
+ });
+ var cancelAll = cancelAllFromDocuments || cancelAllFromAnchorables;
+
+ // If any document prevents closing, cancel the window closing.
+ if (cancelAll)
{
e.Cancel = true;
- //_model.Descendents().OfType().ToArray().ForEach((a) => a.Hide());
+ return;
}
- base.OnClosing(e);
+
+ // Phase 2: Execute actions
+ foreach (var doc in documentsToClose.ToList())
+ {
+ var layoutItem = manager.GetLayoutItemFromModel(doc) as LayoutDocumentItem;
+
+ if (layoutItem != null && !layoutItem.IsDefaultCloseCommand)
+ {
+ // User Custom Command Path
+ // Execute the user's command. Assume user handles risks.
+ layoutItem.CloseCommand?.Execute(null); // CanExecute already checked in Phase 1
+ }
+ else
+ {
+ // Default AvalonDock Logic Path
+ // 1. Perform internal close logic (removes from parent, etc.)
+ doc.CloseInternal(); // Does NOT raise manager's DocumentClosed event
+
+ // 2. Clean up view/logical tree elements
+ if (layoutItem?.IsViewExists() == true)
+ manager.InternalRemoveLogicalChild(layoutItem.View);
+
+ if (doc.Content is UIElement uiElement)
+ manager.InternalRemoveLogicalChild(uiElement);
+
+ doc.Content = null; // Final content cleanup
+
+ // 3. Raise the manager's final event
+ manager.RaiseDocumentClosed(doc);
+ }
+ }
+
+ // We use the compromise: execute user command if provided, otherwise execute default logic directly.
+ var wasAnyContentHidden = false;
+ foreach (var anch in anchorablesToProcess.ToList()) // Use ToList() as actions might modify the underlying collection.
+ {
+ var layoutItem = manager.GetLayoutItemFromModel(anch) as LayoutAnchorableItem;
+ bool useDefaultLogic = layoutItem == null; // Should not happen, but safe default
+
+ if (anch.CanClose) // Priority Action: Close
+ {
+ if (!useDefaultLogic) useDefaultLogic = layoutItem.IsDefaultCloseCommand;
+
+ if (!useDefaultLogic)
+ {
+ // User Custom Command Path
+ layoutItem.CloseCommand?.Execute(null);
+ }
+ else
+ {
+ // Default AvalonDock Logic Path
+ anch.CloseInternal(); // Does NOT raise manager's Closing/Closed events again
+ if (layoutItem?.IsViewExists() == true)
+ manager.InternalRemoveLogicalChild(layoutItem.View);
+ manager.RaiseAnchorableClosed(anch); // Raise final event
+ }
+ }
+ else if (anch.CanHide) // Fallback Action: Hide
+ {
+ if (!useDefaultLogic) useDefaultLogic = layoutItem.IsDefaultHideCommand;
+
+ if (!useDefaultLogic)
+ {
+ // User Custom Command Path
+ layoutItem.HideCommand?.Execute(null);
+ }
+ else
+ {
+ // Default AvalonDock Logic Path
+ // Use 'false' to bypass internal cancel checks already done in Phase 1.
+ if (anch.HideAnchorable(false)) // Does NOT raise manager's Hiding/Hidden events again
+ {
+ // View removal for Hide is typically handled by DockingManager logic or CollectGarbage.
+ manager.RaiseAnchorableHidden(anch); // Raise final event
+ }
+ }
+
+ wasAnyContentHidden = true;
+ }
+ // If neither CanClose nor CanHide, do nothing (already validated in Phase 1).
+ }
+
+ if (wasAnyContentHidden)
+ {
+ // Close the window only if all anchorables were closed
+ e.Cancel = true;
+ }
+
+ // Window will close naturally as e.Cancel was not set to true.
}
+ ///
+ /// Helper method to check DockingManager's DocumentClosing event for cancellation.
+ ///
+ private bool ManagerTestCanClose(LayoutDocument doc)
+ {
+ var docClosingArgs = new DocumentClosingEventArgs(doc);
+ Model?.Root?.Manager.RaiseDocumentClosing(docClosingArgs);
+ return !docClosingArgs.Cancel;
+ }
+
+ ///
+ /// Helper method to check DockingManager's AnchorableClosing event for cancellation.
+ ///
+ private bool ManagerTestCanClose(LayoutAnchorable anch)
+ {
+ var ancClosingArgs = new AnchorableClosingEventArgs(anch);
+ Model?.Root?.Manager.RaiseAnchorableClosing(ancClosingArgs);
+ return !ancClosingArgs.Cancel;
+ }
+
+ ///
+ /// Helper method to check DockingManager's AnchorableHiding event for cancellation,
+ /// including the CloseInsteadOfHide request when CanClose is false.
+ ///
+ private bool ManagerTestCanHide(LayoutAnchorable anch)
+ {
+ var hidingArgs = new AnchorableHidingEventArgs(anch);
+ Model?.Root?.Manager.RaiseAnchorableHiding(hidingArgs);
+
+ // If the Hiding event itself was cancelled, prevent the action.
+ if (hidingArgs.Cancel)
+ return false;
+
+ // If Hiding requests Close instead, but CanClose is false (which it must be
+ // to reach this point), then the requested action cannot be performed, so cancel.
+ if (hidingArgs.CloseInsteadOfHide)
+ {
+ // Log warning maybe? "CloseInsteadOfHide requested for an anchorable where CanClose=false."
+ return false;
+ }
+
+ // Hiding was not cancelled and not replaced by an impossible Close action.
+ return true;
+ }
+
bool IOverlayWindowHost.HitTestScreen(Point dragPoint)
{
return HitTest(this.TransformToDeviceDPI(dragPoint));
diff --git a/source/Components/AvalonDock/Controls/LayoutFloatingWindowControl.cs b/source/Components/AvalonDock/Controls/LayoutFloatingWindowControl.cs
index f13ab5d6..29057e5f 100644
--- a/source/Components/AvalonDock/Controls/LayoutFloatingWindowControl.cs
+++ b/source/Components/AvalonDock/Controls/LayoutFloatingWindowControl.cs
@@ -513,7 +513,10 @@ internal void InternalClose(bool closeInitiatedByUser = false)
///
protected override void OnClosed(EventArgs e)
{
+ // Unsubscribe from window events to prevent memory leaks.
SizeChanged -= OnSizeChanged;
+
+ // Clean up native window resources and message hook.
if (Content != null)
{
(Content as FloatingWindowContentHost)?.Dispose();
@@ -524,6 +527,29 @@ protected override void OnClosed(EventArgs e)
_hwndSrc = null;
}
}
+
+ var root = Model?.Root;
+ var modelToRemove = _model as LayoutFloatingWindow;
+ if (root != null)
+ {
+ // Notify the manager to remove this view instance from its tracking list (_fwList).
+ root.Manager?.RemoveFloatingWindow(this);
+
+ // Remove the model from the LayoutRoot's collection only if closed externally
+ // AND if the model wasn't already detached (e.g., by CollectGarbage during the closing process).
+ if (!_internalCloseFlag && modelToRemove?.Parent == root)
+ {
+ root.FloatingWindows?.Remove(modelToRemove);
+ }
+
+ // Clean up the layout tree (e.g., remove empty parent panes).
+ root.CollectGarbage();
+ }
+
+ // Ensure derived classes clean up model event handlers and bindings
+ // to prevent leaks between view and model.
+ DisableBindings();
+
base.OnClosed(e);
}
diff --git a/source/Components/AvalonDock/Controls/LayoutItem.cs b/source/Components/AvalonDock/Controls/LayoutItem.cs
index 891d17b5..c99ee4df 100644
--- a/source/Components/AvalonDock/Controls/LayoutItem.cs
+++ b/source/Components/AvalonDock/Controls/LayoutItem.cs
@@ -289,6 +289,9 @@ public ICommand CloseCommand
get => (ICommand)GetValue(CloseCommandProperty);
set => SetValue(CloseCommandProperty, value);
}
+
+ /// Gets wether the property has its default value.
+ internal bool IsDefaultCloseCommand => CloseCommand == _defaultCloseCommand;
/// Handles changes to the property.
private static void OnCloseCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) => ((LayoutItem)d).OnCloseCommandChanged(e);
diff --git a/source/Components/AvalonDock/DockingManager.cs b/source/Components/AvalonDock/DockingManager.cs
index 8c7ca9d0..37fbf465 100644
--- a/source/Components/AvalonDock/DockingManager.cs
+++ b/source/Components/AvalonDock/DockingManager.cs
@@ -1990,6 +1990,18 @@ internal void ExecuteHideCommand(LayoutAnchorable anchorable)
internal void ExecuteContentActivateCommand(LayoutContent content) => content.IsActive = true;
+ internal void RaiseDocumentClosing(DocumentClosingEventArgs e) => DocumentClosing?.Invoke(this, e);
+
+ internal void RaiseAnchorableHiding(AnchorableHidingEventArgs e) => AnchorableHiding?.Invoke(this, e);
+
+ internal void RaiseAnchorableClosing(AnchorableClosingEventArgs e) => AnchorableClosing?.Invoke(this, e);
+
+ internal void RaiseDocumentClosed(LayoutDocument document) => DocumentClosed?.Invoke(this, new DocumentClosedEventArgs(document));
+
+ internal void RaiseAnchorableClosed(LayoutAnchorable anchorable) => AnchorableClosed?.Invoke(this, new AnchorableClosedEventArgs(anchorable));
+
+ internal void RaiseAnchorableHidden(LayoutAnchorable anchorable) => AnchorableHidden?.Invoke(this, new AnchorableHiddenEventArgs(anchorable));
+
#endregion Internal Methods
#region Overrides
diff --git a/source/Components/AvalonDock/Layout/LayoutAnchorable.cs b/source/Components/AvalonDock/Layout/LayoutAnchorable.cs
index 68efffde..124fd308 100644
--- a/source/Components/AvalonDock/Layout/LayoutAnchorable.cs
+++ b/source/Components/AvalonDock/Layout/LayoutAnchorable.cs
@@ -646,6 +646,13 @@ internal bool CloseAnchorable()
// _canClose = _canCloseValueBeforeInternalSet;
//}
+ internal bool TestCanHide()
+ {
+ var args = new CancelEventArgs();
+ OnHiding(args);
+ return !args.Cancel;
+ }
+
#endregion Internal Methods
#region Private Methods
diff --git a/source/Components/AvalonDock/Layout/LayoutDocumentPaneGroup.cs b/source/Components/AvalonDock/Layout/LayoutDocumentPaneGroup.cs
index ae317ec5..8dc6f2cc 100644
--- a/source/Components/AvalonDock/Layout/LayoutDocumentPaneGroup.cs
+++ b/source/Components/AvalonDock/Layout/LayoutDocumentPaneGroup.cs
@@ -8,6 +8,7 @@ This program is provided to you under the terms of the Microsoft Public
************************************************************************/
using System;
+using System.Linq;
using System.Windows.Controls;
using System.Windows.Markup;
@@ -60,9 +61,10 @@ public Orientation Orientation
#endregion Properties
#region Overrides
-
+
///
- protected override bool GetVisibility() => true;
+ protected override bool GetVisibility() =>
+ Children.Count > 0 && Children.Any(c => c.IsVisible);
///
public override void WriteXml(System.Xml.XmlWriter writer)
diff --git a/source/Components/AvalonDock/Win32Helper.cs b/source/Components/AvalonDock/Win32Helper.cs
index 9c66b608..7c513190 100644
--- a/source/Components/AvalonDock/Win32Helper.cs
+++ b/source/Components/AvalonDock/Win32Helper.cs
@@ -153,7 +153,6 @@ internal class WINDOWPOS
internal const int WM_INITMENUPOPUP = 0x0117;
internal const int WM_KEYDOWN = 0x0100;
internal const int WM_KEYUP = 0x0101;
- internal const int WM_CLOSE = 0x10;
internal const int WA_INACTIVE = 0x0000;