Routed Events in WPF
Routed Events :
Event routing allows an event to originate in one element but be raised by another one.
For example, event routing allows a click that begins in a toolbar button to rise up to the toolbar and then to the containing window before it’s handled by your code.
Defining, Registering, and Wrapping a Routed Event
Routed events are represented by read-only static fields, registered in a static constructor, and wrapped by a standard .NET event definition.
For example, the WPF Button class provides the familiar Click event, which is inherited from the abstract ButtonBase class.
Here’s how the event is defined and registered:
public abstract class ButtonBase : ContentControl, ...
{
public static readonly RoutedEvent ClickEvent;
static ButtonBase()
{ButtonBase.ClickEvent = EventManager.RegisterRoutedEvent(
"Click", RoutingStrategy.Bubble, typeof(RoutedEventHandler),
typeof(ButtonBase));
}
public event RoutedEventHandler Click
{ add
{ base.AddHandler(ButtonBase.ClickEvent, value);}
remove
{ base.RemoveHandler(ButtonBase.ClickEvent, value);} }
Routed events are registered with the
EventManager.RegisterRoutedEvent() method.
When registering an event, you need to specify the name of the event, the type of routine, the delegate that defines the syntax of the event handler (in this example, RoutedEventHandler), and the class that owns the event.
The event wrapper adds and removes registered callers using the AddHandler() and RemoveHandler() methods, both of which are defined in the base FrameworkElement class and inherited by every WPF element.
private void img_MouseUp(object sender, MouseButtonEventArgs e)
{
...
}
When we add event handler : img.MouseUp += img_MouseUp;
Internally event registration takes place with event wraper like this :
img.AddHandler(UIElement.MouseUpEvent,
new MouseButtonEventHandler(img_MouseUp));
If you want to detach an event handler, code is your only option. You can use the -= operator, as shown here:
img.MouseUp -= img_MouseUp;
Or you can use the UIElement.RemoveHandler() method:
img.RemoveHandler(Image.MouseUpEvent,
new MouseButtonEventHandler(img_MouseUp));
Routing Strategies and Event Handlers :
strategies are exposed as values of a Routingstrategy enumeration
Tunneling - The event is first raised on the root, then on each element down the tree until the source element is reached (or until a handler halts the tunneling by marking the event as handled).
Bubbling - The event is first raised on the source element, then on each element up the tree until the root is reached (or until a handler halts the bubbling by marking the event as handled).
Direct - The event is only raised on the source element. This is the same behavior as a plain .NET event, except that such events can still participate in mechanisms specific to routed events such as event triggers.
MouseUp and MouseDown are bubbling events, you can now determine what happens
When the image is clicked, the MouseDown event fires in this order:
1. Image.MouseDown
2. StackPanel.MouseDown
3. Label.MouseDown
After the MouseDown event is raised for the label, it’s passed on to the next control (which in this case is the Grid that lays out the containing window) and then to its parent (the window).
The window is the top level of the containment hierarchy and the final stop in the event bubbling sequence.
If the user releases the mouse button, the MouseUp event fires in the same sequence.
The e parameter is an instance of RoutedEventArgs, a subclass of EventArgs that exposes four useful properties:
. Source—The element in the logical tree that originally raised the event.
. OriginalSource—The element in the visual tree that originally raised the event (for example, the TextBlock or ButtonChrome child of a standard Button).
. Handled—A Boolean that can be set to true to mark the event as handled. This is precisely what halts any tunneling or bubbling.
. RoutedEvent—The actual routed event object (such as Button.ClickEvent), which can be helpful for identifying the raised event when the same handler is used for multiple routed events.
Based on Events and Delegates
<Button Name=“mybtn” Click=“OnmybtnClick”>Click me/>
Now code behind
Protected void OnmybtnClick(Obect sender, RoutedEventArgs e)
{
MessageBox.Show(“Hello WPF with XAML”);
}
If Button contains CheckBox, event is Bubbled i.e first event arrives to CheckBox and then it bubbles to Button.
Tunnelling event first arrives with outer element and tunnels to inner element.
Control it using e.Handled property of RoutedEvent
Routed Events – Event Bubbling
<Window xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
x:Class=”AboutDialog” MouseRightButtonDown=”AboutDialog_MouseRightButtonDown”
Title=”About WPF Programming” SizeToContent=”WidthAndHeight”
Background=”OrangeRed”>
<StackPanel>…….
Code Behind
public partial class AboutDialog : Window{
void AboutDialog_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
this.Title = “Source = “ + e.Source.GetType().Name + “, OriginalSource = “ +
e.OriginalSource.GetType().Name + “ @ “ + e.Timestamp;
Control source = e.Source as Control;
if (source.BorderThickness != new Thickness(5))
{
source.BorderThickness = new Thickness(5);
source.BorderBrush = Brushes.Black;
}
else
source.BorderThickness = new Thickness(0);
}
}