.NET Framework Developer Center > .NET Development Forums > Windows Presentation Foundation (WPF) > Getting list of all dependency/attached properties of an Object
Ask a questionAsk a question
 

AnswerGetting list of all dependency/attached properties of an Object

  • Friday, October 20, 2006 8:21 PMNpotnis Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    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

  • Tuesday, October 24, 2006 1:26 PMZhou Yong Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    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
  • Tuesday, October 24, 2006 4:50 PMDouglas Stockwell Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer

    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

  • Friday, October 20, 2006 8:53 PMJosh SmithMVPUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    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?
  • Monday, October 23, 2006 2:34 PMNpotnis Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    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.


  • Monday, October 23, 2006 3:08 PMlee dModeratorUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    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" + fsIdea.Name );

    t = t.BaseType;

    }

  • Monday, October 23, 2006 3:24 PMlee dModeratorUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    this might be better

    Type t = typeof(Rectangle);

    while (t != null)

    {

    FieldInfo[] fi = t.GetFields();

    for(int i=0;i<fi.Length;i++)

    if (fiIdea.FieldType.Name == "DependencyProperty")

    System.Diagnostics.Debug.WriteLine(fiIdea.Name);

    t = t.BaseType;

    }

  • Monday, October 23, 2006 3:40 PMDouglas Stockwell Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

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

     

  • Monday, October 23, 2006 3:47 PMlee dModeratorUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    we dont get attached properties, if we do like I mentioned

    I think Doug's way is better

  • Tuesday, October 24, 2006 1:26 PMZhou Yong Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    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
  • Tuesday, October 24, 2006 3:29 PMNpotnis Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    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.
  • Tuesday, October 24, 2006 3:46 PMZhou Yong Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    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
  • Tuesday, October 24, 2006 3:54 PMZhou Yong Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    As a side note, my code can only get the locally set DPs.

    Sheva
  • Tuesday, October 24, 2006 3:58 PMlee dModeratorUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    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

     

  • Tuesday, October 24, 2006 4:25 PMZhou Yong Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
        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
  • Tuesday, October 24, 2006 4:48 PMlee dModeratorUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    going up the inheritance chain like I did, with some modifications should work
  • Tuesday, October 24, 2006 4:50 PMDouglas Stockwell Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer

    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

  • Tuesday, October 24, 2006 5:30 PMNpotnis Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    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
  • Wednesday, October 25, 2006 12:10 PMZhou Yong Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    awesome, Dauglas. I can verify that your code can also examine the custom attached DPs.

    Sheva
  • Saturday, March 21, 2009 5:12 AMjustncase80 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Rather than returning an IList you should return an IEnumerable<DependencyProperty> and use "yield return" instead of adding things to the list. ;)
  • Saturday, September 12, 2009 7:05 AMYst Yang Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Have you ever tried DependencyProperty.FromType(Type ownerType)?

    It is easy to get all DPs from a object.