Rediscovering the Obvious

…stumbling in the footsteps of greatness

Confused about DependencyProperties

without comments

I have a custom control that serves as a generic container for selecting a specific instance of one of a number of types of objects. This container handles the different types by swapping out other user controls as appropriate to what’s being selected, for instance I may have a FooPicker user control and a BarPicker user control. Each of these specific UserControl instances needs to have a value for CurrentSelection and the ability to announce CurrentSelectionChanged. Rather than create a common base class and push a bunch of code into it, I thought I could add a DependencyProperty and RoutedEvent on the container to take care of it for me.

This worked and it didn’t, and here’s why… first, my definitions:

In PickerPanel (the container), I coded:

        public static readonly RoutedEvent CurrentSelectionChangeEvent =
            EventManager.RegisterRoutedEvent(
                “CurrentSelectionChange”,
                RoutingStrategy.Bubble,
                typeof(RoutedEventHandler),
                typeof(PickerPanel));

and

         public static readonly DependencyProperty CurrentSelectionProperty =
            DependencyProperty.Register(
                “CurrentSelection”,
                typeof(object),
                typeof(PickerPanel),
                new PropertyMetadata(
                    null,
                    new PropertyChangedCallback(OnCurrentSelectionChanged) )
            );
        private static void OnCurrentSelectionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            UIElement picker = (UIElement) d;

            RoutedEventArgs args = new RoutedEventArgs(PickerPanel.CurrentSelectionChangeEvent, d);
            picker.RaiseEvent(args);
        }

Then, in the entity-specific UserControl, I handed the change event with:

         private void _fooLookupGrid_RecordActivated(object sender, RecordActivatedEventArgs e)
        {
            DataRecord dr = (DataRecord) e.Record;
            SetValue(PickerPanel.CurrentSelectionProperty, dr.DataItem);
        }

My assumption is that the call to SetValue should cause the firing of OnCurrentSelectionChanged with the user control being passed as the parameter “d”. OnCurrentSelectionChanged never called, ever. I have no idea why, either.

I worked around the issue by replacing the code in the derived class with the below code, but I don’t like it.

        private void _storeLookupGrid_RecordActivated(object sender, RecordActivatedEventArgs e)
        {
            DataRecord dr = (DataRecord) e.Record;
            SetValue(PickerPanel.CurrentSelectionProperty, dr.DataItem);
           
            RoutedEventArgs args = new RoutedEventArgs(PickerPanel.CurrentSelectionChangeEvent, this);
            RaiseEvent(args);
        }

 Having made the above workaround, I can now successfully receive the event from PickerPanel’s parent with:
        private void _pickerPanel_CurrentSelectionChanged(object sender, System.Windows.RoutedEventArgs e)
        {

        }

        In XAML:
        <someNamespace:PickerPanel
            x:Name=”_pickerPanel”
            someNamespace:PickerPanel.CurrentSelectionChanged=”_pickerPanel_CurrentSelectionChanged”/>
 

I’m not very happy with this, because I have clue why the event on the dependency property doesn’t fire.  Since I’m allowed to do so, since I’m writing this blog, I’m going to try something now, and then finish this post (I’m breaking all sorts of blogging rules here, right?)

I’m back!
My suspicion is confirmed, but I’m still very confused. In the handler above, I added a line of code as such:
        private void _pickerPanel_CurrentSelectionChanged(object sender, System.Windows.RoutedEventArgs e)
        {
            _pickerPanel.SetValue(Pickers.PickerPanel.CurrentSelectionProperty, “String’s an object, right?”);
        }

Sure enough, my handler was called, and it fired the event again and would have started up ye olde infinite event loop o’ doom if the changed event wasn’t smart enough to actually check that the object changed.

So, does anybody know why the PropertyChangedCallback provided as part of the PropertyMetadata for a DependencyProperty isn’t called when it’s set on another object? Am I required to treat it as an AttachedProperty at that point? I thought AttachedProperty was a XAML-specific helper based on http://msdn2.microsoft.com/en-us/library/ms749011.aspx.

 

 

Written by erwilleke

July 23rd, 2007 at 1:47 pm

Posted in Uncategorized

Leave a Reply