How to: Add Class Handling for a Routed Event
Routed events can be handled either by class handlers or instance handlers on any given node in the route. Class handlers are invoked first, and can be used by class implementations to suppress events from instance handling or introduce other event specific behaviors on events that are owned by base classes. This example illustrates two closely related techniques for implementing class handlers.
Example
This example uses a custom class based on the Canvas panel. The basic premise of the application is that the custom class introduces behaviors on its child elements, including intercepting any left mouse button clicks and marking them handled, before the child element class or any instance handlers on it will be invoked.
The UIElement class exposes a virtual method that enables class handling on the PreviewMouseLeftButtonDown event, by simply overriding the event. This is the simplest way to implement class handling if such a virtual method is available somewhere in your class' hierarchy. The following code shows the OnPreviewMouseLeftButtonDown implementation in the "MyEditContainer" that is derived from Canvas. The implementation marks the event as handled in the arguments, and then adds some code to give the source element a basic visible change.
Protected Overrides Sub OnPreviewMouseRightButtonDown(ByVal e As System.Windows.Input.MouseButtonEventArgs)
e.Handled = True 'suppress the click event and other leftmousebuttondown responders
Dim ec As MyEditContainer = CType(e.Source, MyEditContainer)
If ec.EditState Then
ec.EditState = False
Else
ec.EditState = True
End If
MyBase.OnPreviewMouseRightButtonDown(e)
End Sub
protected override void OnPreviewMouseRightButtonDown(System.Windows.Input.MouseButtonEventArgs e)
{
e.Handled = true; //suppress the click event and other leftmousebuttondown responders
MyEditContainer ec = (MyEditContainer)e.Source;
if (ec.EditState)
{ ec.EditState = false; }
else
{ ec.EditState = true; }
base.OnPreviewMouseRightButtonDown(e);
}
If no virtual is available on base classes or for that particular method, class handling can be added directly using a utility method of the EventManager class, RegisterClassHandler. This method should only be called within the static initialization of classes that are adding class handling. This example adds another handler for PreviewMouseLeftButtonDown , and in this case the registered class is the custom class. In contrast, when using the virtuals, the registered class is really the UIElement base class. In cases where base classes and subclass each register class handling, the subclass handlers are invoked first. The behavior in an application would be that first this handler would show its message box and then the visual change in the virtual method's handler would be shown.
Shared Sub New()
EventManager.RegisterClassHandler(GetType(MyEditContainer), PreviewMouseRightButtonDownEvent, New RoutedEventHandler(AddressOf LocalOnMouseRightButtonDown))
End Sub
Friend Shared Sub LocalOnMouseRightButtonDown(ByVal sender As Object, ByVal e As RoutedEventArgs)
MessageBox.Show("this is invoked before the On* class handler on UIElement")
'e.Handled = True //uncommenting this would cause ONLY the subclass' class handler to respond
End Sub
static MyEditContainer()
{
EventManager.RegisterClassHandler(typeof(MyEditContainer), PreviewMouseRightButtonDownEvent, new RoutedEventHandler(LocalOnMouseRightButtonDown));
}
internal static void LocalOnMouseRightButtonDown(object sender, RoutedEventArgs e)
{
MessageBox.Show("this is invoked before the On* class handler on UIElement");
//e.Handled = true; //uncommenting this would cause ONLY the subclass' class handler to respond
}