2010-10-18 15 views

Odpowiedz

11

Wypróbuj tę. Najpierw skopiuj i wklej tę klasę DependencyObjectHelper do swojego projektu. Ma funkcję, która pozwala uzyskać wszystkie BindingObjects w danym obiekcie.

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

Następnie należy utworzyć ten GetBindingSourcesRecursive funkcję. Rekursywnie gromadzi obiekty DependencyObjects w drzewie wizualnym, które ma co najmniej jeden obiekt wiążący, który ma przypisaną nazwę właściwości.

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

Następnie, aby to wykorzystać, po prostu zadzwoń GetBindingsRecursive przekazując nazwy właściwości, korzeń wizualny (np okna), oraz listę obiekt, który będzie zawierał wyniki.

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

Mam nadzieję, że to pomoże.

3

Utworzono kod na podstawie zaakceptowanej odpowiedzi ASanch. Ten kod używa LogicalTreeHelper, który sprawia, że ​​jest 6 razy szybszy (130ms vs 20ms przy szukaniu kontroli ze specyficznym wiązaniem w prostym oknie).

Plus naprawić niektóre błędy w kodzie ASanch (spojrzeć na oryginalny "else if (bindingBase jest MultiBinding)" lub "else if (bindingBase jest 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

Wydajność kodu jest świetna! –

Powiązane problemy