using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Media.Media3D; namespace BrightSharp.Extensions { public static class WpfExtensions { /// /// Returns Parent item of DependencyObject /// /// Child object /// Prefer LogicalTree when need. /// Found item public static DependencyObject GetParent(this DependencyObject obj, bool useLogicalTree = false) { if (!useLogicalTree && (obj is Visual || obj is Visual3D)) return VisualTreeHelper.GetParent(obj) ?? LogicalTreeHelper.GetParent(obj); else return LogicalTreeHelper.GetParent(obj); } public static IEnumerable GetAncestors(this DependencyObject obj, bool useLogicalTree = false) where T : DependencyObject { if (obj == null) yield break; var x = GetParent(obj, useLogicalTree); while (x != null && !(x is T)) { x = GetParent(x, useLogicalTree); } if (x != null) yield return x as T; else yield break; foreach (var item in GetAncestors(x, useLogicalTree)) { yield return item; } } public static T FindAncestor(this DependencyObject obj) where T : DependencyObject { return GetAncestors(obj).FirstOrDefault(); } /// /// Try find ItemsPanel of ItemsControl /// /// Where to search /// Panel of ItemsControl public static Panel GetItemsPanel(DependencyObject itemsControl) { if (itemsControl is Panel) return (Panel)itemsControl; ItemsPresenter itemsPresenter = FindVisualChildren(itemsControl).FirstOrDefault(); if (itemsPresenter == null) return null; var itemsPanel = VisualTreeHelper.GetChild(itemsPresenter, 0) as Panel; return itemsPanel; } /// /// Check if object is valid (no errors found in logical children) /// /// Object to search /// True if no errors found public static bool IsValid(this DependencyObject obj) { if (obj == null) return true; if (Validation.GetHasError(obj)) return false; foreach (var child in LogicalTreeHelper.GetChildren(obj).OfType()) { if (child == null) continue; if (child is UIElement ui) { if (!ui.IsVisible || !ui.IsEnabled) continue; } if (!IsValid(child)) return false; } return true; } /// /// Search all textboxes to update invalid with UpdateSource(). For ex. when need update validation messages. /// /// Object where to search TextBoxes public static void UpdateSources(this DependencyObject obj) { if (obj == null) return; if (Validation.GetHasError(obj)) { //TODO Any types? if (obj is TextBox tb) tb.GetBindingExpression(TextBox.TextProperty)?.UpdateSource(); } foreach (var item in FindLogicalChildren(obj)) { UpdateSources(item); } } /// /// Find all visual children of type T /// /// Type to search /// Object where to search /// Enumerator for items public static IEnumerable FindVisualChildren(this DependencyObject depObj) where T : DependencyObject { if (depObj != null && (depObj is Visual || depObj is Visual3D)) { for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++) { DependencyObject child = VisualTreeHelper.GetChild(depObj, i); if (child != null && child is T) { yield return (T)child; } foreach (T childOfChild in FindVisualChildren(child)) { yield return childOfChild; } } } } /// /// Find all logical children of type T /// /// Type to search /// Object where to search /// Enumerator for items public static IEnumerable FindLogicalChildren(this DependencyObject depObj) where T : DependencyObject { if (depObj != null) { foreach (object rawChild in LogicalTreeHelper.GetChildren(depObj)) { if (rawChild is DependencyObject child) { if (child is T) { yield return (T)child; } foreach (T childOfChild in FindLogicalChildren(child)) { yield return childOfChild; } } } } } } }