Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF - Why there is no "OnDataContextChanged" overridable method?

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

Any ideas why?

like image 742
Elad Avatar asked Oct 14 '22 14:10

Elad


2 Answers

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.

like image 160
OwenP Avatar answered Oct 19 '22 03:10

OwenP


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?

like image 24
Kent Boogaart Avatar answered Oct 19 '22 01:10

Kent Boogaart