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;
}
}
}
}
}
}
}