共用方式為


How to initialize an attached DependencyProperty of type Collection

I was reading a thread about Commands in the WPF Disciples group and noticed a comment about being unable to initialize an attached property where the type was collection.  The problem was unless you put in an explicit Collection object tag, the property is initialized to null when the XAML parser tries to add to it.  I ran into the same issue when working on VisualStateManager.  This markup failed:

<VisualStateManager.VisualStateGroups>

<VisualStateGroup x:Name="CommonStates">

Because the VisualStateGroups property contained a null collection (not an empty collection) and the XAML parser tried to add it. This markup worked:

<VisualStateManager.VisualStateGroups>

<VisualStateGroupCollection>

<VisualStateGroup x:Name="CommonStates">

But this seemed inconsistent and unnecessary. The normal way to do this is to initialize the property in the CLR getter, but attached properties were skipping calling the getter. This is an optimization: the XAML parser accesses the DP directly rather than use reflection to find and call the CLR property. Well, the fix is easy: hide the DP from the XAML parser, which can be done by using a different name for the registered DP (and making it internal is a good idea), and defining the attached property by using the static getter and setter. So if the DP is called InternalVisualStateGroups and the getter and setter are for VisualStateGroups, the parser will call the static property.

 

Here's a snippet showing how the property is defined that works:

 

        internal static readonly DependencyProperty VisualStateGroupsProperty =

            DependencyProperty.RegisterAttached("InternalVisualStateGroups",

                            typeof(VisualStateGroupCollection),

                            typeof(VisualStateManager),

                            new UIPropertyMetadata(null,

                                    new PropertyChangedCallback(VisualStateManager.VisualStateGroupsProperty_Changed)));

 

        internal static VisualStateGroupCollection GetVisualStateGroupsInternal(DependencyObject obj)

        {

            if (obj == null)

            {

                throw new ArgumentNullException("obj");

            }

            VisualStateGroupCollection groups = obj.GetValue(VisualStateManager.VisualStateGroupsProperty) as VisualStateGroupCollection;

            if (groups == null)

            {

                groups = new VisualStateGroupCollection();

                SetVisualStateGroups(obj, groups);

            }

            return groups;

        }

 

        public static IList GetVisualStateGroups(DependencyObject obj)

        {

            return VisualStateManager.GetVisualStateGroupsInternal(obj);

        }

Comments

  • Anonymous
    July 28, 2008
    PingBack from http://blog.a-foton.ru/2008/07/how-to-initialize-an-attached-dependencyproperty-of-type-collection/

  • Anonymous
    July 31, 2008
    Hi John, I saw you posted to the WPF Disciples mailing list asking for feedback on WPF.  Do you think you could also post the same request to your blog?  I have a ton of feedback, but don't have the time available to share all of it.  However, I have at least one "biggie" I want to see in WPF 4.0. Z-Bo

  • Anonymous
    July 31, 2008
    We would always love to get your feedback...it is probably more useful to post it on the MSDN forums than in the comments to my blog, where it is possibly going to get lost: http://forums.msdn.microsoft.com/en-US/wpf/threads/ You can also send me e-mail...it's John with a dot, my last name and microsoft.com