tags:

views:

193

answers:

4

The FrameworkElement object has DataContextChanged event. However, there is no OnDataContextChanged method that can be overridden.

Any ideas why?

A: 

Good question.

I'm just guessing, but looking in Reflector I'd say it's just laziness, perhaps with a pinch of (unfounded?) performance concerns. FrameworkElement has a generic EventHandlersStore which is responsible for maintaining event information (delegates) for a whole bunch of events. The add and remove logic in the CLR events (such as DataContextChanged) simple call into the EventHandlersStore with the appropriate key.

There is a generic RaiseDependencyPropertyChanged method that is called to raise all different sorts of events. There is also a private OnDataContextChanged method that calls the RaiseDependencyPropertyChanged method. However, it is static and registered as part of the d-prop metadata.

So, in short, I see no technical reason not to include an overridable OnDataContextChanged method. Just looks like a short-cut in implementation to me.

Is this merely academic, or are you trying to achieve something here?

HTH, Kent

Kent Boogaart
Honestly I was simply wondering if there is some logic behind that it. It didn't make any sense to me either.Registering to the events is just as good for my needs.Thank you for the great answer!
Elad
+1  A: 

If a method is virtual, then the user has the option to either augment the base functionalty by calling the base class method or replace the base class functionality by failing to call the base class method. For OnEvent() methods, if you don't call the base class method then the event will not be raised (that's the responsibility of the base class method.) If the base class performs some kind of state management inside of the OnEvent method, this means that the derived class can accidentally invalidate the state of the object if the user chooses to omit a call to the base class method. Documentation can specify "please always call the base class method", but there's no way to enforce it.

When I see an event that doesn't have a virtual OnEvent() method, I usually assume the method performs some kind of internal state management and the designers of the class want to guarantee their state management runs. This isn't the case in FrameworkElement, and it's not the only event that doesn't follow the pattern, so I'm curious what the reasoning is.

I dug around in Reflector to see if I could discover a reason. There is an OnDataContextChanged() method, but it's a dependency property change handler and doesn't follow the standard event pattern. This is probably the reason for not making it protected virtual. It's non-standard, so it would be confusing. It's static, so you wouldn't be able to override it anyway. Since it's called automatically by the dependency property framework and you are unable to override it, I believe we have the reason why it's private instead of static virtual.

You could use a different pattern to expose the normal event pattern:

class FrameworkElement
{
    // difference: use DataContextPropertyChanged as the change callback
    public static readonly DependencyProperty DataContextProperty = ...

    protected virtual void OnDataContextChanged(...)
    {
        // raise the DataContextChanged event
    }

    private static void DataContextPropertyChanged(...)
    {
        ((FrameworkElement)d).OnDataContextChanged(...);
    }
}

My guess why they didn't do this? Usually you call OnEvent() to raise the event. The event is automatically raised when DataContext changes, and it doesn't make sense for you to raise it at any other time.

OwenP
There's no reason the static OnDataContextChanged event couldn't invoke a non-static OnDataContextChanged event. They'd want to rename to make things clearer, of course. Providing an overridable OnXxx method is standard .NET practice. Granted, there are pitfalls as you mention, but there are also mitigations and a certain amount of onus on the developer to know what they're doing.
Kent Boogaart
That's valid, but doesn't answer the question "When does it make sense for a user to be able to raise the event?" If the method is protected, it can be raised whenever the user decides to do so.We're missing some information: it's possible this event is used by lots of internal WPF classes in ways that aren't public knowledge, and letting the user change the behavior in any way is a danger.
OwenP
A: 

Silverlight Note:

At of Silverlight Beta 4 there IS no DataContextChanged event (well its not public at least).

The Microsoft Connect bug report has been marked as 'Fixed' but with no indication of what that actually means.

In the meantime you need a workaround such as this one from CodeProject - which is very simple and should be easy to switch out if Microsoft ever actually makes the event public.

Simon_Weaver
A: 

Dependency properties usually don't have corresponding virtual methods for raising the event because it's expected that the change events will be managed by the dependecy property system itself.

What you can override however, to handle any dependency property changing is DependencyObject.OnPropertyChanged like so:

class MyClass : FrameworkElement {

    protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) {
        base.OnPropertyChanged(e);
        if (e.Property == FrameworkElement.DataContextProperty) {
            // do something with e.NewValue/e.OldValue
        }
    }

}
Josh Einstein
Balls! I did it again and replied to a really old question that showed up on the front page. Grrr....
Josh Einstein