views:

33

answers:

1

Any ideas on how to implement a method that given a propertyname, finds a control (perhaps from a visualtree) which is bound to the given property?

A: 

Try this one. First, copy-paste this DependencyObjectHelper class in your project. It has a function that allows you to get all the BindingObjects in a given object.

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

Then, create this GetBindingSourcesRecursive function. It recursively collects the DependencyObjects in the visual tree that has at least one Binding object targetting a given property name.

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

Then, to use this, just call GetBindingsRecursive passing in the property name, the root visual (e.g. the Window), and an object list that will contain the results.

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

Hope this helps.

karmicpuppet