2010-10-18 166 views

回答

11

试试这个。首先,在您的项目中复制粘贴此DependencyObjectHelper类。它有一个函数可以让你获得给定对象中的所有BindingObjects。

public static class DependencyObjectHelper 
{ 
    public static List<BindingBase> GetBindingObjects(Object element) 
    { 
     List<BindingBase> bindings = new List<BindingBase>(); 
     List<DependencyProperty> dpList = new List<DependencyProperty>(); 
     dpList.AddRange(DependencyObjectHelper.GetDependencyProperties(element)); 
     dpList.AddRange(DependencyObjectHelper.GetAttachedProperties(element)); 

     foreach (DependencyProperty dp in dpList) 
     { 
      BindingBase b = BindingOperations.GetBindingBase(element as DependencyObject, dp); 
      if (b != null) 
      { 
       bindings.Add(b); 
      } 
     } 

     return bindings; 
    } 

    public static List<DependencyProperty> GetDependencyProperties(Object element) 
    { 
     List<DependencyProperty> properties = new List<DependencyProperty>(); 
     MarkupObject markupObject = MarkupWriter.GetMarkupObjectFor(element); 
     if (markupObject != null) 
     { 
      foreach (MarkupProperty mp in markupObject.Properties) 
      { 
       if (mp.DependencyProperty != null) 
       { 
        properties.Add(mp.DependencyProperty); 
       } 
      } 
     } 

     return properties; 
    } 

    public static List<DependencyProperty> GetAttachedProperties(Object element) 
    { 
     List<DependencyProperty> attachedProperties = new List<DependencyProperty>(); 
     MarkupObject markupObject = MarkupWriter.GetMarkupObjectFor(element); 
     if (markupObject != null) 
     { 
      foreach (MarkupProperty mp in markupObject.Properties) 
      { 
       if (mp.IsAttached) 
       { 
        attachedProperties.Add(mp.DependencyProperty); 
       } 
      } 
     } 

     return attachedProperties; 
    } 
} 

然后,创建这个GetBindingSourcesRecursive功能。它递归地收集可视树中的DependencyObjects,该可视树至少有一个绑定对象,其目标是给定的属性名称。

private void GetBindingSourcesRecursive(string propertyName, DependencyObject root, List<object> sources) 
{ 
    List<BindingBase> bindings = DependencyObjectHelper.GetBindingObjects(root); 
    Predicate<Binding> condition = 
     (b) => 
     { 
      return (b.Path is PropertyPath) 
       && (((PropertyPath)b.Path).Path == propertyName) 
       && (!sources.Contains(root)); 
     }; 

    foreach (BindingBase bindingBase in bindings) 
    { 
     if (bindingBase is Binding) 
     { 
      if (condition(bindingBase as Binding)) 
       sources.Add(root); 
     } 
     else if (bindingBase is MultiBinding) 
     { 
      MultiBinding mb = bindingBase as MultiBinding; 
      foreach (Binding b in mb.Bindings) 
      { 
       if (condition(bindingBase as Binding)) 
        sources.Add(root); 
      } 
     } 
     else if (bindingBase is PriorityBinding) 
     { 
      PriorityBinding pb = bindingBase as PriorityBinding; 
      foreach (Binding b in pb.Bindings) 
      { 
       if (condition(bindingBase as Binding)) 
        sources.Add(root); 
      } 
     } 
    } 

    int childrenCount = VisualTreeHelper.GetChildrenCount(root); 
    if (childrenCount > 0) 
    { 
     for (int i = 0; i < childrenCount; i++) 
     { 
      DependencyObject child = VisualTreeHelper.GetChild(root, i); 
      GetBindingSourcesRecursive(propertyName, child, sources); 
     } 
    } 
} 

然后,使用此,只需调用GetBindingsRecursive传入属性名,根视觉(例如,窗口),并且将包含结果的对象列表。

List<object> sources = new List<object>(); 
GetBindingSourcesRecursive("SomePropertyPath", this, sources); 
sources.ForEach((o) => Console.WriteLine(o.ToString())); 

希望这会有所帮助。

3

我根据接受的ASanch答案创建了代码。这段代码使用了LogicalTreeHelper,它使它快6倍(当在简单的窗口中寻找具有特定绑定的控件时,130ms vs 20ms)。

加上我修复ASanch代码一些错误(看原“否则,如果(bindingBase是MultiBinding)”“否则,如果(bindingBase是PriorityBinding)”)。

public static class DependencyObjectHelper 
{ 
    /// <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>(); 
     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>(); 
     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); 
     } 
    } 
} 
+0

代码的性能很好! – 2017-07-29 10:04:58