Поделиться через


Events Overview for Silverlight

Microsoft Silverlight will reach end of support after October 2021. Learn more.

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 (CLR) 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
  • Button.Click: An Introduction to Using Silverlight Events
  • Defining an Event Handler
  • The sender Parameter and Event Data
  • Adding Event Handlers in Managed Code
  • Routed Events
  • Input Event Handlers in Controls
  • User-Initiated Events
  • Programming Model Alternatives
  • Removing Event Handlers
  • Commanding
  • What's Next
  • Related Topics

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 for a typical Silverlight-based application is defined in markup (XAML), some of the principles of connecting UI events from markup elements to a runtime code entity are similar to other Web technologies, such as ASP.NET, or working with an HTML DOM. In Silverlight and WPF, the code that provides the runtime logic for a XAML-defined UI is often referred to as code-behind or the code-behind file. In the Visual Studio solution views, this relationship is shown graphically, with the code-behind file being a dependent and nested file versus the XAML page it refers to.

In addition to the CLR events that act within its own runtime object model, Silverlight also has a few events that can invoke script-based handlers on the plug-in instance itself and at the HTML level, such as OnError. These events are exposed and can be handled by any script working against the plug-in instance in the HTML DOM. As a general event model for an application, HTML scripting should have first chance to do the handling, and if you handle events in an HTML, these events should not be passed on to the managed API.

NoteNote:

Because Silverlight often operates within the plug-in architecture of the hosting browser, the input stimulus for input events is initially handled by the browser host. 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 Microsoft Expression Blend or from a design surface in a larger IDE such as Silverlight Designer for Visual Studio. The XAML can also be written out in a plaintext editor or a third-party XAML 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 specifying the string-form name of the handler method that you define in your code-behind. 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 markup-compiled and parsed, both the XAML markup compile step in your development environment's build action and the eventual Silverlight runtime that parses the XAML can find a method named showUpdatesButton_Click. Moreover, showUpdatesButton_Click must be a method that implements a compatible method signature (based on a delegate) 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...
...
}
Private Sub showUpdatesButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
    Dim b As Button = CType(e.OriginalSource, Button)
    ' more logic to do here...
End Sub

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 and then define them in code-behind. This includes providing an automatic naming scheme for the handlers. For more information, see Walkthrough: Creating Your First Silverlight Application.

You can also use the .NET Framework Class Library for Silverlight documentation to look up a specific event and determine its delegate. The handler you write must be compatible with that delegate signature. For the previously shown example, the best matching delegate is RoutedEventHandler.

NoteNote:

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 in XAML references the handler name only, and other mechanisms, such as the expected input parameters of your handler, pass the information.

Defining an Event Handler

For objects that are UI and 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, which is a reference to the object where the handler is attached. The sender parameter 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. This technique is useful if you expect to check or change state on the sender object itself. Based on your own application design, you expect a type that is safe to cast sender to, based on where the handler is attached or other design specifics.

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 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 Framework Class Library for Silverlight. Some Silverlight events use the EventHandler<TEventArgs> delegate or other generic handler types. An example is ColumnReordered. In most cases, the event definitions constrains the generic with a specific EventArgs derived event data class. You should then write the handler method as if it took that EventArgs derived event data class directly as the second parameter.

For some events, the event data in the EventArgs derived class is as important as knowing that the event was raised. This is especially true of the input events. For mouse events, the position of the mouse when the event occurred might be important. For keyboard events, key presses 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.

For more information about handling input events, see Mouse Support and Keyboard Support. Input events and input scenarios 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. You instantiate the handler by declaring a new delegate that uses the event handler method name.

If you are using code to add event handlers to objects that appear in the run-time UI, a common practice for Silverlight is to add such handlers in response to an object lifetime event or callback, 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 and then provides 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 keyword and also 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
NoteNote:

Visual Studio and its XAML design surface generally promote the instance-handling technique instead of the Handles keyword. This is because establishing the event handler wiring in XAML is part of typical designer-developer workflow for Silverlight and WPF, and the Handles keyword technique is incompatible with wiring the event handlers in XAML.

Routed Events

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. The following is a list of input events that are routed events:

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. In general you can think of the routed events as "bubbling" from XAML object element children that raise the event, toward the parent object element that contains them. The event occurrence and its event data continue and are reported to objects along the event route until the root element is reached. (If you have used certain Web technologies such as DHTML, the "bubbling" concept might already be familiar to you.)

NoteNote:

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, instead of 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.

TipTip:

Using input bubbling to your advantage is especially useful if you are creating a templated control. Any control that has a template can have a new template applied by its consumer and therefore, might potentially eliminate any event handling declared in the default template XAML. You can still provide control-level event handling by attaching handlers as part of the OnApplyTemplate override in the class definition and catch the input events that bubble up to the control's root.

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, DragEventArgs.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 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 up to you. However, you should keep in mind the behavior of the Silverlight event system if you 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 where the input event originated in the UI layout.

NoteNote:

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. These objects are not part of the usual parent-child relationships that connect 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. You should not rely on routing inside any compositing that is performed for Popup or ToolTip content. This is because event routing for routed events works only along the main visual tree. Popup or ToolTip is not considered a parent of subsidiary UI elements and never receives the routed event, even if it is 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 topics for specific control classes in the .NET Framework Library often note the event handling behavior implemented by the class. In some cases, the behavior can be changed 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 where 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 violate a control's intended usage or object model.

For more information including a usage example, see AddHandler.

User-Initiated Events

Silverlight enforces that certain operations are only permitted in the context of a handler that handles a user-initiated event. The following is a list of such operations:

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.

API calls that require user initiation should be called as soon as possible in an event handler. This is because the Silverlight user initiation concept also requires that the calls occur within a certain time window after the event occurrence. In Silverlight 5, this time window is approximately one second.

User-initiated event restrictions also apply to usages of JavaScript API for Silverlight.

When Silverlight is in full-screen mode, some input events are deliberately limited for security reasons, although this can be mitigated for out-of-browser applications using elevated trust. 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 JavaScript API for Silverlight to perform event handling for a XAML page. JavaScript API for Silverlight is appropriate for a limited range of scenarios such as splash screens or similar XAML-based UI that is visual in character but not especially interactive.

You declare the event handling model (managed API versus JavaScript API) 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. Including x:Class and using managed API 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.

Removing Event Handlers

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

The following code shows how to remove an event handler named textBlocks_MouseEnter from the target object textBlock1.

void Cleanup()
{
    textBlock1.MouseEnter -= textBlocks_MouseEnter;
}
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; however, you could also walk the object tree in order to find the necessary object reference if you had to.

Commanding

In Silverlight 5, a small number of UI elements support commanding. Commanding uses input-related routed events in its underlying implementation and enables processing of related UI input (a certain mouse action, a specific accelerator key) by invoking a single command handler. If commanding is available for a UI element, consider using its commanding APIs instead of any discrete input events. For more information, see one of the following:

ButtonBase.Command

Hyperlink.Command

What's Next

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.