// Copyright (c) 2017 schick Informatik // Description: Validation / Highlighting helper class // using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Data; using System.Windows.Markup.Primitives; using bsmd.database; namespace ENI2.Util { class ValidationContext { private BindingExpression _bindingExpression; private UIElement _uiElement; public ValidationContext(BindingExpression bindingExpression, UIElement anUIElement) { _bindingExpression = bindingExpression; _uiElement = anUIElement; } #region Properties public BindingExpression BindingExpression { get { return this._bindingExpression; } } public UIElement UIElement { get { return this._uiElement; } } #endregion #region static creation /// /// Rekursive Funktion mit Reflection /// /// /// /// /// private static ValidationContext GetBindingForProperty(Type boundType, string boundPropertyName, FrameworkElement root) { foreach (FrameworkElement element in LogicalTreeHelper.GetChildren(root).OfType()) { FieldInfo[] properties = element.GetType().GetFields(BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.FlattenHierarchy); // | BindingFlags.Static foreach (FieldInfo field in properties) { if (field.FieldType == typeof(DependencyProperty)) { DependencyProperty dp = (DependencyProperty)field.GetValue(null); if (BindingOperations.IsDataBound(element, dp)) { BindingExpression bindingExpression = BindingOperations.GetBindingExpression(element, dp); if (boundType == bindingExpression.DataItem.GetType()) { if (boundPropertyName == bindingExpression.ParentBinding.Path.Path) { return new ValidationContext(bindingExpression, element as UIElement); } } } } } // Not found so check all child elements ValidationContext bindingContext = GetBindingForProperty(boundType, boundPropertyName, element); if (bindingContext != null) return bindingContext; } return null; } #endregion /// /// Gets all dependency objects which has binding to specific property /// /// /// /// public static IList GetDependencyObjectsWithBindingToProperty(DependencyObject dependencyObject, string propertyName) { var list = new List(); ValidationContext.GetDependencyObjectsWithBindingToPropertyRecursive(propertyName, dependencyObject, list); return list; } /// /// /// /// /// /// /// /// Based on ASanch answer on http://stackoverflow.com/questions/3959421/wpf-find-control-that-binds-to-specific-property /// > private static void GetDependencyObjectsWithBindingToPropertyRecursive(string propertyName, DependencyObject dependencyObject, ICollection sources) { var dependencyProperties = new List(); if ((dependencyObject == null) || (propertyName.IsNullOrEmpty())) return; // sanity dependencyProperties.AddRange(MarkupWriter.GetMarkupObjectFor(dependencyObject).Properties.Where(x => x.DependencyProperty != null).Select(x => x.DependencyProperty).ToList()); dependencyProperties.AddRange(MarkupWriter.GetMarkupObjectFor(dependencyObject).Properties.Where(x => x.IsAttached && x.DependencyProperty != null).Select(x => x.DependencyProperty).ToList()); var bindings = dependencyProperties.Select(x => BindingOperations.GetBindingBase(dependencyObject, x)).Where(x => x != null).ToList(); Predicate condition = binding => binding != null && binding.Path.Path == propertyName && !sources.Contains(dependencyObject); foreach (var bindingBase in bindings) { if (bindingBase is Binding) { if (condition(bindingBase as Binding)) sources.Add(dependencyObject); } else if (bindingBase is MultiBinding) { if (((MultiBinding)bindingBase).Bindings.Any(bindingBase2 => condition(bindingBase2 as Binding))) { sources.Add(dependencyObject); } } else if (bindingBase is PriorityBinding) { if (((PriorityBinding)bindingBase).Bindings.Any(bindingBase2 => condition(bindingBase2 as Binding))) { sources.Add(dependencyObject); } } } var children = LogicalTreeHelper.GetChildren(dependencyObject).OfType().ToList(); if (children.Count == 0) return; foreach (var child in children) { GetDependencyObjectsWithBindingToPropertyRecursive(propertyName, child, sources); } } } }