WPF .NET Core - Routed Events
Written by Mike James   
Thursday, 22 October 2020
Article Index
WPF .NET Core - Routed Events
Adding and removing handlers
Types of Routed Event
Creating your own routed events
Routed events – good or bad

 

Creating your own routed events

As the element hierarchy plays such a role in routed events you can only create new routed events in classes that derive from UIElement. The simplest way to do this is derive a new class from an existing WPF UIElement such as a button:

public class MyButton : Button
{

To define a new even we first need to use the EventManager class to register the new event.

This is how the system knows how to handle the event and in particular what sort of routing is to be applied. The RegisterRoutedEvent returns a RoutedEvent object which has to be stored as a static field for later use within the new control.

For example, we use the m_MyEvent field to store the object:

public static readonly RoutedEvent 
m_MyEvent =EventManager.RegisterRoutedEvent(
"MyEvent",
RoutingStrategy.Bubble,
typeof(RoutedEventHandler),
typeof(MyButton));

The first parameter specifies the name of the event that clients will use to add handlers to the event. This name has to be unique within the new control. Next we specify the type of routing, bubble in this case, and the type of the event handler and the type of object that can fire the event. The event handler delegate, RoutedEventHandler in this case, specifies the signature of any method that is to be added to the invocation list.

Now that we have registered the event we have to create some of the infrastructure needed to use the event. First we need to create the event property and an add and remove method using event accessors:

public event RoutedEventHandler MyEvent
{
add { AddHandler(m_MyEvent, value); }
remove { RemoveHandler(m_MyEvent, value); }
}

These are automatically used by the system when you add and remove event handlers using the +=  and -= operators. Notice that the event property has to have the same name as you registered using the EventManager.

Finally we need a RaiseEvent method that can be used to trigger the new event:

void RaiseMyEvent()
{
RoutedEventArgs newEventArgs =
new RoutedEventArgs(MyButton.m_MyEvent);
RaiseEvent(newEventArgs);
}

The only tricky part here is that the RoutedEventArgs constructor accepts a RoutedEvent object and creates the correct set of arguments based on the information it contains but the Source and OriginalSource properties are null. However you don’t have to do anything about them because they are filled in correctly when you use the RaiseEvent method.

For simplicity we can connect the new event to an existing Button event:

protected override void OnClick()
{
RaiseMyEvent();
}

Of course in a real situation you would have some complex set of conditions to be fulfilled before the new event was raised.

Now we can make use of the new MyButton class and its associated routed event. Start a new project, enter the definition of the new button class below the Window() class, after all it isn’t worth creating the class as a separate entity and add a stackFrame using the designer. Now we can create an instance of MyButton at runtime (again it isn’t worth adding it to the Toolbox for an example):

MyButton B1=new MyButton();

We need to set some minimal properties to ensure that it displays in a reasonable way:

B1.Width = 50;
B1.Height = 50;
B1.Content = "ClickMe";

and we need to add it to the stackPanel’s Children collection;

stackPanel1.Children.Add(B1);

Given that it now has a position within the element hierarchy – it is a child element of the stackPanel  - we can use the new routed event and expect it to be bubbled up to the stackPanel if we add:

stackPanel1.AddHandler(MyButton.m_MyEvent,
new RoutedEventHandler(MyButtonHandler));
void MyButtonHandler(object sender,
RoutedEventArgs e)
{
MessageBox.Show("My New Clicked Event");
}

Notice that when using AddHandler you have to use the static field to specify the type of event that is going to be attached to the stackPanel. Contrast this to adding an event handler to a control that supports the event directly, for example:

B1.MyEvent += (object sender,
RoutedEventArgs e) =>
{
MessageBox.Show("MyClicked");
};

Now when you run the program the new event will bubble up to the stackPanel as promised. You can change the nature of the routing as part of the registration using the EventManager to see how it all works.

XAML

 



Last Updated ( Thursday, 22 October 2020 )