This topic describes the programming concept of events, and how the event concept works in Silverlight and its programming models. Silverlight events are essentially the same event concept as defined by the common language runtime and the .NET Framework. Similar to WPF, you can assign handlers for events as part of the declarations for UI elements in XAML, or you can use language-specific syntax to add the handlers in code. Silverlight supports the concept of routed events, which is a feature whereby certain input events and data events can be handled by objects other than the object that raised the event. Routed events are useful when compositing control templates or when centralizing the event logic of an application page.
This topic contains the following sections.
Events as a Programming Concept
An event is a message sent by an object to signal the occurrence of an action. The action could be caused by user interaction, such as a mouse click, or it could be triggered by the internal logic of a class. The object that raises the event is called the event sender. The object that captures the event and responds to it is called the event receiver. Basically the purpose of events is to communicate time-specific, relatively lightweight information from an object at run time, and potentially to deliver that information to other objects in the application.
Silverlight Events
Generally speaking, Silverlight events are CLR events, and therefore are events that you can handle with managed code. If you know how to work with basic CLR events already, you have a head start on some of the concepts involved. But you do not necessarily need to know that much about the CLR event model in order to perform some basic tasks, such as attaching handlers. (If you want some more conceptual background, see Events, Delegates, and CLR Event System Conventions.)
Because the UI is defined in markup (XAML) some of the principles are similar to other Web technologies, such as ASP.NET, or working with an HTML DOM.
Silverlight also has a few events that require handlers on the plug-in instance itself, such as the OnError event. These events are exposed and possibly handled by any script working against the plug-in instance in the HTML DOM. HTML scripting should have first chance to do the handling, so these events are not passed on to the managed API.
Note: |
|---|
Because Silverlight operates within the plug-in architecture of the hosting browser, the input stimulus for input events is initially handled by the browser. The input information is then sent to the Silverlight plug-in through that browser's API for general plug-in support, and you can handle the corresponding events defined in the Silverlight API. Most other non-input events in Silverlight do not necessarily have such browser implications. |
Button.Click: An Introduction to Using Silverlight Events
Because Silverlight is a UI technology, one of the most common tasks you have is to capture user input to the UI. For example, your UI might have a button that the user must click to submit information or change your application's state.
Generally, you define the UI for your Silverlight-based application by generating XAML. This XAML can be the output from a designer such as Expression Blend 2 SP1, a design surface such as Silverlight Designer for Visual Studio, or it can also be written out in a text editor. As part of generating that XAML, you can wire event handlers for individual UI elements at the same time that you define all the other attributes that describe that UI element. Event wiring in XAML involves providing the name of the handler method. For example, the following XAML defines a Button object with some important properties assigned as attributes, and wires a handler for the button's Click event:
<Button Name="showUpdatesButton" Content="{Binding ShowUpdatesText}" Click="showUpdatesButton_Click"/>
The actual handler is written in one of the programming languages that are supported by the .NET Framework for Silverlight, such as Visual Basic or C#. With the attribute Click="showUpdatesButton_Click", you have created a contract that when the XAML is compiled, the XAML compiler can find a method named showUpdatesButton_Click defined in the code-behind for that XAML page. Moreover, showUpdatesButton_Click must be a method that implements the specific method signature (based on a delegate) that is required for any handler of the Click event.
For example, the following code defines the showUpdatesButton_Click handler.
private void showUpdatesButton_Click (object sender, RoutedEventArgs e) {
Button b = e.OriginalSource as Button;
//more logic to do here...
...
}
If you are using Silverlight Designer for Visual Studio, you can use design features that make it very simple to wire event handlers from XAML then define them in code-behind. This includes providing a naming scheme for the handlers based on characteristics of the element and matching the correct delegate signature of the event being handled. Otherwise, you can use the .NET Framework Class Library for Silverlight documentation to look up the event and determine its delegate. The handler you write must match that delegate signature. For the previously shown example, the delegate is RoutedEventHandler.
Note: |
|---|
Silverlight event-handler functions cannot be called with parameter values (even empty ones), which is a notable difference from event handler syntax in the HTML DOM. The attribute value simply references the handler name, and other mechanisms like the expected input parameters of your handler take care of passing information. |
Defining an Event Handler
For objects that are UI declared in XAML, event handler code must be defined in the partial class that serves as the code-behind for a XAML page. For more information about how partial classes and code-behind for XAML work together, see Code-Behind and Partial Classes.
Event handlers in the partial class are written as methods, based on the CLR delegates that are used by that particular event. Your event handler methods can be public, or they can have a private access level. Private access works because the handler and instance created by the XAML are ultimately joined by code generation. The general recommendation is to not make your event handler methods public in the class.
The sender Parameter and Event Data
Any handler you write for a managed Silverlight event can access two values that are available as input for each case where your handler is invoked. The first such value is sender. sender is a reference to the object where the handler is attached. sender is typed as the base Object type. A common technique in Silverlight (and WPF) event handling is to cast sender to a more precise type, if you expect to check or change state on the sender object itself, and you know a type that it is safe to cast sender to based on where you know the handler is attached or other specific information about your application.
The second value is event data, which generally appears in signatures as the e parameter. Per the CLR event model, all events send some kind of event data, with that data captured as an instance of a class that somehow inherits EventArgs (or is EventArgs itself). You can discover which properties for event data are available by looking at the e parameter of the delegate that is assigned for the specific event you are handling, and then using Intellisense in Visual Studio or the .NET Reference Library for Silverlight.
For some events, the event data in the EventArgs derived class is as important as knowing that the event was raised. This is particularly true of the input events. For mouse events, the position of the mouse when the event occurred might be important. For keyboard events, keys on the keyboard raise the same KeyUp and KeyDown events. In order to determine which key was pressed, you must access the KeyEventArgs that is available to the event handler.
Note: |
|---|
For more information about handling input events, see Mouse Support and Keyboard Support. Input events often have additional considerations that are not covered in this topic, such as mouse capture for mouse events, and modifier keys and platform key codes for keyboard events. |
Adding Event Handlers in Managed Code
XAML is not the only way to assign an event handler to an object. To add event handlers to any given object in managed code, including to objects that are not even usable in XAML, you can use the CLR-language-specific syntax for adding event handlers. In C#, the syntax is to use the += operator, and to instantiate the handler by declaring a new delegate using the event handler method name.
If you are using code to add event handlers to objects that do appear in the run-time UI, a common practice for Silverlight is to add such handlers in response to an object lifetime event such as Loaded or OnApplyTemplate, so that the event handlers on the relevant object are ready for user-initiated events at run time. The following example illustrates first the XAML outline to give some idea of the structure, then the C# language syntax.
<Grid x:Name="LayoutRoot" Loaded="LayoutRoot_Loaded">
<StackPanel>
<TextBlock Name="textBlock1">Put the mouse over this text</TextBlock>
...
</StackPanel>
</Grid>
void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
{
textBlock1.MouseEnter += new MouseEventHandler(textBlocks_MouseEnter);
textBlock1.MouseLeave += new MouseEventHandler(textBlocks_MouseLeave);
}
There are two possibilities for Visual Basic syntax. One is to parallel the C# syntax and attach handlers directly to instances. This requires the AddHandler function as well as the AddressOf operator that dereferences the handler method name.
Private Sub LayoutRoot_Loaded(ByVal sender As Object, ByVal e As RoutedEventArgs e)
AddHandler textBlock1.MouseEnter, AddressOf textBlocks_MouseEnter
AddHandler textBlock1.MouseLeave, AddressOf textBlocks_MouseLeave
End Sub
The other option for Visual Basic syntax is to use the Handles keyword on event handlers. This technique is appropriate for cases where handlers are expected to exist on objects at load time and persist throughout the object lifetime. Using Handles on an object that is defined in XAML requires that you provide a Name / x:Name. This name becomes the instance qualifier that is needed for the Instance.Event part of the Handles syntax. In this case you do not need an object lifetime-based event handler to initiate attaching the other event handlers; the Handles connections are created when you compile your XAML page.
Sub textBlock1_MouseEnter(ByVal sender As Object, ByVal e As MouseEventArgs) Handles textBlock1.MouseEnter
'....
End Sub
Sub textBlock1_MouseLeave(ByVal sender As Object, ByVal e As MouseEventArgs) Handles textBlock1.MouseLeave
'....
End Sub
Silverlight supports the concept of a routed event for several input events that are defined in base classes and are present on most UI elements that support user interaction and input:
A routed event is an event that is potentially passed on (routed) from a child object to each of its successive parent objects in the object tree. The object tree in question is approximated by the XAML structure of your UI, with the root of that tree being the root element in XAML. The true object tree might vary somewhat from the XAML because the object tree does not include XAML language features such as property element tags, but in general you can think of the routed events as "bubbling" from XAML object element children that raise the event, towards the parent object element that contains them, and continuing to route until the root element is reached. (If you have used certain Web technologies such as DHTML before, the "bubbling" concept might already be familiar to you.)
Note: |
|---|
WPF supports an analogous "tunneling" routing strategy, whereby the root of a page / object tree has the first chance to handle a routed event, and the event then "tunnels" down the object tree toward its event source. Silverlight does not use "tunneling" routed events. Events in Silverlight either follow the "bubbling" routing strategy (and are referred to as routed events) or do not route at all. There are also other API-level differences in routed event behavior between Silverlight and WPF. |
The OriginalSource Property of RoutedEventArgs
When an event bubbles up an event route, sender is no longer the same object as the event-raising object. Instead, sender is the object where the handler that is being invoked is attached. In many cases, sender is not the object of interest, and you are instead interested in knowing information such as which of the possible child objects the mouse is over, or which object held focus when a keyboard key was pressed. For these cases, the value of the OriginalSource property is the object of interest.
At all points on the route, OriginalSource reports the original object that raised the event, rather than where the handler is attached For an example scenario where this is useful, consider an application where you want certain key combinations to be "hot keys" or accelerators, regardless of which control currently holds keyboard focus and initiated the event. In terms of the object tree, the focused object might be nested within some items list in a list box, or could be one of hundreds of objects in the overall UI. Having to attach handlers to every possible focusable object in an application to detect your accelerator is obviously impractical. But because the keyboard events are bubbling routed events, the event eventually reaches the root object in its route. Therefore, you can often attach a single KeyDown handler on the root object and rely on the behavior that a KeyDown event eventually bubbles to the root object. Then the handler can determine whether that key is the valid combination for an intended accelerator action, or whether no action is necessary.
Tip: |
|---|
Using input bubbling to your advantage is particularly useful if you are creating a templatable control, in which case you do not even always have the opportunity to define the handlers for the template parts because your control has potentially been user-retemplated. |
The Handled Property
Several event data classes for specific routed events contain a property named Handled. For examples, see MouseButtonEventArgs..::.Handled, KeyEventArgs..::.Handled, MouseWheelEventArgs..::.Handled, and ValidationErrorEventArgs..::.Handled. Handled is a settable Boolean property.
Setting the Handled property to true influences the event system in Silverlight. When you set the value to true in event data, the routing stops for purposes of most event handlers; the event does not continue along the route to notify other attached handlers of that particular event case. What "handled" as an action means in the context of the event and how your application responds, is entirely up to you. However, you should definitely be aware of this behavior of the Silverlight event system when you choose to set Handled in your event handlers.
Not all of the routed events are cancellable in this way. GotFocus, LostFocus, and MouseMove will always route all the way to the root, and their event data classes do not have a Handled property that can influence that behavior. Therefore, checking OriginalSource values for those events is often a good idea, to make sure you are not handling an event and making incorrect assumptions about what the event means and how it was sourced.
Note: |
|---|
The concept of a Handled property for routed events also exists in WPF. In WPF, the Handled property exists on all routed event-data classes; in Silverlight only the specific event data classes that have their own Handled property can be used to cancel the related event's route. |
Routed Events Outside the Visual Tree
Certain objects in Silverlight participate in a relationship with the primary visual tree that is conceptually like an overlay over the main visuals, and are not part of the usual parent-child relationships that connects all tree elements to the visual root. This is the case for any displayed Popup or ToolTip. If you want to handle routed events from a Popup or ToolTip, you should place the handlers on specific UI elements that are within the Popup or ToolTip and not the Popup or ToolTip elements themselves, and you should not rely on routing inside any compositing that is done for Popup or ToolTip content. This is because event routing for routed events works only along the main visual tree. Popup or ToolTip are not considered parents of subsidiary UI elements, and never receive the routed event, even if are trying to use something like the Popup default background as the capture area for input events.
Input Event Handlers in Controls
Specific existing Silverlight controls sometimes use this Handled concept for input events internally. This can give the appearance from user code that an input event never occurs. For example, the Button class includes logic that deliberately handles the general input event MouseLeftButtonDown. It does so because the class raises a Click event that is initiated by that mouse input. For purposes of the class design the raw mouse event is conceptually handled, and class consumers should instead choose to handle or not handle Click. Reference for specific controls pages in the .NET Framework Library often note the event handling behavior implemented by the class. In some cases, the behavior can be altered or appended in subclasses by overriding OnEvent methods. For example, you can change how your TextBox derived class reacts to key input by overriding TextBox..::.OnKeyDown.
Registering Handlers for Already-Handled Routed Events
Earlier it was stated that setting Handled to true prevented most handlers from acting. The API AddHandler provides a technique whereby you can attach a handler that will always be invoked for the route, even if some other handler earlier in the route has set Handled to true. This technique is useful if a control you are using has handled the event in its internal compositing or for control-specific logic but you still want to respond to it on a control instance, or higher in the route. However, this technique should be used with caution, because it can contradict the purpose of Handled and possibly a control's intended usage.
For more information including a usage example, see AddHandler.
User-initiated Events, Full-screen Mode
Silverlight enforces that certain operations are only permitted in the context of a handler that handles a user-initiated event:
Silverlight user-initiated events include the mouse events (such as MouseLeftButtonDown), and the keyboard events (such as KeyDown). Events of controls that are based on such events (such as Click) are also considered user-initiated.
Once Silverlight is in full-screen mode, some input events are deliberately suppressed for security reasons. For more information, see Full-Screen Support.
Programming Model Alternatives
This topic specifically discusses Silverlight events and the managed API. But you could also use the Silverlight JavaScript API for event handling for a XAML page, which is appropriate for a limited range of scenarios such as splash screens or similar XAML-based UI that is visual in character but not particularly interactive.
You declare the event handling model at the page level by including or excluding the x:Class attribute on the root element. If the x:Class attribute exists, the page uses the managed API. This is the default for most if not all XAML page templates produced by development tools for Silverlight. To use the JavaScript API for event handling, make sure the XAML page does not declare an x:Class attribute.
For a description of the JavaScript API for event handling, see Handling Silverlight Events by Using JavaScript.
In some circumstances, you might want to remove event handlers during the application lifetime. To remove event handlers, you use the CLR-language-specific syntax. In C#, you use the -= operator. In Visual Basic, you use the RemoveHandler function. In either case, you reference the event handler method name (textBlocks_MouseEnter) as well as the target object where the handler is to be removed (textBlock1).
Private Sub Cleanup()
RemoveHandler textBlock1.MouseEnter, AddressOf textBlocks_MouseEnter
End Sub
You can also remove handlers for cases where the event was added through a XAML attribute. This is easier to do if you provided a Name value for the element where the handler was attached because that provides an object reference for code later, but you could also walk the object tree in order to find the necessary object reference if you had to.
If you are interested in defining your own events for your own controls or other types, see Defining Events for Custom Silverlight Classes.
If you want to learn more about Silverlight input events specifically, see Mouse Support or Keyboard Support. Other types of input that involve events that were not discussed in this topic include ink, multi-touch, and mouse wheel events. See Ink Overview, Touch, or Mouse Wheel Input.
If you are interested in learning more about the CLR event system concepts that apply to Silverlight, see Events, Delegates, and CLR Event System Conventions.
Concepts