git_bsmd/ENI2/Util/ValidationContext.cs

150 lines
6.2 KiB
C#

// 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
/// <summary>
/// Rekursive Funktion mit Reflection
/// </summary>
/// <param name="boundType"></param>
/// <param name="boundPropertyName"></param>
/// <param name="root"></param>
/// <returns></returns>
private static ValidationContext GetBindingForProperty(Type boundType, string boundPropertyName, FrameworkElement root)
{
foreach (FrameworkElement element in LogicalTreeHelper.GetChildren(root).OfType<FrameworkElement>())
{
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
/// <summary>
/// Gets all dependency objects which has binding to specific property
/// </summary>
/// <param name="dependencyObject"></param>
/// <param name="propertyName"></param>
/// <returns></returns>
public static IList<DependencyObject> GetDependencyObjectsWithBindingToProperty(DependencyObject dependencyObject, string propertyName)
{
var list = new List<DependencyObject>();
ValidationContext.GetDependencyObjectsWithBindingToPropertyRecursive(propertyName, dependencyObject, list);
return list;
}
/// <summary>
///
/// </summary>
/// <param name="propertyName"></param>
/// <param name="dependencyObject"></param>
/// <param name="sources"></param>
/// <remarks>
/// Based on ASanch answer on http://stackoverflow.com/questions/3959421/wpf-find-control-that-binds-to-specific-property
/// </remarks>>
private static void GetDependencyObjectsWithBindingToPropertyRecursive(string propertyName, DependencyObject dependencyObject,
ICollection<DependencyObject> sources)
{
var dependencyProperties = new List<DependencyProperty>();
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<Binding> 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<DependencyObject>().ToList();
if (children.Count == 0)
return;
foreach (var child in children)
{
GetDependencyObjectsWithBindingToPropertyRecursive(propertyName, child, sources);
}
}
}
}