Getting list of all dependency/attached properties of an Object
- In Visual Studio, in the XAML view when we add a element tag say <Rectangle...> and hit the spacebar, we get a list of all the attached properties and dependency properties of the object. (For e.g. Canvas.Left).
How can this be achieved through procedural code ? I tried using Reflection (on a Rectangle object in above case) but it did not help.
Thanks,
Niranjan
Answers
- Well, Doug's code is awesome, but what the original poster want to do is get all the attached DPs applied to a specified object, then you can use the following helper methods I create:
public static class DependencyObjectHelper
{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;
}}
Sheva Actually I thought I found a slightly more elegant solution:
public IList<DependencyProperty> GetAttachedProperties(DependencyObject obj) { List<DependencyProperty> attached = new List<DependencyProperty>(); foreach (PropertyDescriptor pd in TypeDescriptor.GetProperties(obj, new Attribute[] { new PropertyFilterAttribute(PropertyFilterOptions.All) })) { DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(pd); if (dpd != null && dpd.IsAttached) { attached.Add(dpd.DependencyProperty); } } return attached; }
But, it would appear this will not give any DP's which we define.
- Doug
All Replies
- Attached properties that appear in Intellisense don't really have anything to do with the object that are attached to. For instance, when you create a <Rectangle> and see Canvas.Left in the Intellisense, that is just Visual Studio helping you out. There is no relationship between Rectangle and Canvas.Left besides the fact that you can supply a value on a Rectangle for that attached property. With that in mind, what do you want to achieve?
- Hi Josh,
Thanks for the response. Here is my specific requirement -
In my logical tree, I want the user to be able to provide any object name and any property name on that object as string inputs. Based on these inputs, I need to set a value on that property for that object (more specifically I want to set a binding on that property).
Thus, for instance if I had a Rectangle object called "myRect" in the logical tree. The user inputs would be:
Element Name : myRect
Element Property : Canvas.Left
Path : SomeInput (used for databinding)
I then need to get a Dependency property object corresponding to Canvas.Left and set the binding on myRect object programatically (I am using the FrameworkElement.SetBinding method).
The problem is , as you already mentioned, Canvas.Left has no relationship to Rectangle so I cannot look into Rectangle properties. And moreover the user can provide any property name that can participate in Data Binding. How can I get the corresponding dependency property object in this case?
Thanks,
Niranjan. you can try something like this
Type t = typeof(Button); while (t != null){
FieldInfo[] fs = t.GetFields();System.Diagnostics.
Debug.WriteLine(t.ToString()); for (int i = 0; i < fs.Length; i++)System.Diagnostics.
Debug.WriteLine("\t" + fs
.Name );
t = t.BaseType;
}
this might be better
Type
t = typeof(Rectangle); while (t != null){
FieldInfo[] fi = t.GetFields(); for(int i=0;i<fi.Length;i++) if (fi
.FieldType.Name == "DependencyProperty")
System.Diagnostics.
Debug.WriteLine(fi
.Name);
t = t.BaseType;
}
You can obtain attached properties using reflection. Here's an example that iterates through all the types in an assembly:
Note the use of DependencyPropertyDescriptor to obtain additional information about each Dependency Property (this allows us to check if they are Attached or not). There may be a better method that avoids iterating over all the types like this, but I haven't found it yet!
- Doug
List<DependencyProperty> attached = new List<DependencyProperty>(); Assembly a = Assembly.Load( @"PresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"); foreach (Type t in a.GetTypes()) { foreach (FieldInfo fi in t.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public)) { if (fi.FieldType == typeof(DependencyProperty)) { DependencyProperty dp = (DependencyProperty)fi.GetValue(null); try { DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(dp, t); if (dpd != null && dpd.IsAttached) { // found an Attached Dependency Property attached.Add(dp); } } catch (ArgumentException) { // there was a problem obtaining the // DependencyPropertyDescriptor? } } } }
we dont get attached properties, if we do like I mentioned
I think Doug's way is better
- Well, Doug's code is awesome, but what the original poster want to do is get all the attached DPs applied to a specified object, then you can use the following helper methods I create:
public static class DependencyObjectHelper
{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;
}}
Sheva - Doug, lee and Zhou,
Thanks for your great inputs. I have it working now. Initially I used a combination of Doug's and Lee's code and got it to work. Thougg Zhou's code is more specific to the requirement and works too.
I had not come across MarkupObject and MarkupWriter classes. Another observation I made was that for these classes to work, the element has to be a part of a logical tree. So if I try to create a new Rectangle object and use it , markupobject.Properties is empty. On the other hand if the rectangle is a part of the logical tree, the relevant properties are returned.
The documentation says that these classes are primarily used to serialize logical trees into XAML format which seems somewhat in harmony to the above observation.
Any ideas on this ?
Thanks,
Niranjan. - Actually, you don't need to add the element to the logical tree to get my code work, the following demo code illustrates this:
<Window x:Class="TestCode.GetAllDPDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TestCode" Height="300" Width="300"
><DockPanel>
<Button Content="Get All DPs" Name="myButton" Width="100" Height="30" DockPanel.Dock="Top"/>
<TextBlock Name="myTextBlock" FontSize="16" Foreground="Red"/>
</DockPanel>
</Window>
namespace TestCode
{public partial class GetAllDPDemo : Window
{public GetAllDPDemo()
{InitializeComponent();myButton.Click += new RoutedEventHandler(myButton_Click);
}private void myButton_Click(Object sender, RoutedEventArgs e)
{Button btn = new Button();
DockPanel.SetDock(btn, Dock.Top);
FocusManager.SetIsFocusScope(btn, true);
FooClass.SetBarAttached(btn, true); // Set custom attached dependency property.
myTextBlock.Text = GetAllDPs(btn);}private String GetAllDPs(DependencyObject element)
{StringBuilder sb = new StringBuilder();
sb.AppendFormat("Attached DPs applied on {0}: \n", element.GetType().Name);
MarkupObject markupObject = MarkupWriter.GetMarkupObjectFor(element);
if (markupObject != null)
{foreach (MarkupProperty property in markupObject.Properties)
{if (property.IsAttached)
{sb.AppendLine(property.Name);}}}return sb.ToString();
}}public static class FooClass
{public static readonly DependencyProperty BarAttachedProperty = DependencyProperty.RegisterAttached(
"BarAttached",
typeof(Object),
typeof(FooClass),
new FrameworkPropertyMetadata(null));
public static Object GetBarAttached(DependencyObject element)
{return element.GetValue(BarAttachedProperty);
}public static void SetBarAttached(DependencyObject element, Object value)
{element.SetValue(BarAttachedProperty, value);}}}
Please take a closer look at the code hightlighted in red colour, actually my code also supports custom attched DP scenario.
Sheva - As a side note, my code can only get the locally set DPs.
Sheva Zhou ,
your code will only get the properties that are set on the element, not all the properties available for the element. Am I missing something
- Yep, probably I've missed the original poster's intention, it seems he want to get all the DPs available for an element, actually we can use Doug's code here to get all the DPs defined by the WPF base class library, but how about those DPs defined by ourselves?
Sheva - going up the inheritance chain like I did, with some modifications should work
Actually I thought I found a slightly more elegant solution:
public IList<DependencyProperty> GetAttachedProperties(DependencyObject obj) { List<DependencyProperty> attached = new List<DependencyProperty>(); foreach (PropertyDescriptor pd in TypeDescriptor.GetProperties(obj, new Attribute[] { new PropertyFilterAttribute(PropertyFilterOptions.All) })) { DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(pd); if (dpd != null && dpd.IsAttached) { attached.Add(dpd.DependencyProperty); } } return attached; }
But, it would appear this will not give any DP's which we define.
- Doug
- The above code seems to fetch the custom Dependency Properties as well. I have some properties registered as -
DependencyProperty.Register("IsRuntime", typeof(XXX), typeof(XXX), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure))
which are being sucessfully fetched.
Niranjan - awesome, Dauglas. I can verify that your code can also examine the custom attached DPs.
Sheva - Rather than returning an IList you should return an IEnumerable<DependencyProperty> and use "yield return" instead of adding things to the list. ;)
- Have you ever tried DependencyProperty.FromType(Type ownerType)?
It is easy to get all DPs from a object.

