WPF。查找绑定到特定属性的控件

时间:2010-10-18 13:05:14

标签: wpf data-binding binding

关于如何实现给定属性名的方法的任何想法,找到绑定到给定属性的控件(可能来自visualtree)?

2 个答案:

答案 0 :(得分: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,其中至少有一个Binding对象以给定的属性名称为目标。

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 传递属性名称,根视觉(例如Window)和包含结果的对象列表。

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

希望这有帮助。

答案 1 :(得分:3)

我根据公认的ASanch答案创建了代码。这段代码使用了LogicalTreeHelper,它使得它的速度提高了6倍(在简单窗口上寻找具有特定绑定的控件时,130ms对20ms)。

另外我修复了ASanch代码中的一些错误(查看原始&#34;否则if(bindingBase是MultiBinding)&#34; &#34;否则if(bindingBase是PriorityBinding)&#34;

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