* Add article, toc, and redirects * Add a prerequisites section to 3 other event articles * Further edits * Update dotnet-desktop-guide/net/wpf/toc.yml Co-authored-by: Andy (Steve) De George <[email protected]> * Update article links * Minor clarification Co-authored-by: Andy (Steve) De George <[email protected]>
7.8 KiB
title, description, ms.date, dev_langs, helpviewer_keywords
| title | description | ms.date | dev_langs | helpviewer_keywords | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Preview events | Learn about preview events in Windows Presentation Foundation (WPF) and how to use preview events for composite control event handling. | 03/09/2022 |
|
|
Preview events (WPF .NET)
Preview events, also known as tunneling events, are routed events that traverse downward through the element tree from the application root element to the element that raised the event. The element that raises an event is reported as the xref:System.Windows.RoutedEventArgs.Source in the event data. Not all event scenarios support or require preview events. This article describes where preview events exist and how applications or components can interact with them. For information on how to create a preview event, see How to create a custom routed event.
[!INCLUDE desktop guide under construction]
Prerequisites
The article assumes a basic knowledge of routed events, and that you've read Routed events overview. To follow the examples in this article, it helps if you're familiar with Extensible Application Markup Language (XAML) and know how to write Windows Presentation Foundation (WPF) applications.
Preview events marked as handled
Be cautious when marking preview events as handled in event data. Marking a preview event as handled on an element other than the element that raised it can prevent the element that raised it from handling the event. Sometimes marking preview events as handled is intentional. For example, a composite control might suppress events raised by individual components and replace them with events raised by the complete control. Custom events for a control can provide customized event data and trigger based on component state relationships.
For input events, event data is shared by both the preview and non-preview (bubbling) equivalents of each event. If you use a preview event class-handler to mark an input event as handled, class-handlers for the bubbling input event typically won't be invoked. Or, if you use a preview event instance-handler to mark an event as handled, instance-handlers for the bubbling input event typically won't be invoked. Although you can configure class and instance handlers to be invoked even if an event is marked as handled, that handler configuration isn't common. For more information about class handling and how it relates to preview events, see Marking routed events as handled and class handling.
Note
Not all preview events are tunneling events. For example, the xref:System.Windows.UIElement.PreviewMouseLeftButtonDown input event follows a downward route through the element tree, but is a direct routed event that's raised and reraised by each xref:System.Windows.UIElement in the route.
Preview events in composite controls
Preview events are commonly used by composite controls to handle input events raised by their components. For example, a composite control may suppress input events at the component level and replace them with one or more events that provide customized event data. For example, the WPF xref:System.Windows.Controls.Primitives.ButtonBase marks the xref:System.Windows.UIElement.MouseLeftButtonDown input event as handled in its xref:System.Windows.UIElement.OnMouseLeftButtonDown%2A method and raises the xref:System.Windows.Controls.Primitives.ButtonBase.Click event. The MouseLeftButtonDown event and its event data still continue along the element tree route, but because the event is marked as xref:System.Windows.RoutedEventArgs.Handled%2A in event data, only handlers that are configured to respond to handled events are invoked.
If you want other elements toward the root of your application to handle a routed event that's marked as handled, you can either:
-
Attach handlers by calling the xref:System.Windows.UIElement.AddHandler(System.Windows.RoutedEvent,System.Delegate,System.Boolean)?displayProperty=nameWithType method and setting the parameter
handledEventsToototrue. This approach requires attaching the event handler in code-behind, after obtaining an object reference to the element that it will attach to. -
If the event marked as handled is a bubbling event, attach handlers for the equivalent preview event if available. For instance, if a control suppresses the xref:System.Windows.UIElement.MouseLeftButtonDown event, you can attach a handler for the xref:System.Windows.UIElement.PreviewMouseLeftButtonDown event instead. This approach only works for base element input events that implement both tunneling and bubbling routing strategies and share event data.
The following example implements a rudimentary custom control named componentWrapper that contains a xref:System.Windows.Controls.TextBox. The control is added to a xref:System.Windows.Controls.StackPanel named outerStackPanel.
:::code language="xaml" source="./snippets/preview-events/csharp/MainWindow.xaml" id="CustomControlEventSuppression":::
The componentWrapper control listens for the xref:System.Windows.UIElement.KeyDown bubbling event raised by its TextBox component whenever a keystroke occurs. On that occurrence, the componentWrapper control:
-
Marks the
KeyDownbubbling routed event as handled to suppress it. As a result, only theouterStackPanelhandler that's configured in code-behind to respond to handledKeyDownevents is triggered. TheouterStackPanelhandler attached in XAML forKeyDownevents isn't invoked. -
Raises a custom bubbling routed event named
CustomKey, which triggers theouterStackPanelhandler for theCustomKeyevent.
:::code language="csharp" source="./snippets/preview-events/csharp/MainWindow.xaml.cs" id="EventSuppressionWorkarounds"::: :::code language="vb" source="./snippets/preview-events/vb/MainWindow.xaml.vb" id="EventSuppressionWorkarounds":::
The example demonstrates two workarounds for getting the suppressed KeyDown routed event to invoke an event handler attached to the outerStackPanel:
-
Attach a xref:System.Windows.UIElement.PreviewKeyDown event handler to the
outerStackPanel. Since a preview input routed event precedes the equivalent bubbling routed event, thePreviewKeyDownhandler in the example runs ahead of theKeyDownhandler that suppresses both preview and bubbling events through their shared event data. -
Attach a
KeyDownevent handler to theouterStackPanelby using the xref:System.Windows.UIElement.AddHandler(System.Windows.RoutedEvent,System.Delegate,System.Boolean)?displayProperty=nameWithType method in code-behind, with thehandledEventsTooparameter set totrue.
Note
Marking preview or non-preview equivalents of input events as handled are both strategies for suppressing events raised by the components of a control. The approach you use depends on your application requirements.