using System; using System.Collections.Generic; namespace Avalonia.LogicalTree { /// /// Provides extension methods for working with the logical tree. /// public static class LogicalExtensions { /// /// Enumerates the ancestors of an in the logical tree. /// /// The logical. /// The logical's ancestors. public static IEnumerable GetLogicalAncestors(this ILogical logical) { _ = logical ?? throw new ArgumentNullException(nameof(logical)); ILogical? l = logical.LogicalParent; while (l != null) { yield return l; l = l.LogicalParent; } } /// /// Enumerates an and its ancestors in the logical tree. /// /// The logical. /// The logical and its ancestors. public static IEnumerable GetSelfAndLogicalAncestors(this ILogical logical) { yield return logical; foreach (var ancestor in logical.GetLogicalAncestors()) { yield return ancestor; } } /// /// 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; } var parent = includeSelf ? logical : logical.LogicalParent; while (parent != null) { if (parent is T result) { return result; } parent = parent.LogicalParent; } return null; } /// /// Enumerates the children of an in the logical tree. /// /// The logical. /// The logical children. public static IEnumerable GetLogicalChildren(this ILogical logical) { return logical.LogicalChildren; } /// /// Enumerates the descendants of an in the logical tree. /// /// The logical. /// The logical's ancestors. public static IEnumerable GetLogicalDescendants(this ILogical logical) { foreach (ILogical child in logical.LogicalChildren) { yield return child; foreach (ILogical descendant in child.GetLogicalDescendants()) { yield return descendant; } } } /// /// Enumerates an and its descendants in the logical tree. /// /// The logical. /// The logical and its ancestors. public static IEnumerable GetSelfAndLogicalDescendants(this ILogical logical) { yield return logical; foreach (var descendent in logical.GetLogicalDescendants()) { yield return descendent; } } /// /// 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); } /// /// Gets the logical parent of an . /// /// The logical. /// The parent, or null if the logical is unparented. public static ILogical? GetLogicalParent(this ILogical logical) { return logical.LogicalParent; } /// /// Gets the logical parent of an . /// /// The type of the logical parent. /// The logical. /// /// The parent, or null if the logical is unparented or its parent is not of type . /// public static T? GetLogicalParent(this ILogical logical) where T : class { return logical.LogicalParent as T; } /// /// Enumerates the siblings of an in the logical tree. /// /// The logical. /// The logical siblings. public static IEnumerable GetLogicalSiblings(this ILogical logical) { var parent = logical.LogicalParent; if (parent != null) { foreach (ILogical sibling in parent.LogicalChildren) { yield return sibling; } } } /// /// Tests whether an is an ancestor of another logical. /// /// The logical. /// The potential descendant. /// /// True if is an ancestor of ; /// otherwise false. /// public static bool IsLogicalAncestorOf(this ILogical? logical, ILogical? target) { var 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; } } }