#602 – Accessing Information in RoutedEventArgs

All predefined routed events in WPF are declared as instances of a delegate type that passes back either an instance of RoutedEventArgs or of some subclass of RoutedEventArgs.

public delegate void RoutedEventHandler(object sender, RoutedEventArgs e);

The RoutedEventArgs type includes the following properties, which you can make use of in your event handlers:

  • Handled – has event been handled yet?
  • OriginalSource – original low-level element where the event originated (e.g. sub-element in a control)
  • RoutedEvent – an instance of the associated routed event
  • Source – element where the event originated

Note that if the event is bubbling or tunneling, the Source property will refer to the element where the event originated, while the sender parameter will refer to the element that raised the event.  If the event is bubbling or tunneling, this element may be higher up the logical tree than the source element.

#601 – The RoutedEventHandler Delegate Type

In the example showing the implementation of the ButtonBase.Click routed event, you’ll notice that the Click event is declared as a standard CLR event whose type is the RoutedEventHandler delegate type.

If we look at RoutedEventHandler, we see that it has this signature:

public delegate void RoutedEventHandler(object sender, RoutedEventArgs e);

In WPF, many routed events have this signature and others declare a new delegate type that passes back a subclass of RoutedEventArgs.  For example, UIElement.KeyDown has a delegate type of KeyEventHandler, which has the following signature:

public delegate void KeyEventHandler(Object sender, KeyEventArgs e)

The KeyEventArgs type inherits from RoutedEventArgs (indirectly), adding some properties that make sense for key press events.

So event handlers for predefined routed events in WPF will normally be passed either an instance of RoutedEventArgs or an instance of a type that inherits from RoutedEventArgs.

#502 – Sender vs. RoutedEventArgs.Source

When handling a routed event, you can check the RoutedEventArgs.Source property to get at the control that is the originator of the event.  But the event handler also includes a sender parameter that in many cases also points to the originator of the event.

In the case of routed events, RoutedEventArgs.Source will refer to the originator of the event and sender will refer to the object that owns the event handler.

In the example below, RoutedEventArgs.Source will refer to the Button that a user clicked on, while sender will refer to the StackPanel to which the  Click event is attached.

    <StackPanel ButtonBase.Click="Button_Click">
        <Button Content="Keaton" />
        <Button Content="Chaplin" />
        <Button Content="Arbuckle" />
    </StackPanel>

 

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Button b = e.Source as Button;
            MessageBox.Show(string.Format("You clicked on {0} button, sender is of type {1}",
                b.Content, sender.GetType().ToString()));
        }

#500 – Sharing an Event Handler Across Multiple Controls, Method 1

You can use the same event handler for more than one control by specifying the handler for each control and pointing to the same event handler code.

In the example below, we have three buttons, each of which wires up a handler for the Click event, but using the same handler (Button_Click).

    <StackPanel>
        <Button Content="Keaton" HorizontalAlignment="Center" Padding="10,5" Margin="5"
                Click="Button_Click"/>
        <Button Content="Chaplin" HorizontalAlignment="Center" Padding="10,5" Margin="5"
                Click="Button_Click"/>
        <Button Content="Arbuckle" HorizontalAlignment="Center" Padding="10,5" Margin="5"
                Click="Button_Click"/>
    </StackPanel>

In the Button_Click event handler, we can check the Source property of the RoutedEventArgs parameter to determine which button sent us the event.

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            // Get at originator of event using RoutedEventArgs.Source property

            Button b = e.Source as Button;
            MessageBox.Show(string.Format("You clicked on {0} button", b.Content));
        }