C# – WPF Attached Events vs Non-Attached Events

croutedeventwpfxaml

The question is that after all my research I still can't find the difference between a regular routed event and a attached event. What is the functional the difference? or do others agree that there is none?

Implementation

The ButtonBase class declares a routed event named ClickEvent; a normal routed event.

public static readonly RoutedEvent ClickEvent = EventManager.RegisterRoutedEvent("Click", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ButtonBase));

[Category("Behavior")]
public event RoutedEventHandler Click
{
    add
    {
        base.AddHandler(ClickEvent, value);
    }
    remove
    {
        base.RemoveHandler(ClickEvent, value);
    }
}

The Mouse class declares a routed event named MouseDownEvent; an attached event.

public static readonly RoutedEvent MouseDownEvent = EventManager.RegisterRoutedEvent("MouseDown", RoutingStrategy.Bubble, typeof(MouseButtonEventHandler), typeof(Mouse));

public static void AddMouseDownHandler(DependencyObject element, MouseButtonEventHandler handler)
{
    UIElement.AddHandler(element, MouseDownEvent, handler);
}

public static void RemoveMouseDownHandler(DependencyObject element, MouseButtonEventHandler handler)
{
    UIElement.RemoveHandler(element, MouseDownEvent, handler);
}

Both events are registered with EventManager and stored as a public, static, readonly, fields in the same manner. ClickEvent has a backing CLR event field with custom add and remove accessors that call base.AddHandler and base.RemoveHandler respectively; both of which are declared in the UIElement base class that ButtonBase derives from. MouseDownEvent instead has two static methods AddMouseDownHandler and RemoveMouseDownHandler, that ultimately call the same two AddHandler and RemoveHandler methods declared in UIElement just like ClickEvent.

The Add*Handler and Remove*Handler static methods for actual attached events declared on a static class must follow a specific naming convention to allow the WPF event system to use reflection to find the appropriate add and remove handlers at run-time.


Usage

Both events can have handlers attached in XAML as follows:

<Grid Button.Click="Grid_Click"
      Mouse.MouseDown="Grid_MouseDown">
</Grid>

Both events can be attached in code as follows:

// Attach ClickEvent handler.
myGrid.AddHandler(Button.ClickEvent, new RoutedEventHandler(Grid_Click));

// Attach MouseDownEvent handler.
Mouse.AddMouseDownHandler(myGrid, Grid_MouseDown);

As you can see both events can be attached to elements that do not own or declare them.


Conclusion – What is an Attached Event?

MSDN documentation states:
http://msdn.microsoft.com/en-us/library/bb613550.aspx

Extensible Application Markup Language
(XAML) defines a language component
and type of event called an attached
event. The concept of an attached
event enables you to add a handler for
a particular event to an arbitrary
element rather than to an element that
actually defines or inherits the
event. In this case, neither the
object potentially raising the event
nor the destination handling instance
defines or otherwise "owns" the event.

In addition, the official MCTS Training Kit for Exam 70-511 – Windows Applications Development with Microsoft .NET Framework 4 states:

It is possible for a control to define
a handler for an event that the
control cannot itself raise. These
incidents are called attached events.
For example, consider Button controls
in a grid. The Button class defines a
Click event, but the Grid class does
not. However, you can still define a
handler for buttons in the grid by
attaching the Click event of the
Button control in the XAML code.

The term "attached event" seems to be blurred throughout Microsoft learning resources, although it is clear there are two different, but very closely related concepts at play here: attached events and XAML attached event syntax. Both Microsoft sources I've quoted seem to be referring to XAML attached event syntax, rather than actual attached events. However, the attached events overview MSDN page does go on to show you how to implement an actual attached event, where as the training kit does not.

Mouse.MouseDownEvent is an example of a routed event declared on a static class with corresponding static add and remove handlers, otherwise known as an attached event. However, ButtonBase.ClickEvent is a normal routed event, although it can still be used with XAML attached event syntax in the same manner as an actual attached event.

The purpose of an actual attached event is that it allows developers to declare new routed events for existing UIElement-derived classes without having to subclass them; meaning you can just attach new routed events without them actually existing on the classes you want to raise or handle them on. But, wait a minute… isn't that the primary purpose of a pure routed event in the first place?

The routed events overview page on MSDN states: http://msdn.microsoft.com/en-us/library/ms742806.aspx

Functional definition: A routed event
is a type of event that can invoke
handlers on multiple listeners in an
element tree, rather than just on the
object that raised the event.

From that functional definition it seems that any routed event essentially provides the same exact functionality as an attached event. So basically an attached event is really just a means to declare a routed event on a static class and doesn't really offer any benefit over normal routed events.

Let me know you think, as I may be missing something here.

Thanks,
Tim Valentine

Best Answer

The difference is mostly syntactic, both delegate references are being handled by WPF's EventManager but what the attached events give you is the ability to declare generic functionality without needing to bloat all your classes' implementation.

In the case of a normal routed event, the class provides the interface to be able to at some point respond to an event by calling the event handler. But all WPF needs to know is if it is an object of derived from a given type and if a handler was registered. This means that we can make simpler class hierarchies and also supports the Open-Closed Principle (Open to Extension, Closed to Modification). This way a programmer can define a new behavior that several classes should have but does not need to modify the original classes.

See also Attached Properties