views:

143

answers:

2

Anybody know how to list the the attached properties that have been set on a UIElement in Silveright 3? Plenty of WPF solutions as usual!

Cheers

+1  A: 

The short answer is: it can't be done.

Silverlight's DependencyObject does not have a GetLocalValueEnumerator which enables this for WPF. In fact the only method which offers a glimmer is the ReadLocalValue.

Hence if you are actually only interested in a specific sub-set of the properties you could try each one in turn through the ReadLocalValue. Highly unsatisfactory for the general requirement though.

I'm curious, what would drive such a requirement in the first place?

AnthonyWJones
A: 

A pretty horrible brute force brittle implementation I decided to go with was as follows: Scan through the loaded assemblies searching for dependency properties. If there was a dependency property with a corresponding Getxxx/Setxxx public static method then it was an attached property. Obviously it has lots of holes but it will do me for now.

The reason I want to get a list of the attached properties is so I can look at what attached properties are set on an object @ runtime and change them, just for debugging.

Code below:

public static List<DependencyProperty> GetAttachedProperties(Object element)
    {
        List<DependencyProperty> attachedProperties = new List<DependencyProperty>();

        foreach (AssemblyPart ap in Deployment.Current.Parts)
        {
            StreamResourceInfo sri = Application.GetResourceStream(new Uri(ap.Source, UriKind.Relative));
            Assembly a = new AssemblyPart().Load(sri.Stream);
            GetAttachedProperties(a, attachedProperties);
        }


        return attachedProperties;

    }

    private static void GetAttachedProperties(Assembly a, List<DependencyProperty> attachedProperties)
    {
        foreach (var type in a.GetTypes())
        {
            Debug.WriteLine(type.FullName);
            var dependencyProperties = type.GetFields(BindingFlags.Static | BindingFlags.Public).Where(
                f => typeof (DependencyProperty).IsAssignableFrom(f.FieldType)).Select(f => f);
            foreach (var dp in dependencyProperties)
            {
                FieldInfo info = dp;
                var methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public);
                Debug.WriteLine("{0} suitable dp methods found", methods.Count());
                var fields = methods.Where(
                    m => (IsAttachedGetter(m, info) || IsAttachedSetter(m, info))).Select(
                    m => info).ToArray();
                foreach(var field in fields)
                {
                    try
                    {
                        Debug.WriteLine("Adding dependency property {0} from type {1}", dp.Name, type.FullName);
                        attachedProperties.Add((DependencyProperty)field.GetValue(null));
                    }
                    catch (Exception e)
                    {
                        Debug.WriteLine("Error getting dependency property {0} from type {1}, exception: {2}",
                            dp.Name, type.FullName, e);
                    }
                }
            }
        }
    }

    private static bool IsAttachedSetter(MethodInfo methodInfo, FieldInfo info)
    {
        string setName = string.Format("Set{0}", info.Name.Replace("Property", string.Empty));
        if(methodInfo.Name == setName)
        {
            var methodParams = methodInfo.GetParameters();
            return methodParams.Count() == 2
                   && typeof (DependencyObject).IsAssignableFrom(methodParams[0].ParameterType);
        }
        return false;
    }

    private static bool IsAttachedGetter(MethodInfo methodInfo, FieldInfo info)
    {
        string getName = string.Format("Get{0}", info.Name.Replace("Property", string.Empty));
        if(methodInfo.Name == getName)
        {
            var methodParams = methodInfo.GetParameters();
            return methodParams.Count() == 1 &&
                   methodParams[0].ParameterType.IsAssignableFrom(typeof (DependencyObject));
        }
        return false;
    }
moosecode