tags:

views:

325

answers:

3

Essentially I want some simple reflection where I have an arbitrary DependencyProperty as a parameter. I'd have a special case (in an if statement, for example) if DependencyProperty is defined by / property of a PlaneProjection. I've done some simple fandangling of GetType() but no luck with the expected getters like MemberType.

public void SomeFunc(DependencyProperty dp)
{
    // if dp is a dependency property of plane projection, do something
    // would maybe look like PlaneProjection.hasProperty(dp)
}
A: 

Does this condition catch it?

Edit: Only in WPF - not SilverLight.

dp.OwnerType.IsAssignableFrom(typeof(PlaneProjection))
280Z28
Unfortunately it doesn't. You would expect PlaneProjection.CenterOfRotationXProperty.GetType().IsAssignableFrom(typeof(PlaneProjection) to return True, but this call always returns False.
roblocop
The `OwnerType` property and the `GetType()` method are very different. If `OwnerType` is available in SilverLight (it is in WPF), then that's what you want.
280Z28
Yeah, it seems like the OwnerType property is unavailable in Silverlight. Would have been useful!
roblocop
+1  A: 

Try this code with extension methods:

public static class Helpers
{
    public static DependencyProperty FindDependencyProperty(this DependencyObject target, string propName)
    {
        FieldInfo fInfo = target.GetType().GetField(propName, BindingFlags.Static | BindingFlags.FlattenHierarchy | BindingFlags.Public);

        if (fInfo == null) return null;

        return (DependencyProperty)fInfo.GetValue(null);
    }

    public static bool HasDependencyProperty(this DependencyObject target, string propName)
    {
        return FindDependencyProperty(target, propName) != null;
    }

    public static string GetStaticMemberName<TMemb>(Expression<Func<TMemb>> expression)
    {
        var body = expression.Body as MemberExpression;

        if (body == null) throw new ArgumentException("'expression' should be a member expression");

        return body.Member.Name;
    }
}

Usage:

planeProjection1.HasDependecyProperty(
    Helpers.GetStaticMemberName(() => PlaneProjection.CenterOfRotationXProperty));
kek444
Although watch out for the BindingFlags.FlattenHierarchy if you only want to detect DPs declared on this class, as that gets all inherited DPs, from FrameworkElement for example.
mattmanser
Well, it doesn't "get" them, it only checks among all inherited fields. It should be the default, to be able to get "Width" and similar inherited properties.
kek444
Well I couldn't get this to work with my case. Specifically, I should be able to say something like: PlaneProjection pp = new PlaneProjection(); pp.HasDependencyProperty(PlaneProjection.CenterOfRotationXProperty); // this returned null. However, I had to change HasDependencyProperty's call to FindDependencyProperty(target, prop.GetType().Name) to get it to compile correctly.
roblocop
You are right, I forgot about differences between wpf and silverlight; fixed my post, this should work now
kek444
HasDependencyProperty always returns false.PlaneProjection pp = new PlaneProjection();pp.HasDependencyProperTety(PlaneProjection.CenterOfRotationXProperty); // returns false, expect trueI think this could be since PlaneProjection.CenterOfRotationXProperty.GetType().Name returns "CoreDependencyProperty" and a string like "CenterOfRotationXProperty". It seems like FindDependencyProperty is fine and works with the call pp.FindDependencyProperty("CenterOfRotationXProperty"). The trouble is how to get that property name as a string. Usual ToString() calls return "CoreDependencyProperty"
roblocop
Try this approach with static reflection for getting member name as string. Good Luck!
kek444
Sorry for the confusion, but when using static reflection with a variable DependencyProperty dp (like in the original question), what's returned is the string "dp" and not something like "CenterOfRotationXProperty".
roblocop
The static reflection indeed returns the member declared name. I'm not sure what is the problem here. Could you post your "dp" and "CenterOfRotationXProperty" as you declare them in your class?
kek444
I specifically want to be able to test against any DependencyProperty. For example, public static string GetName(DependencyProperty dp) { return GetStaticMemberName(() => dp); }Always returns "dp", say for example GetName(PlaneProjection.CenterOfRotationXProperty). I want to be able to test if any arbitrary DependencyProperty belongs to PlaneProjection, then I create a PlaneProjection instance and set that property on it.
roblocop
Ahh, there we are -> you cannot encapsulate the GetStaticMemberName - you MUST use it with lambda expressions, no other way will it work. It extracts the name directly from the expression, it must be in the form of GetStaticMemberName(() => PlaneProjection.CenterOfRotationXProperty).
kek444
A: 

This should take care of your needs in SilverLight:

private static readonly Dictionary<DependencyProperty, Type> _ownerCache = new Dictionary<DependencyProperty, Type>();
// normally you'd use a HashSet<DependencyProperty>, but it's not available in SilverLight
private static readonly Dictionary<Type, Dictionary<DependencyProperty, bool>> _excludeCache = new Dictionary<Type, Dictionary<DependencyProperty, bool>>();

public static bool IsOwnedByTypeOrParent(DependencyProperty dp, Type type)
{
    lock (_ownerCache)
    {
        Type owner;
        if (_ownerCache.TryGetValue(dp, out owner))
            return owner.IsAssignableFrom(type);

        Dictionary<DependencyProperty, bool> exclude;
        if (_excludeCache.TryGetValue(type, out exclude))
        {
            if (exclude.ContainsKey(dp))
                return false;
        }

        FieldInfo[] fields = type.GetFields(BindingFlags.Static | BindingFlags.FlattenHierarchy);
        foreach (FieldInfo field in fields)
        {
            if (typeof(DependencyProperty).IsAssignableFrom(field.FieldType))
            {
                try
                {
                    object value = field.GetValue(null);
                    if (object.ReferenceEquals(dp, value))
                    {
                        _ownerCache[dp] = field.DeclaringType;
                        return true;
                    }
                }
                catch
                {
                }
            }
        }

        if (exclude == null)
        {
            exclude = new Dictionary<DependencyProperty, bool>();
            _excludeCache[type] = exclude;
        }

        exclude.Add(dp, false);

        /* optional if you want to minimize memory overhead. unnecessary unless
         * you are using this on enormous numbers of types/DPs
         */
        foreach (var item in _excludeCache)
        {
            item.Value.Remove(dp);
        }

        return false;
    }
}
280Z28