using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Media; namespace WPFluent.Controls.Primitives; public static class VisualTree { public static FrameworkElement? FindDescendantByName(this DependencyObject element, string name) { if (element == null || string.IsNullOrWhiteSpace(name)) { return null; } if (name.Equals((element as FrameworkElement)?.Name, StringComparison.OrdinalIgnoreCase)) { return element as FrameworkElement; } var childrenCount = VisualTreeHelper.GetChildrenCount(element); for (var i = 0; i < childrenCount; i++) { var frameworkElement = VisualTreeHelper.GetChild(element, i).FindDescendantByName(name); if (frameworkElement != null) { return frameworkElement; } } return null; } public static T? FindDescendant(this DependencyObject element) where T : DependencyObject { T? val = null; var childrenCount = VisualTreeHelper.GetChildrenCount(element); for (var i = 0; i < childrenCount; i++) { var child = VisualTreeHelper.GetChild(element, i); if (child is T val2) { val = val2; break; } val = child.FindDescendant(); if (val != null) { break; } } return val; } public static object? FindDescendant(this DependencyObject element, Type type) { object? obj = null; var childrenCount = VisualTreeHelper.GetChildrenCount(element); for (var i = 0; i < childrenCount; i++) { var child = VisualTreeHelper.GetChild(element, i); if (child.GetType() == type) { obj = child; break; } obj = child.FindDescendant(type); if (obj != null) { break; } } return obj; } public static IEnumerable FindDescendants(this DependencyObject element) where T : DependencyObject { var childrenCount = VisualTreeHelper.GetChildrenCount(element); for (var i = 0; i < childrenCount; i++) { var child = VisualTreeHelper.GetChild(element, i); if (child is T val) { yield return val; } foreach (var item in child.FindDescendants()) { yield return item; } } } public static FrameworkElement? FindAscendantByName(this DependencyObject element, string name) { if (element == null || string.IsNullOrWhiteSpace(name)) { return null; } var parent = VisualTreeHelper.GetParent(element); if (parent == null) { return null; } if (name.Equals((parent as FrameworkElement)?.Name, StringComparison.OrdinalIgnoreCase)) { return parent as FrameworkElement; } return parent.FindAscendantByName(name); } public static T? FindAscendant(this DependencyObject element) where T : DependencyObject { var parent = VisualTreeHelper.GetParent(element); if (parent == null) { return null; } if (parent is T) { return parent as T; } return parent.FindAscendant(); } public static object? FindAscendant(this DependencyObject element, Type type) { var parent = VisualTreeHelper.GetParent(element); if (parent == null) { return null; } if (parent.GetType() == type) { return parent; } return parent.FindAscendant(type); } public static IEnumerable FindAscendants(this DependencyObject element) { for (var parent = VisualTreeHelper.GetParent(element); parent != null; parent = VisualTreeHelper.GetParent(parent)) { yield return parent; } } public static bool DetachFromParent(this FrameworkElement element, DependencyObject parent) { try { if (parent is Panel panel) { panel.Children.Remove(element); return true; } if (parent is Decorator decorator) { if (decorator.Child == element) { decorator.Child = null; return true; } } else { if (parent is ContentControl contentControl) { contentControl.Content = null; return true; } if (parent is ContentPresenter contentPresenter) { contentPresenter.Content = null; return true; } if (parent is Popup popup) { popup.Child = null; return true; } if (parent is ItemsControl itemsControl) { if (itemsControl.Items.Contains(element)) { itemsControl.Items.Remove(element); return true; } if (itemsControl.Items.Contains(element.DataContext)) { itemsControl.Items.Remove(element.DataContext); return true; } } else { var type = parent.GetType(); var bindingAttr = BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public; List obj = [ type.GetProperty("Children", bindingAttr), type.GetProperty("Child", bindingAttr), type.GetProperty("Content", bindingAttr), type.GetProperty("Items", bindingAttr) ]; var flag = false; foreach (var item in obj) { switch (item.Name.ToLower()) { case "children": { var value = item.GetValue(parent, null); var methods = value?.GetType().GetMethods() ?? []; foreach (var methodInfo in methods) { if (methodInfo.Name.ToLower() == "remove") { methodInfo.Invoke(value, [element]); flag = true; } } break; } case "child": case "content": if (item.GetValue(parent) == element) { item.SetValue(parent, null); flag = true; } break; } } if (flag) { return true; } } } } catch { if (Debugger.IsAttached) { throw; } } return false; } public static bool DetachFromLogicalParent(this FrameworkElement element) { var parent = element.Parent; element.DetachFromParent(parent); return element.Parent != parent; } public static bool DetachFromVisualParent(this FrameworkElement element) { var parent = VisualTreeHelper.GetParent(element); element.DetachFromParent(parent); return VisualTreeHelper.GetParent(element) != parent; } }