diff --git a/components/Extensions/src/Tree/FrameworkElementExtensions.LogicalTree.cs b/components/Extensions/src/Tree/FrameworkElementExtensions.LogicalTree.cs
index 2ffaba73..9e4d6fb6 100644
--- a/components/Extensions/src/Tree/FrameworkElementExtensions.LogicalTree.cs
+++ b/components/Extensions/src/Tree/FrameworkElementExtensions.LogicalTree.cs
@@ -1,773 +1,805 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Collections.Generic;
-using System.Reflection;
-using CommunityToolkit.WinUI.Predicates;
-
-#nullable enable
-
-namespace CommunityToolkit.WinUI;
-
-///
-public static partial class FrameworkElementExtensions
-{
- ///
- /// Find the first child of type with a given name, using a depth-first search.
- ///
- /// The root element.
- /// The name of the element to look for.
- /// The comparison type to use to match .
- /// The child that was found, or .
- public static FrameworkElement? FindChild(this FrameworkElement element, string name, StringComparison comparisonType = StringComparison.Ordinal)
- {
- PredicateByName predicateByName = new (name, comparisonType);
-
- return FindChild(element, ref predicateByName);
- }
-
- ///
- /// Find the first child element of a given type, using a depth-first search.
- ///
- /// The type of elements to match.
- /// The root element.
- /// The child that was found, or .
- public static T? FindChild(this FrameworkElement element)
- where T : notnull, FrameworkElement
- {
- PredicateByAny predicateByAny = default;
-
- return FindChild>(element, ref predicateByAny);
- }
-
- ///
- /// Find the first child element of a given type, using a depth-first search.
- ///
- /// The root element.
- /// The type of element to match.
- /// The child that was found, or .
- public static FrameworkElement? FindChild(this FrameworkElement element, Type type)
- {
- PredicateByType predicateByType = new (type);
-
- return FindChild(element, ref predicateByType);
- }
-
- ///
- /// Find the first child element matching a given predicate, using a depth-first search.
- ///
- /// The type of elements to match.
- /// The root element.
- /// The predicatee to use to match the child nodes.
- /// The child that was found, or .
- public static T? FindChild(this FrameworkElement element, Func predicate)
- where T : notnull, FrameworkElement
- {
- PredicateByFunc predicateByFunc = new (predicate);
-
- return FindChild>(element, ref predicateByFunc);
- }
-
- ///
- /// Find the first child element matching a given predicate, using a depth-first search.
- ///
- /// The type of elements to match.
- /// The type of state to use when matching nodes.
- /// The root element.
- /// The state to give as input to .
- /// The predicatee to use to match the child nodes.
- /// The child that was found, or .
- public static T? FindChild(this FrameworkElement element, TState state, Func predicate)
- where T : notnull, FrameworkElement
- {
- PredicateByFunc predicateByFunc = new (state, predicate);
-
- return FindChild>(element, ref predicateByFunc);
- }
-
- ///
- /// Find the first child element matching a given predicate, using a depth-first search.
- ///
- /// The type of elements to match.
- /// The type of predicate in use.
- /// The root element.
- /// The predicatee to use to match the child nodes.
- /// The child that was found, or .
- private static T? FindChild(this FrameworkElement element, ref TPredicate predicate)
- where T : notnull, FrameworkElement
- where TPredicate : struct, IPredicate
- {
- // Jump label to manually optimize the tail recursive paths for elements with a single
- // child by just overwriting the current element and jumping back to the start of the
- // method. This avoids a recursive call and one stack frame every time.
- Start:
-
- if (element is Panel panel)
- {
- foreach (UIElement child in panel.Children)
- {
- if (child is not FrameworkElement current)
- {
- continue;
- }
-
- if (child is T result && predicate.Match(result))
- {
- return result;
- }
-
- T? descendant = FindChild(current, ref predicate);
-
- if (descendant is not null)
- {
- return descendant;
- }
- }
- }
- else if (element is ItemsControl itemsControl)
- {
- foreach (object item in itemsControl.Items)
- {
- if (item is not FrameworkElement current)
- {
- continue;
- }
-
- if (item is T result && predicate.Match(result))
- {
- return result;
- }
-
- T? descendant = FindChild(current, ref predicate);
-
- if (descendant is not null)
- {
- return descendant;
- }
- }
- }
- else if (element is ContentControl contentControl)
- {
- if (contentControl.Content is FrameworkElement content)
- {
- if (content is T result && predicate.Match(result))
- {
- return result;
- }
-
- element = content;
-
- goto Start;
- }
- }
- else if (element is Border border)
- {
- if (border.Child is FrameworkElement child)
- {
- if (child is T result && predicate.Match(result))
- {
- return result;
- }
-
- element = child;
-
- goto Start;
- }
- }
- else if (element is ContentPresenter contentPresenter)
- {
- // Sometimes ContentPresenter is used in control templates instead of ContentControl,
- // therefore we should still check if its Content is a matching FrameworkElement instance.
- // This also makes this work for SwitchPresenter.
- if (contentPresenter.Content is FrameworkElement content)
- {
- if (content is T result && predicate.Match(result))
- {
- return result;
- }
-
- element = content;
-
- goto Start;
- }
- }
- else if (element is Viewbox viewbox)
- {
- if (viewbox.Child is FrameworkElement child)
- {
- if (child is T result && predicate.Match(result))
- {
- return result;
- }
-
- element = child;
-
- goto Start;
- }
- }
- else if (element is UserControl userControl)
- {
- // We put UserControl right before the slower reflection fallback path as
- // this type is less likely to be used compared to the other ones above.
- if (userControl.Content is FrameworkElement content)
- {
- if (content is T result && predicate.Match(result))
- {
- return result;
- }
-
- element = content;
-
- goto Start;
- }
- }
- else if (element.GetContentControl() is FrameworkElement containedControl)
- {
- if (containedControl is T result && predicate.Match(result))
- {
- return result;
- }
-
- element = containedControl;
-
- goto Start;
- }
-
- return null;
- }
-
- ///
- /// Find the first child (or self) of type with a given name, using a depth-first search.
- ///
- /// The root element.
- /// The name of the element to look for.
- /// The comparison type to use to match .
- /// The child (or self) that was found, or .
- public static FrameworkElement? FindChildOrSelf(this FrameworkElement element, string name, StringComparison comparisonType = StringComparison.Ordinal)
- {
- if (name.Equals(element.Name, comparisonType))
- {
- return element;
- }
-
- return FindChild(element, name, comparisonType);
- }
-
- ///
- /// Find the first child (or self) element of a given type, using a depth-first search.
- ///
- /// The type of elements to match.
- /// The root element.
- /// The child (or self) that was found, or .
- public static T? FindChildOrSelf(this FrameworkElement element)
- where T : notnull, FrameworkElement
- {
- if (element is T result)
- {
- return result;
- }
-
- return FindChild(element);
- }
-
- ///
- /// Find the first child (or self) element of a given type, using a depth-first search.
- ///
- /// The root element.
- /// The type of element to match.
- /// The child (or self) that was found, or .
- public static FrameworkElement? FindChildOrSelf(this FrameworkElement element, Type type)
- {
- if (element.GetType() == type)
- {
- return element;
- }
-
- return FindChild(element, type);
- }
-
- ///
- /// Find the first child (or self) element matching a given predicate, using a depth-first search.
- ///
- /// The type of elements to match.
- /// The root element.
- /// The predicatee to use to match the child nodes.
- /// The child (or self) that was found, or .
- public static T? FindChildOrSelf(this FrameworkElement element, Func predicate)
- where T : notnull, FrameworkElement
- {
- if (element is T result && predicate(result))
- {
- return result;
- }
-
- return FindChild(element, predicate);
- }
-
- ///
- /// Find the first child (or self) element matching a given predicate, using a depth-first search.
- ///
- /// The type of elements to match.
- /// The type of state to use when matching nodes.
- /// The root element.
- /// The state to give as input to .
- /// The predicatee to use to match the child nodes.
- /// The child (or self) that was found, or .
- public static T? FindChildOrSelf(this FrameworkElement element, TState state, Func predicate)
- where T : notnull, FrameworkElement
- {
- if (element is T result && predicate(result, state))
- {
- return result;
- }
-
- return FindChild(element, state, predicate);
- }
-
- ///
- /// Find all logical child elements of the specified element. This method can be chained with
- /// LINQ calls to add additional filters or projections on top of the returned results.
- ///
- /// This method is meant to provide extra flexibility in specific scenarios and it should not
- /// be used when only the first item is being looked for. In those cases, use one of the
- /// available overloads instead, which will
- /// offer a more compact syntax as well as better performance in those cases.
- ///
- ///
- /// The root element.
- /// All the child instance from .
- public static IEnumerable FindChildren(this FrameworkElement element)
- {
- Start:
-
- if (element is Panel panel)
- {
- foreach (UIElement child in panel.Children)
- {
- if (child is not FrameworkElement current)
- {
- continue;
- }
-
- yield return current;
-
- foreach (FrameworkElement childOfChild in FindChildren(current))
- {
- yield return childOfChild;
- }
- }
- }
- else if (element is ItemsControl itemsControl)
- {
- foreach (object item in itemsControl.Items)
- {
- if (item is not FrameworkElement current)
- {
- continue;
- }
-
- yield return current;
-
- foreach (FrameworkElement childOfChild in FindChildren(current))
- {
- yield return childOfChild;
- }
- }
- }
- else if (element is ContentControl contentControl)
- {
- if (contentControl.Content is FrameworkElement content)
- {
- yield return content;
-
- element = content;
-
- goto Start;
- }
- }
- else if (element is Border border)
- {
- if (border.Child is FrameworkElement child)
- {
- yield return child;
-
- element = child;
-
- goto Start;
- }
- }
- else if (element is ContentPresenter contentPresenter)
- {
- if (contentPresenter.Content is FrameworkElement content)
- {
- yield return content;
-
- element = content;
-
- goto Start;
- }
- }
- else if (element is Viewbox viewbox)
- {
- if (viewbox.Child is FrameworkElement child)
- {
- yield return child;
-
- element = child;
-
- goto Start;
- }
- }
- else if (element is UserControl userControl)
- {
- if (userControl.Content is FrameworkElement content)
- {
- yield return content;
-
- element = content;
-
- goto Start;
- }
- }
- else if (element.GetContentControl() is FrameworkElement containedControl)
- {
- yield return containedControl;
-
- element = containedControl;
-
- goto Start;
- }
- }
-
- ///
- /// Find the first parent of type with a given name.
- ///
- /// The starting element.
- /// The name of the element to look for.
- /// The comparison type to use to match .
- /// The parent that was found, or .
- public static FrameworkElement? FindParent(this FrameworkElement element, string name, StringComparison comparisonType = StringComparison.Ordinal)
- {
- PredicateByName predicateByName = new (name, comparisonType);
-
- return FindParent(element, ref predicateByName);
- }
-
- ///
- /// Find the first parent element of a given type.
- ///
- /// The type of elements to match.
- /// The starting element.
- /// The parent that was found, or .
- public static T? FindParent(this FrameworkElement element)
- where T : notnull, FrameworkElement
- {
- PredicateByAny predicateByAny = default;
-
- return FindParent>(element, ref predicateByAny);
- }
-
- ///
- /// Find the first parent element of a given type.
- ///
- /// The starting element.
- /// The type of element to match.
- /// The parent that was found, or .
- public static FrameworkElement? FindParent(this FrameworkElement element, Type type)
- {
- PredicateByType predicateByType = new (type);
-
- return FindParent(element, ref predicateByType);
- }
-
- ///
- /// Find the first parent element matching a given predicate.
- ///
- /// The type of elements to match.
- /// The starting element.
- /// The predicatee to use to match the parent nodes.
- /// The parent that was found, or .
- public static T? FindParent(this FrameworkElement element, Func predicate)
- where T : notnull, FrameworkElement
- {
- PredicateByFunc predicateByFunc = new (predicate);
-
- return FindParent>(element, ref predicateByFunc);
- }
-
- ///
- /// Find the first parent element matching a given predicate.
- ///
- /// The type of elements to match.
- /// The type of state to use when matching nodes.
- /// The starting element.
- /// The state to give as input to .
- /// The predicatee to use to match the parent nodes.
- /// The parent that was found, or .
- public static T? FindParent(this FrameworkElement element, TState state, Func predicate)
- where T : notnull, FrameworkElement
- {
- PredicateByFunc predicateByFunc = new (state, predicate);
-
- return FindParent>(element, ref predicateByFunc);
- }
-
- ///
- /// Find the first parent element matching a given predicate.
- ///
- /// The type of elements to match.
- /// The type of predicate in use.
- /// The starting element.
- /// The predicatee to use to match the parent nodes.
- /// The parent that was found, or .
- private static T? FindParent(this FrameworkElement element, ref TPredicate predicate)
- where T : notnull, FrameworkElement
- where TPredicate : struct, IPredicate
- {
- while (true)
- {
- if (element.Parent is not FrameworkElement parent)
- {
- return null;
- }
-
- if (parent is T result && predicate.Match(result))
- {
- return result;
- }
-
- element = parent;
- }
- }
-
- ///
- /// Find the first parent (or self) of type with a given name.
- ///
- /// The starting element.
- /// The name of the element to look for.
- /// The comparison type to use to match .
- /// The parent (or self) that was found, or .
- public static FrameworkElement? FindParentOrSelf(this FrameworkElement element, string name, StringComparison comparisonType = StringComparison.Ordinal)
- {
- if (name.Equals(element.Name, comparisonType))
- {
- return element;
- }
-
- return FindParent(element, name, comparisonType);
- }
-
- ///
- /// Find the first parent (or self) element of a given type.
- ///
- /// The type of elements to match.
- /// The starting element.
- /// The parent (or self) that was found, or .
- public static T? FindParentOrSelf(this FrameworkElement element)
- where T : notnull, FrameworkElement
- {
- if (element is T result)
- {
- return result;
- }
-
- return FindParent(element);
- }
-
- ///
- /// Find the first parent (or self) element of a given type.
- ///
- /// The starting element.
- /// The type of element to match.
- /// The parent (or self) that was found, or .
- public static FrameworkElement? FindParentOrSelf(this FrameworkElement element, Type type)
- {
- if (element.GetType() == type)
- {
- return element;
- }
-
- return FindParent(element, type);
- }
-
- ///
- /// Find the first parent (or self) element matching a given predicate.
- ///
- /// The type of elements to match.
- /// The starting element.
- /// The predicatee to use to match the parent nodes.
- /// The parent (or self) that was found, or .
- public static T? FindParentOrSelf(this FrameworkElement element, Func predicate)
- where T : notnull, FrameworkElement
- {
- if (element is T result && predicate(result))
- {
- return result;
- }
-
- return FindParent(element, predicate);
- }
-
- ///
- /// Find the first parent (or self) element matching a given predicate.
- ///
- /// The type of elements to match.
- /// The type of state to use when matching nodes.
- /// The starting element.
- /// The state to give as input to .
- /// The predicatee to use to match the parent nodes.
- /// The parent (or self) that was found, or .
- public static T? FindParentOrSelf(this FrameworkElement element, TState state, Func predicate)
- where T : notnull, FrameworkElement
- {
- if (element is T result && predicate(result, state))
- {
- return result;
- }
-
- return FindParent(element, state, predicate);
- }
-
- ///
- /// Find all parent elements of the specified element. This method can be chained with
- /// LINQ calls to add additional filters or projections on top of the returned results.
- ///
- /// This method is meant to provide extra flexibility in specific scenarios and it should not
- /// be used when only the first item is being looked for. In those cases, use one of the
- /// available overloads instead, which will
- /// offer a more compact syntax as well as better performance in those cases.
- ///
- ///
- /// The root element.
- /// All the parent instance from .
- public static IEnumerable FindParents(this FrameworkElement element)
- {
- while (true)
- {
- if (element.Parent is not FrameworkElement parent)
- {
- yield break;
- }
-
- yield return parent;
-
- element = parent;
- }
- }
-
- ///
- /// Gets the content property of this element as defined by , if available.
- ///
- /// The parent element.
- /// The retrieved content control, or if not available.
- #if NET8_0_OR_GREATER
- [System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "This method is currently not safe for trimming, and annotations here wouldn't help.")]
- #endif
- public static UIElement? GetContentControl(this FrameworkElement element)
- {
- Type type = element.GetType();
- TypeInfo? typeInfo = type.GetTypeInfo();
-
- while (typeInfo is not null)
- {
- // We need to manually explore the custom attributes this way as the target one
- // is not returned by any of the other available GetCustomAttribute APIs.
- foreach (CustomAttributeData attribute in typeInfo.CustomAttributes)
- {
- if (attribute.AttributeType == typeof(ContentPropertyAttribute))
- {
- // If we're finding a ContentPropertyAttribute, this whole path should be set,
- // don't think we need additional checks here.
- string propertyName = (string)attribute.NamedArguments![0].TypedValue!.Value!;
- PropertyInfo? propertyInfo = type.GetProperty(propertyName);
-
- return propertyInfo?.GetValue(element) as UIElement;
- }
- }
-
- typeInfo = typeInfo.BaseType?.GetTypeInfo();
- }
-
- return null;
- }
-
- ///
- /// Provides a WPF compatible version of FindResource to provide a static resource lookup.
- /// If the key is not found in the current element's resources, the logical tree is then
- /// searched element-by-element to look for the resource in each element's resources.
- /// If none of the elements contain the resource, the Application's resources are then searched.
- /// See: .
- /// And also: .
- ///
- /// The to start searching for the target resource.
- /// The resource key to search for.
- /// The requested resource.
- /// Thrown when no resource is found with the specified key.
- public static object FindResource(this FrameworkElement element, object resourceKey)
- {
- if (TryFindResource(element, resourceKey, out object? value))
- {
- return value!;
- }
-
- static object Throw(object resourceKey) => throw new KeyNotFoundException($"No resource was found with the key \"{resourceKey}\"");
-
- return Throw(resourceKey);
- }
-
- ///
- /// Provides a WPF compatible version of TryFindResource to provide a static resource lookup.
- /// If the key is not found in the current element's resources, the logical tree is then
- /// searched element-by-element to look for the resource in each element's resources.
- /// If none of the elements contain the resource, the Application's resources are then searched.
- /// See: .
- /// And also: .
- ///
- /// The to start searching for the target resource.
- /// The resource key to search for.
- /// The requested resource, or if it wasn't found.
- public static object? TryFindResource(this FrameworkElement element, object resourceKey)
- {
- object? value = null;
-
- FrameworkElement? current = element;
-
- // Look in our dictionary and then walk-up parents. We use a do-while loop here
- // so that an implicit NRE will be thrown at the first iteration in case the
- // input element is null. This is consistent with the other extensions.
- do
- {
- if (current.Resources?.TryGetValue(resourceKey, out value) == true)
- {
- return value;
- }
-
- current = current.Parent as FrameworkElement;
- }
- while (current is not null);
-
- // Finally try application resources
- _ = Application.Current?.Resources?.TryGetValue(resourceKey, out value);
-
- return value;
- }
-
- ///
- /// Provides a WPF compatible version of TryFindResource to provide a static resource lookup.
- /// If the key is not found in the current element's resources, the logical tree is then
- /// searched element-by-element to look for the resource in each element's resources.
- /// If none of the elements contain the resource, the Application's resources are then searched.
- /// See: .
- /// And also: .
- ///
- /// The to start searching for the target resource.
- /// The resource key to search for.
- /// The resulting value, if present.
- /// Whether or not a value with the specified key has been found.
- public static bool TryFindResource(this FrameworkElement element, object resourceKey, out object? value)
- {
- return (value = TryFindResource(element, resourceKey)) is not null;
- }
-}
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using CommunityToolkit.WinUI.Predicates;
+using Microsoft.UI.Xaml.Controls;
+
+#nullable enable
+
+namespace CommunityToolkit.WinUI;
+
+///
+public static partial class FrameworkElementExtensions
+{
+ ///
+ /// Find the first child of type with a given name, using a depth-first search.
+ ///
+ /// The root element.
+ /// The name of the element to look for.
+ /// The comparison type to use to match .
+ /// The child that was found, or .
+ public static FrameworkElement? FindChild(this FrameworkElement element, string name, StringComparison comparisonType = StringComparison.Ordinal)
+ {
+ PredicateByName predicateByName = new (name, comparisonType);
+
+ return FindChild(element, ref predicateByName);
+ }
+
+ ///
+ /// Find the first child element of a given type, using a depth-first search.
+ ///
+ /// The type of elements to match.
+ /// The root element.
+ /// The child that was found, or .
+ public static T? FindChild(this FrameworkElement element)
+ where T : notnull, FrameworkElement
+ {
+ PredicateByAny predicateByAny = default;
+
+ return FindChild>(element, ref predicateByAny);
+ }
+
+ ///
+ /// Find the first child element of a given type, using a depth-first search.
+ ///
+ /// The root element.
+ /// The type of element to match.
+ /// The child that was found, or .
+ public static FrameworkElement? FindChild(this FrameworkElement element, Type type)
+ {
+ PredicateByType predicateByType = new (type);
+
+ return FindChild(element, ref predicateByType);
+ }
+
+ ///
+ /// Find the first child element matching a given predicate, using a depth-first search.
+ ///
+ /// The type of elements to match.
+ /// The root element.
+ /// The predicatee to use to match the child nodes.
+ /// The child that was found, or .
+ public static T? FindChild(this FrameworkElement element, Func predicate)
+ where T : notnull, FrameworkElement
+ {
+ PredicateByFunc predicateByFunc = new (predicate);
+
+ return FindChild>(element, ref predicateByFunc);
+ }
+
+ ///
+ /// Find the first child element matching a given predicate, using a depth-first search.
+ ///
+ /// The type of elements to match.
+ /// The type of state to use when matching nodes.
+ /// The root element.
+ /// The state to give as input to .
+ /// The predicatee to use to match the child nodes.
+ /// The child that was found, or .
+ public static T? FindChild(this FrameworkElement element, TState state, Func predicate)
+ where T : notnull, FrameworkElement
+ {
+ PredicateByFunc predicateByFunc = new (state, predicate);
+
+ return FindChild>(element, ref predicateByFunc);
+ }
+
+ ///
+ /// Find the first child element matching a given predicate, using a depth-first search.
+ ///
+ /// The type of elements to match.
+ /// The type of predicate in use.
+ /// The root element.
+ /// The predicatee to use to match the child nodes.
+ /// The child that was found, or .
+ private static T? FindChild(this FrameworkElement element, ref TPredicate predicate)
+ where T : notnull, FrameworkElement
+ where TPredicate : struct, IPredicate
+ {
+ // Jump label to manually optimize the tail recursive paths for elements with a single
+ // child by just overwriting the current element and jumping back to the start of the
+ // method. This avoids a recursive call and one stack frame every time.
+ Start:
+
+ if (element is Panel panel)
+ {
+ foreach (UIElement child in panel.Children)
+ {
+ if (child is not FrameworkElement current)
+ {
+ continue;
+ }
+
+ if (child is T result && predicate.Match(result))
+ {
+ return result;
+ }
+
+ T? descendant = FindChild(current, ref predicate);
+
+ if (descendant is not null)
+ {
+ return descendant;
+ }
+ }
+ }
+ else if (element is ItemsControl itemsControl)
+ {
+ foreach (object item in itemsControl.Items)
+ {
+ if (item is not FrameworkElement current)
+ {
+ continue;
+ }
+
+ if (item is T result && predicate.Match(result))
+ {
+ return result;
+ }
+
+ T? descendant = FindChild(current, ref predicate);
+
+ if (descendant is not null)
+ {
+ return descendant;
+ }
+ }
+ }
+ else if (element is ContentControl contentControl)
+ {
+ if (element is Expander expander)
+ {
+ if (expander.Header is FrameworkElement header)
+ {
+ if (header is T result && predicate.Match(result))
+ {
+ return result;
+ }
+
+ T? descendant = FindChild(header, ref predicate);
+
+ if (descendant is not null)
+ {
+ return descendant;
+ }
+ }
+ }
+
+ if (contentControl.Content is FrameworkElement content)
+ {
+ if (content is T result && predicate.Match(result))
+ {
+ return result;
+ }
+
+ element = content;
+
+ goto Start;
+ }
+ }
+ else if (element is Border border)
+ {
+ if (border.Child is FrameworkElement child)
+ {
+ if (child is T result && predicate.Match(result))
+ {
+ return result;
+ }
+
+ element = child;
+
+ goto Start;
+ }
+ }
+ else if (element is ContentPresenter contentPresenter)
+ {
+ // Sometimes ContentPresenter is used in control templates instead of ContentControl,
+ // therefore we should still check if its Content is a matching FrameworkElement instance.
+ // This also makes this work for SwitchPresenter.
+ if (contentPresenter.Content is FrameworkElement content)
+ {
+ if (content is T result && predicate.Match(result))
+ {
+ return result;
+ }
+
+ element = content;
+
+ goto Start;
+ }
+ }
+ else if (element is Viewbox viewbox)
+ {
+ if (viewbox.Child is FrameworkElement child)
+ {
+ if (child is T result && predicate.Match(result))
+ {
+ return result;
+ }
+
+ element = child;
+
+ goto Start;
+ }
+ }
+ else if (element is UserControl userControl)
+ {
+ // We put UserControl right before the slower reflection fallback path as
+ // this type is less likely to be used compared to the other ones above.
+ if (userControl.Content is FrameworkElement content)
+ {
+ if (content is T result && predicate.Match(result))
+ {
+ return result;
+ }
+
+ element = content;
+
+ goto Start;
+ }
+ }
+ else if (element.GetContentControl() is FrameworkElement containedControl)
+ {
+ if (containedControl is T result && predicate.Match(result))
+ {
+ return result;
+ }
+
+ element = containedControl;
+
+ goto Start;
+ }
+
+ return null;
+ }
+
+ ///
+ /// Find the first child (or self) of type with a given name, using a depth-first search.
+ ///
+ /// The root element.
+ /// The name of the element to look for.
+ /// The comparison type to use to match .
+ /// The child (or self) that was found, or .
+ public static FrameworkElement? FindChildOrSelf(this FrameworkElement element, string name, StringComparison comparisonType = StringComparison.Ordinal)
+ {
+ if (name.Equals(element.Name, comparisonType))
+ {
+ return element;
+ }
+
+ return FindChild(element, name, comparisonType);
+ }
+
+ ///
+ /// Find the first child (or self) element of a given type, using a depth-first search.
+ ///
+ /// The type of elements to match.
+ /// The root element.
+ /// The child (or self) that was found, or .
+ public static T? FindChildOrSelf(this FrameworkElement element)
+ where T : notnull, FrameworkElement
+ {
+ if (element is T result)
+ {
+ return result;
+ }
+
+ return FindChild(element);
+ }
+
+ ///
+ /// Find the first child (or self) element of a given type, using a depth-first search.
+ ///
+ /// The root element.
+ /// The type of element to match.
+ /// The child (or self) that was found, or .
+ public static FrameworkElement? FindChildOrSelf(this FrameworkElement element, Type type)
+ {
+ if (element.GetType() == type)
+ {
+ return element;
+ }
+
+ return FindChild(element, type);
+ }
+
+ ///
+ /// Find the first child (or self) element matching a given predicate, using a depth-first search.
+ ///
+ /// The type of elements to match.
+ /// The root element.
+ /// The predicatee to use to match the child nodes.
+ /// The child (or self) that was found, or .
+ public static T? FindChildOrSelf(this FrameworkElement element, Func predicate)
+ where T : notnull, FrameworkElement
+ {
+ if (element is T result && predicate(result))
+ {
+ return result;
+ }
+
+ return FindChild(element, predicate);
+ }
+
+ ///
+ /// Find the first child (or self) element matching a given predicate, using a depth-first search.
+ ///
+ /// The type of elements to match.
+ /// The type of state to use when matching nodes.
+ /// The root element.
+ /// The state to give as input to .
+ /// The predicatee to use to match the child nodes.
+ /// The child (or self) that was found, or .
+ public static T? FindChildOrSelf(this FrameworkElement element, TState state, Func predicate)
+ where T : notnull, FrameworkElement
+ {
+ if (element is T result && predicate(result, state))
+ {
+ return result;
+ }
+
+ return FindChild(element, state, predicate);
+ }
+
+ ///
+ /// Find all logical child elements of the specified element. This method can be chained with
+ /// LINQ calls to add additional filters or projections on top of the returned results.
+ ///
+ /// This method is meant to provide extra flexibility in specific scenarios and it should not
+ /// be used when only the first item is being looked for. In those cases, use one of the
+ /// available overloads instead, which will
+ /// offer a more compact syntax as well as better performance in those cases.
+ ///
+ ///
+ /// The root element.
+ /// All the child instance from .
+ public static IEnumerable FindChildren(this FrameworkElement element)
+ {
+ Start:
+
+ if (element is Panel panel)
+ {
+ foreach (UIElement child in panel.Children)
+ {
+ if (child is not FrameworkElement current)
+ {
+ continue;
+ }
+
+ yield return current;
+
+ foreach (FrameworkElement childOfChild in FindChildren(current))
+ {
+ yield return childOfChild;
+ }
+ }
+ }
+ else if (element is ItemsControl itemsControl)
+ {
+ foreach (object item in itemsControl.Items)
+ {
+ if (item is not FrameworkElement current)
+ {
+ continue;
+ }
+
+ yield return current;
+
+ foreach (FrameworkElement childOfChild in FindChildren(current))
+ {
+ yield return childOfChild;
+ }
+ }
+ }
+ else if (element is ContentControl contentControl)
+ {
+ if (element is Expander expander)
+ {
+ if (expander.Header is FrameworkElement header)
+ {
+ yield return header;
+
+ foreach (FrameworkElement childOfChild in FindChildren(header))
+ {
+ yield return childOfChild;
+ }
+ }
+ }
+
+ if (contentControl.Content is FrameworkElement content)
+ {
+ yield return content;
+
+ element = content;
+
+ goto Start;
+ }
+ }
+ else if (element is Border border)
+ {
+ if (border.Child is FrameworkElement child)
+ {
+ yield return child;
+
+ element = child;
+
+ goto Start;
+ }
+ }
+ else if (element is ContentPresenter contentPresenter)
+ {
+ if (contentPresenter.Content is FrameworkElement content)
+ {
+ yield return content;
+
+ element = content;
+
+ goto Start;
+ }
+ }
+ else if (element is Viewbox viewbox)
+ {
+ if (viewbox.Child is FrameworkElement child)
+ {
+ yield return child;
+
+ element = child;
+
+ goto Start;
+ }
+ }
+ else if (element is UserControl userControl)
+ {
+ if (userControl.Content is FrameworkElement content)
+ {
+ yield return content;
+
+ element = content;
+
+ goto Start;
+ }
+ }
+ else if (element.GetContentControl() is FrameworkElement containedControl)
+ {
+ yield return containedControl;
+
+ element = containedControl;
+
+ goto Start;
+ }
+ }
+
+ ///
+ /// Find the first parent of type with a given name.
+ ///
+ /// The starting element.
+ /// The name of the element to look for.
+ /// The comparison type to use to match .
+ /// The parent that was found, or .
+ public static FrameworkElement? FindParent(this FrameworkElement element, string name, StringComparison comparisonType = StringComparison.Ordinal)
+ {
+ PredicateByName predicateByName = new (name, comparisonType);
+
+ return FindParent(element, ref predicateByName);
+ }
+
+ ///
+ /// Find the first parent element of a given type.
+ ///
+ /// The type of elements to match.
+ /// The starting element.
+ /// The parent that was found, or .
+ public static T? FindParent(this FrameworkElement element)
+ where T : notnull, FrameworkElement
+ {
+ PredicateByAny predicateByAny = default;
+
+ return FindParent>(element, ref predicateByAny);
+ }
+
+ ///
+ /// Find the first parent element of a given type.
+ ///
+ /// The starting element.
+ /// The type of element to match.
+ /// The parent that was found, or .
+ public static FrameworkElement? FindParent(this FrameworkElement element, Type type)
+ {
+ PredicateByType predicateByType = new (type);
+
+ return FindParent(element, ref predicateByType);
+ }
+
+ ///
+ /// Find the first parent element matching a given predicate.
+ ///
+ /// The type of elements to match.
+ /// The starting element.
+ /// The predicatee to use to match the parent nodes.
+ /// The parent that was found, or .
+ public static T? FindParent(this FrameworkElement element, Func predicate)
+ where T : notnull, FrameworkElement
+ {
+ PredicateByFunc predicateByFunc = new (predicate);
+
+ return FindParent>(element, ref predicateByFunc);
+ }
+
+ ///
+ /// Find the first parent element matching a given predicate.
+ ///
+ /// The type of elements to match.
+ /// The type of state to use when matching nodes.
+ /// The starting element.
+ /// The state to give as input to .
+ /// The predicatee to use to match the parent nodes.
+ /// The parent that was found, or .
+ public static T? FindParent(this FrameworkElement element, TState state, Func predicate)
+ where T : notnull, FrameworkElement
+ {
+ PredicateByFunc predicateByFunc = new (state, predicate);
+
+ return FindParent>(element, ref predicateByFunc);
+ }
+
+ ///
+ /// Find the first parent element matching a given predicate.
+ ///
+ /// The type of elements to match.
+ /// The type of predicate in use.
+ /// The starting element.
+ /// The predicatee to use to match the parent nodes.
+ /// The parent that was found, or .
+ private static T? FindParent(this FrameworkElement element, ref TPredicate predicate)
+ where T : notnull, FrameworkElement
+ where TPredicate : struct, IPredicate
+ {
+ while (true)
+ {
+ if (element.Parent is not FrameworkElement parent)
+ {
+ return null;
+ }
+
+ if (parent is T result && predicate.Match(result))
+ {
+ return result;
+ }
+
+ element = parent;
+ }
+ }
+
+ ///
+ /// Find the first parent (or self) of type with a given name.
+ ///
+ /// The starting element.
+ /// The name of the element to look for.
+ /// The comparison type to use to match .
+ /// The parent (or self) that was found, or .
+ public static FrameworkElement? FindParentOrSelf(this FrameworkElement element, string name, StringComparison comparisonType = StringComparison.Ordinal)
+ {
+ if (name.Equals(element.Name, comparisonType))
+ {
+ return element;
+ }
+
+ return FindParent(element, name, comparisonType);
+ }
+
+ ///
+ /// Find the first parent (or self) element of a given type.
+ ///
+ /// The type of elements to match.
+ /// The starting element.
+ /// The parent (or self) that was found, or .
+ public static T? FindParentOrSelf(this FrameworkElement element)
+ where T : notnull, FrameworkElement
+ {
+ if (element is T result)
+ {
+ return result;
+ }
+
+ return FindParent(element);
+ }
+
+ ///
+ /// Find the first parent (or self) element of a given type.
+ ///
+ /// The starting element.
+ /// The type of element to match.
+ /// The parent (or self) that was found, or .
+ public static FrameworkElement? FindParentOrSelf(this FrameworkElement element, Type type)
+ {
+ if (element.GetType() == type)
+ {
+ return element;
+ }
+
+ return FindParent(element, type);
+ }
+
+ ///
+ /// Find the first parent (or self) element matching a given predicate.
+ ///
+ /// The type of elements to match.
+ /// The starting element.
+ /// The predicatee to use to match the parent nodes.
+ /// The parent (or self) that was found, or .
+ public static T? FindParentOrSelf(this FrameworkElement element, Func predicate)
+ where T : notnull, FrameworkElement
+ {
+ if (element is T result && predicate(result))
+ {
+ return result;
+ }
+
+ return FindParent(element, predicate);
+ }
+
+ ///
+ /// Find the first parent (or self) element matching a given predicate.
+ ///
+ /// The type of elements to match.
+ /// The type of state to use when matching nodes.
+ /// The starting element.
+ /// The state to give as input to .
+ /// The predicatee to use to match the parent nodes.
+ /// The parent (or self) that was found, or .
+ public static T? FindParentOrSelf(this FrameworkElement element, TState state, Func predicate)
+ where T : notnull, FrameworkElement
+ {
+ if (element is T result && predicate(result, state))
+ {
+ return result;
+ }
+
+ return FindParent(element, state, predicate);
+ }
+
+ ///
+ /// Find all parent elements of the specified element. This method can be chained with
+ /// LINQ calls to add additional filters or projections on top of the returned results.
+ ///
+ /// This method is meant to provide extra flexibility in specific scenarios and it should not
+ /// be used when only the first item is being looked for. In those cases, use one of the
+ /// available overloads instead, which will
+ /// offer a more compact syntax as well as better performance in those cases.
+ ///
+ ///
+ /// The root element.
+ /// All the parent instance from .
+ public static IEnumerable FindParents(this FrameworkElement element)
+ {
+ while (true)
+ {
+ if (element.Parent is not FrameworkElement parent)
+ {
+ yield break;
+ }
+
+ yield return parent;
+
+ element = parent;
+ }
+ }
+
+ ///
+ /// Gets the content property of this element as defined by , if available.
+ ///
+ /// The parent element.
+ /// The retrieved content control, or if not available.
+ #if NET8_0_OR_GREATER
+ [System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "This method is currently not safe for trimming, and annotations here wouldn't help.")]
+ #endif
+ public static UIElement? GetContentControl(this FrameworkElement element)
+ {
+ Type type = element.GetType();
+ TypeInfo? typeInfo = type.GetTypeInfo();
+
+ while (typeInfo is not null)
+ {
+ // We need to manually explore the custom attributes this way as the target one
+ // is not returned by any of the other available GetCustomAttribute APIs.
+ foreach (CustomAttributeData attribute in typeInfo.CustomAttributes)
+ {
+ if (attribute.AttributeType == typeof(ContentPropertyAttribute))
+ {
+ // If we're finding a ContentPropertyAttribute, this whole path should be set,
+ // don't think we need additional checks here.
+ string propertyName = (string)attribute.NamedArguments![0].TypedValue!.Value!;
+ PropertyInfo? propertyInfo = type.GetProperty(propertyName);
+
+ return propertyInfo?.GetValue(element) as UIElement;
+ }
+ }
+
+ typeInfo = typeInfo.BaseType?.GetTypeInfo();
+ }
+
+ return null;
+ }
+
+ ///
+ /// Provides a WPF compatible version of FindResource to provide a static resource lookup.
+ /// If the key is not found in the current element's resources, the logical tree is then
+ /// searched element-by-element to look for the resource in each element's resources.
+ /// If none of the elements contain the resource, the Application's resources are then searched.
+ /// See: .
+ /// And also: .
+ ///
+ /// The to start searching for the target resource.
+ /// The resource key to search for.
+ /// The requested resource.
+ /// Thrown when no resource is found with the specified key.
+ public static object FindResource(this FrameworkElement element, object resourceKey)
+ {
+ if (TryFindResource(element, resourceKey, out object? value))
+ {
+ return value!;
+ }
+
+ static object Throw(object resourceKey) => throw new KeyNotFoundException($"No resource was found with the key \"{resourceKey}\"");
+
+ return Throw(resourceKey);
+ }
+
+ ///
+ /// Provides a WPF compatible version of TryFindResource to provide a static resource lookup.
+ /// If the key is not found in the current element's resources, the logical tree is then
+ /// searched element-by-element to look for the resource in each element's resources.
+ /// If none of the elements contain the resource, the Application's resources are then searched.
+ /// See: .
+ /// And also: .
+ ///
+ /// The to start searching for the target resource.
+ /// The resource key to search for.
+ /// The requested resource, or if it wasn't found.
+ public static object? TryFindResource(this FrameworkElement element, object resourceKey)
+ {
+ object? value = null;
+
+ FrameworkElement? current = element;
+
+ // Look in our dictionary and then walk-up parents. We use a do-while loop here
+ // so that an implicit NRE will be thrown at the first iteration in case the
+ // input element is null. This is consistent with the other extensions.
+ do
+ {
+ if (current.Resources?.TryGetValue(resourceKey, out value) == true)
+ {
+ return value;
+ }
+
+ current = current.Parent as FrameworkElement;
+ }
+ while (current is not null);
+
+ // Finally try application resources
+ _ = Application.Current?.Resources?.TryGetValue(resourceKey, out value);
+
+ return value;
+ }
+
+ ///
+ /// Provides a WPF compatible version of TryFindResource to provide a static resource lookup.
+ /// If the key is not found in the current element's resources, the logical tree is then
+ /// searched element-by-element to look for the resource in each element's resources.
+ /// If none of the elements contain the resource, the Application's resources are then searched.
+ /// See: .
+ /// And also: .
+ ///
+ /// The to start searching for the target resource.
+ /// The resource key to search for.
+ /// The resulting value, if present.
+ /// Whether or not a value with the specified key has been found.
+ public static bool TryFindResource(this FrameworkElement element, object resourceKey, out object? value)
+ {
+ return (value = TryFindResource(element, resourceKey)) is not null;
+ }
+}