From cd2b26bc949d3a6f347d4dd2e2d27b502423ae73 Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Fri, 1 May 2020 20:09:36 +0200 Subject: [PATCH] Add extra methods to LogicalExtensions and optimize a few methods as well. --- .../Platform/DefaultMenuInteractionHandler.cs | 2 +- .../ManagedFileChooser.xaml.cs | 2 +- .../LogicalTree/LogicalExtensions.cs | 93 ++++++++++++++++++- .../VisualTree/VisualExtensions.cs | 14 ++- 4 files changed, 105 insertions(+), 6 deletions(-) diff --git a/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs b/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs index 3715bc52a4..8ad622ba4a 100644 --- a/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs +++ b/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs @@ -392,7 +392,7 @@ namespace Avalonia.Controls.Platform { var control = e.Source as ILogical; - if (!Menu.IsLogicalParentOf(control)) + if (!Menu.IsLogicalAncestorOf(control)) { Menu.Close(); } diff --git a/src/Avalonia.Dialogs/ManagedFileChooser.xaml.cs b/src/Avalonia.Dialogs/ManagedFileChooser.xaml.cs index b967b40c0d..616f260397 100644 --- a/src/Avalonia.Dialogs/ManagedFileChooser.xaml.cs +++ b/src/Avalonia.Dialogs/ManagedFileChooser.xaml.cs @@ -34,7 +34,7 @@ namespace Avalonia.Dialogs return; } - var isQuickLink = _quickLinksRoot.IsLogicalParentOf(e.Source as Control); + var isQuickLink = _quickLinksRoot.IsLogicalAncestorOf(e.Source as Control); if (e.ClickCount == 2 || isQuickLink) { if (model.ItemType == ManagedFileChooserItemType.File) diff --git a/src/Avalonia.Styling/LogicalTree/LogicalExtensions.cs b/src/Avalonia.Styling/LogicalTree/LogicalExtensions.cs index 1003375978..bd05796578 100644 --- a/src/Avalonia.Styling/LogicalTree/LogicalExtensions.cs +++ b/src/Avalonia.Styling/LogicalTree/LogicalExtensions.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; namespace Avalonia.LogicalTree { @@ -29,6 +28,35 @@ namespace Avalonia.LogicalTree } } + /// + /// Finds first ancestor of given type. + /// + /// Ancestor type. + /// The logical. + /// If given logical should be included in search. + /// First ancestor of given type. + public static T FindLogicalAncestorOfType(this ILogical logical, bool includeSelf = false) where T : class + { + if (logical is null) + { + return null; + } + + ILogical parent = includeSelf ? logical : logical.LogicalParent; + + while (parent != null) + { + if (parent is T result) + { + return result; + } + + parent = parent.LogicalParent; + } + + return null; + } + public static IEnumerable GetLogicalChildren(this ILogical logical) { return logical.LogicalChildren; @@ -57,6 +85,28 @@ namespace Avalonia.LogicalTree } } + /// + /// Finds first descendant of given type. + /// + /// Descendant type. + /// The logical. + /// If given logical should be included in search. + /// First descendant of given type. + public static T FindLogicalDescendantOfType(this ILogical logical, bool includeSelf = false) where T : class + { + if (logical is null) + { + return null; + } + + if (includeSelf && logical is T result) + { + return result; + } + + return FindDescendantOfTypeCore(logical); + } + public static ILogical GetLogicalParent(this ILogical logical) { return logical.LogicalParent; @@ -80,9 +130,46 @@ namespace Avalonia.LogicalTree } } - public static bool IsLogicalParentOf(this ILogical logical, ILogical target) + public static bool IsLogicalAncestorOf(this ILogical logical, ILogical target) { - return target.GetLogicalAncestors().Any(x => x == logical); + ILogical current = target?.LogicalParent; + + while (current != null) + { + if (current == logical) + { + return true; + } + + current = current.LogicalParent; + } + + return false; + } + + private static T FindDescendantOfTypeCore(ILogical logical) where T : class + { + var logicalChildren = logical.LogicalChildren; + var logicalChildrenCount = logicalChildren.Count; + + for (var i = 0; i < logicalChildrenCount; i++) + { + ILogical child = logicalChildren[i]; + + if (child is T result) + { + return result; + } + + var childResult = FindDescendantOfTypeCore(child); + + if (!(childResult is null)) + { + return childResult; + } + } + + return null; } } } diff --git a/src/Avalonia.Visuals/VisualTree/VisualExtensions.cs b/src/Avalonia.Visuals/VisualTree/VisualExtensions.cs index 4b3e757e7a..636aa6836e 100644 --- a/src/Avalonia.Visuals/VisualTree/VisualExtensions.cs +++ b/src/Avalonia.Visuals/VisualTree/VisualExtensions.cs @@ -377,7 +377,19 @@ namespace Avalonia.VisualTree /// public static bool IsVisualAncestorOf(this IVisual visual, IVisual target) { - return target.GetVisualAncestors().Any(x => x == visual); + IVisual current = target; + + while (current != null) + { + if (current == visual) + { + return true; + } + + current = current.VisualParent; + } + + return false; } public static IEnumerable SortByZIndex(this IEnumerable elements)