Skip to content
Cole Campbell edited this page Mar 3, 2018 · 1 revision

Routed events are a concept in the Ultraviolet Presentation Foundation which supplement traditional .NET events. Such events are aware of the hierarchy of interface elements and can automatically propagate themselves through it. Routed events can be raised against any object which is descended from the DependencyObject abstract class.

Declaring a Routed Event

To create a new routed event, the event must be registered with the routed event system using the RegisterRoutedEvent() method of the EventManager class. This method returns an instance of the RoutedEvent class which uniquely identifies the event that was created.

public class MyElement : FrameworkElement
{
    public static readonly RoutedEvent FooEvent = EventManager.RegisterRoutedEvent("Foo", 
        RoutingStrategy.Bubble, typeof(UpfRoutedEventHandler), typeof(MyElement));
}

The method's parameters are, in order:

  1. The name of the routed event, in this case Foo.
  2. The event's routing strategy. This determines how the event is propagated through the visual tree of elements.
  • RoutingStrategy.Bubble starts at the source element and "bubbles" upwards through the tree, moving to the source's parent, and then to the parent's parent, and so on, until it reaches the layout root.
  • RoutingStrategy.Direct causes the event to only be raised against the source element.
  • RoutingStrategy.Tunnel starts at the layout root and "tunnels" down to the source element. This is used primarily for events which allow ancestor elements to preview their descendants' input events.
  1. The type of delegate which handles the event. In this case it's UpfRoutedEventHandler. You can define custom handler types, but they must satisfy the following conditions:
  • The handler must have a return type of void.
  • The handler's first parameter must be an instance of DependencyObject. This parameter represents the element which is currently processing the event (not the source element).
  • The handler's final parameter must be an instance of RoutedEventData.
  1. The type which owns the routed event.

The RoutedEventData structure contains metadata relating to the current event invocation, including a reference to the event's source element. It also contains a property called Handled which, when set to true, indicates that the event should be ignored by subsequent handlers.

Once a routed event has been declared, you can expose it through a standard .NET event by providing custom add and remove accessors which make use of the AddHandler() and RemoveHandler() methods defined on UIElement.

public class MyElement : FrameworkElement
{
    public event UpfRoutedEventHandler Foo
    {
        add { AddHandler(FooEvent, value); }
        remove { RemoveHandler(FooEvent, value); }
    }
}

Routed events can be referenced by name in UVML and UVSS so long as they are qualified by the names of their owner types, regardless of whether there exists a standard event which exposes them. Like dependency properties, routed events have a styling name which is used in UVSS in place of its actual name, and the styling names for routed events follow the same conventions as those used by dependency properties.

Attached Events

An attached event is analogous to an attached property: it is a routed event which is raised against a type other than the one which owns it. Unlike with dependency properties, there is no special method for registering attached events, as all routed events can be used in an attached fashion.

Just like with dependency properties, attached events are referenced in UVML and UVSS by prepending the name of the event's owner type to the event name.

<Button Mouse.MouseEnter="HandleMouseEnter"/>

Invocation Delegates

To invoke a routed event, you must first retrieve its associated invocation delegate using the EventManager class, and then you must invoke that delegate.

protected virtual void OnFoo()
{
    var evtDelegate = EventManager.GetInvocationDelegate<UpfRoutedEventHandler>(FooEvent);
    var evtData = RoutedEventData.Retrieve(this);
    evtDelegate(this, evtData);
}

The first parameter is the source element against which to raise the event; the second parameter is the event metadata. Event metadata is pooled and will be automatically released after the event handler completes execution, unless the autorelease parameter of the Retrieve() method is set to false.

The invocation delegate of a routed event has its routing behavior built directly into it; this is how it routes itself through the visual tree of elements. It is automatically generated by Ultraviolet when the event is registered, and has the same delegate type as the event itself.

Clone this wiki locally