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

The FrameworkElement object has a DataContextChanged event. However, the OnDataContextChanged method cannot be overridden.

Any ideas why?

+4
source share
4 answers

If the method is virtual, the user can either increase the basic functionality by calling the base class method, or replace the functionality of the base class without calling the base class method. For OnEvent () methods, if you do not call the base class method, this event will not increase (this is the responsibility of the base class method.) If the base class does some kind of state management inside the OnEvent method, this means that the derived class may accidentally invalidate the state object, if the user decided to omit the method call of the base class. The documentation may indicate "always call the base class method", but there is no way to enforce it.

When I see an event that does not have a virtual OnEvent () method, I usually assume that this method performs some kind of internal state control, and the class developers want to guarantee their state control starts. This is not the case in FrameworkElement, and this is not the only event that does not match the pattern, so I'm curious what reasoning is.

I turned around in Reflector to find out if I can find the reason. There is an OnDataContextChanged () method, but it is a handler for changing dependency properties and does not conform to standard event patterns. This is probably the reason that it is not protected by virtual. This is non-standard, so this will be confusing. This is static, so you still cannot override it. Since it is automatically called by the structure of dependency properties, and you cannot override it, I believe that we have a reason why it is private and not static virtual.

You can use another template to display the normal event template:

 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 is why they did not? Usually you call OnEvent () to raise an event. The event automatically occurs when the DataContext changes, and you do not need to raise it at any other time.

+2
source

Good question.

I just guess, but looking in Reflector, I would say that this is just laziness, possibly with performance problems (unfounded?). FrameworkElement has a common EventHandlersStore , which is responsible for storing event information (delegates) for an entire group of events. The logic of adding and removing in CLR events (for example, DataContextChanged ) simply calls the corresponding key in EventHandlersStore .

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

So, in short, I see no technical reason not to include the OnDataContextChanged method. I just look like a short cut in implementation.

Is it just academic, or are you trying to achieve something here?

+1
source

Silverlight Note:

Silverlight Beta 4 does not have a DataContextChanged event (well, at least not publicly).

The Microsoft Connect bug report is marked as “Fixed,” but without specifying what it actually means.

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

0
source

Dependency properties usually do not have the appropriate virtual methods to create an event, since he expected change events to be controlled by the dependecy property system itself.

However, you can override to handle any change to the dependency property - DependencyObject.OnPropertyChanged as follows:

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

All Articles