mirror of
https://github.com/Stone-Red-Code/docs-desktop.git
synced 2026-09-04 00:56:03 +02:00
merge main branch
This commit is contained in:
@@ -636,6 +636,14 @@
|
||||
{
|
||||
"source_path": "dotnet-desktop-guide/framework/wpf/events/preview-events.md",
|
||||
"redirect_url": "/dotnet/desktop/wpf/advanced/preview-events?view=netframeworkdesktop-4.8"
|
||||
},
|
||||
{
|
||||
"source_path": "dotnet-desktop-guide/net/wpf/advanced/marking-routed-events-as-handled-and-class-handling.md",
|
||||
"redirect_url": "/dotnet/desktop/wpf/events/marking-routed-events-as-handled-and-class-handling?view=netdesktop-6.0"
|
||||
},
|
||||
{
|
||||
"source_path": "dotnet-desktop-guide/framework/wpf/events/marking-routed-events-as-handled-and-class-handling.md",
|
||||
"redirect_url": "/dotnet/desktop/wpf/advanced/marking-routed-events-as-handled-and-class-handling?view=netframeworkdesktop-4.8"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
---
|
||||
title: "Marking routed events as handled, and class handling"
|
||||
description: Learn about class handling of routed events in Windows Presentation Foundation (WPF) and when to mark a routed event as handled.
|
||||
ms.date: "03/21/2022"
|
||||
dev_langs:
|
||||
- "csharp"
|
||||
- "vb"
|
||||
helpviewer_keywords:
|
||||
- "tunneling events [WPF]"
|
||||
- "class listeners [WPF]"
|
||||
- "listeners [WPF]"
|
||||
- "Preview routed events [WPF]"
|
||||
- "instance listeners [WPF]"
|
||||
- "events [WPF], bubbling"
|
||||
- "suppressing events [WPF]"
|
||||
- "routed events [WPF], preview"
|
||||
- "composited controls [WPF]"
|
||||
- "events [WPF], tunneling"
|
||||
- "routed events [WPF], marking as handled"
|
||||
- "controls [WPF], compositing"
|
||||
- "events [WPF], suppressing"
|
||||
- "bubbling events [WPF]"
|
||||
---
|
||||
<!--The acrolinx score was 95 on 03/21/2022-->
|
||||
|
||||
# Marking routed events as handled, and class handling (WPF .NET)
|
||||
|
||||
Although there's no absolute rule for when to mark a routed event as handled, consider marking an event as handled if your code responds to the event in a significant way. A routed event that's marked as handled will continue along its route, but only handlers that are configured to respond to handled events are invoked. Basically, marking a routed event as handled limits its visibility to listeners along the event route.
|
||||
|
||||
Routed event handlers can be either instance handlers or class handlers. Instance handlers handle routed events on objects or XAML elements. Class handlers handle a routed event at a class level, and are invoked before any instance handler responding to the same event on any instance of the class. When routed events are marked as handled, they're often marked as such within class handlers. This article discusses the benefits and potential pitfalls of marking routed events as handled, the different types of routed events and routed event handlers, and event suppression in composite controls.
|
||||
|
||||
[!INCLUDE [desktop guide under construction](../../includes/desktop-guide-preview-note.md)]
|
||||
|
||||
## Prerequisites
|
||||
|
||||
The article assumes a basic knowledge of routed events, and that you've read [Routed events overview](/dotnet/desktop/wpf/advanced/routed-events-overview?view=netframeworkdesktop-4.8&preserve-view=true). 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.
|
||||
|
||||
## When to mark routed events as handled
|
||||
|
||||
Typically, only one handler should provide a significant response for each routed event. Avoid using the routed event system to provide a significant response across multiple handlers. The definition of what constitutes a significant response is subjective and depends on your application. As general guidance:
|
||||
|
||||
- Significant responses include setting focus, modifying public state, setting properties that affect visual representation, raising new events, and completely handling an event.
|
||||
- Insignificant responses include modifying private state without visual or programmatic impact, event logging, and examining event data without responding to the event.
|
||||
|
||||
Some WPF controls suppress component-level events that don't need further handling by marking them as handled. If you want to handle an event that was marked as handled by a control, see [Working around event suppression by controls](#working-around-input-event-suppression).
|
||||
|
||||
To mark an event as _handled_, set the <xref:System.Windows.RoutedEventArgs.Handled%2A> property value in its event data to `true`. Although it's possible to revert that value to `false`, the need to do so should be rare.
|
||||
|
||||
## Preview and bubbling routed event pairs
|
||||
|
||||
[Preview](preview-events.md) and bubbling routed event pairs are specific to [input events](/dotnet/desktop/wpf/advanced/input-overview). Several input events implement a [tunneling](<xref:System.Windows.RoutingStrategy.Tunnel>) and [bubbling](<xref:System.Windows.RoutingStrategy.Bubble>) routed event pair, such as <xref:System.Windows.UIElement.PreviewKeyDown> and <xref:System.Windows.UIElement.KeyDown>. The `Preview` prefix signifies that the bubbling event starts once the preview event completes. Each preview and bubbling event pair shares the same instance of event data.
|
||||
|
||||
Routed event handlers are invoked in an order that corresponds to an event's routing strategy:
|
||||
|
||||
1. The preview event travels from the application root element down to the element that raised the routed event. Preview event handlers attached to the application root element get invoked first, followed by handlers attached to successive nested elements.
|
||||
1. After the preview event completes, the paired bubbling event travels from the element that raised the routed event to the application root element. Bubbling event handlers attached to the same element that raised the routed event get invoked first, followed by handlers attached to successive parent elements.
|
||||
|
||||
Paired preview and bubbling events are part of the internal implementation of several WPF classes that declare and raise their own routed events. Without that class-level internal implementation, preview and bubbling routed events are entirely separate and won't share event data—regardless of event naming. For information about how to implement bubbling or tunneling input routed events in a custom class, see [Create a custom routed event](how-to-create-a-custom-routed-event.md).
|
||||
|
||||
Because each preview and bubbling event pair shares the same instance of event data, if a preview routed event is marked as handled then its paired bubbling event will also be handled. If a bubbling routed event is marked as handled, it won't affect the paired preview event because the preview event completed. Be careful when marking preview and bubbling input event pairs as handled. A handled preview input event won't invoke any normally registered event handlers for the remainder of the tunneling route, and the paired bubbling event won't be raised. A handled bubbling input event won't invoke any normally registered event handlers for the remainder of the bubbling route.
|
||||
|
||||
## Instance and class routed event handlers
|
||||
|
||||
Routed event handlers can be either _instance_ handlers or _class_ handlers. Class handlers for a given class are invoked before any instance handler responding to the same event on any instance of that class. Due to this behavior, when routed events are marked as handled, they're often marked as such within class handlers. There are two types of class handlers:
|
||||
|
||||
- [Static class event handlers](#static-class-event-handlers), which are registered by calling the <xref:System.Windows.EventManager.RegisterClassHandler%2A> method within a static class constructor.
|
||||
- [Override class event handlers](#override-class-event-handlers), which are registered by overriding base class virtual event methods. Base class virtual event methods primarily exist for input events, and have names that start with **On\<event name\>** and **OnPreview\<event name\>**.
|
||||
|
||||
### Instance event handlers
|
||||
|
||||
You can attach instance handlers to objects or XAML elements by directly calling the <xref:System.Windows.UIElement.AddHandler%2A> method. WPF routed events implement a common language runtime (CLR) event wrapper that uses the `AddHandler` method to attach event handlers. Since XAML attribute syntax for attaching event handlers results in a call to the CLR event wrapper, even attaching handlers in XAML resolves to an `AddHandler` call. For handled events:
|
||||
|
||||
- Handlers that are attached using XAML attribute syntax or the common signature of `AddHandler` aren't invoked.
|
||||
- Handlers that are attached using the <xref:System.Windows.UIElement.AddHandler%28System.Windows.RoutedEvent%2CSystem.Delegate%2CSystem.Boolean%29> overload with the `handledEventsToo` parameter set to `true` are invoked. This overload is available for the rare cases when it's necessary to respond to handled events. For example, some element in an element tree has marked an event as handled, but other elements further along the event route need to respond to the handled event.
|
||||
|
||||
The following XAML sample adds a custom control named `componentWrapper`, which wraps a <xref:System.Windows.Controls.TextBox> named `componentTextBox`, to a <xref:System.Windows.Controls.StackPanel> named `outerStackPanel`. An instance event handler for the <xref:System.Windows.UIElement.PreviewKeyDown> event is attached to the `componentWrapper` using XAML attribute syntax. As a result, the instance handler will only respond to unhandled `PreviewKeyDown` tunneling events raised by the `componentTextBox`.
|
||||
|
||||
:::code language="xaml" source="./snippets/marking-routed-events-as-handled-and-class-handling/csharp/MainWindow.xaml" id="InstanceEventHandling":::
|
||||
|
||||
The `MainWindow` constructor attaches an instance handler for the `KeyDown` bubbling event to the `componentWrapper` using the <xref:System.Windows.UIElement.AddHandler(System.Windows.RoutedEvent,System.Delegate,System.Boolean)?displayProperty=nameWithType> overload, with the `handledEventsToo` parameter set to `true`. As a result, the instance event handler will respond to both unhandled and handled events.
|
||||
|
||||
:::code language="csharp" source="./snippets/marking-routed-events-as-handled-and-class-handling/csharp/MainWindow.xaml.cs" id="InstanceEventHandling":::
|
||||
:::code language="vb" source="./snippets/marking-routed-events-as-handled-and-class-handling/vb/MainWindow.xaml.vb" id="InstanceEventHandling":::
|
||||
|
||||
The code-behind implementation of `ComponentWrapper` is shown in the next section.
|
||||
|
||||
### Static class event handlers
|
||||
|
||||
You can attach static class event handlers by calling the <xref:System.Windows.EventManager.RegisterClassHandler%2A> method in the static constructor of a class. Each class in a class hierarchy can register its own static class handler for each routed event. As a result, there can be multiple static class handlers invoked for the same event on any given node in the event route. When the event route for the event is constructed, all static class handlers for each node are added to the event route. The order of invocation of static class handlers on a node starts with the most-derived static class handler, followed by static class handlers from each successive base class.
|
||||
|
||||
Static class event handlers registered using the <xref:System.Windows.EventManager.RegisterClassHandler%28System.Type%2CSystem.Windows.RoutedEvent%2CSystem.Delegate%2CSystem.Boolean%29> overload with the `handledEventsToo` parameter set to `true` will respond to both unhandled and handled routed events.
|
||||
|
||||
Static class handlers are typically registered to respond to unhandled events only. In which case, if a derived class handler on a node marks an event as handled, base class handlers for that event won't be invoked. In that scenario, the base class handler is effectively replaced by the derived class handler. Base class handlers often contribute to control design in areas such as visual appearance, state logic, input handling, and command handling, so be cautious about replacing them. Derived class handlers that don't mark an event as handled end up supplementing the base class handlers instead of replacing them.
|
||||
|
||||
The following code sample shows the class hierarchy for the `ComponentWrapper` custom control that was referenced in the preceding XAML. The `ComponentWrapper` class derives from the `ComponentWrapperBase` class, which in turn derives from the <xref:System.Windows.Controls.StackPanel> class. The `RegisterClassHandler` method, used in the static constructor of the `ComponentWrapper` and `ComponentWrapperBase` classes, registers a static class event handler for each of those classes. The WPF event system invokes the `ComponentWrapper` static class handler ahead of the `ComponentWrapperBase` static class handler.
|
||||
|
||||
:::code language="csharp" source="./snippets/marking-routed-events-as-handled-and-class-handling/csharp/MainWindow.xaml.cs" id="ClassEventHandling":::
|
||||
:::code language="vb" source="./snippets/marking-routed-events-as-handled-and-class-handling/vb/MainWindow.xaml.vb" id="ClassEventHandling":::
|
||||
|
||||
The code-behind implementation of the override class event handlers in this code sample is discussed in the next section.
|
||||
|
||||
### Override class event handlers
|
||||
|
||||
Some visual element base classes expose empty **On\<event name\>** and **OnPreview\<event name\>** virtual methods for each of their public routed input events. For example, <xref:System.Windows.UIElement> implements the <xref:System.Windows.UIElement.OnKeyDown%2A> and <xref:System.Windows.UIElement.OnPreviewKeyDown%2A> virtual event handlers, and many others. You can override base class virtual event handlers to implement override class event handlers for your derived classes. For example, you can add an override class handler for the <xref:System.Windows.UIElement.DragEnter> event in any `UIElement` derived class by overriding the <xref:System.Windows.UIElement.OnDragEnter%2A> virtual method. Overriding base class virtual methods is a simpler way to implement class handlers than registering class handlers in a static constructor. Within the override, you can raise events, initiate class-specific logic to change element properties on instances, mark the event as handled, or perform other event handling logic.
|
||||
|
||||
Unlike static class event handlers, the WPF event system only invokes override class event handlers for the most derived class in a class hierarchy. The most derived class in a class hierarchy, can then use the [base](/dotnet/csharp/language-reference/keywords/base) keyword to call the base implementation of the virtual method. In most cases, you should call the base implementation, regardless of whether you mark an event as handled. You should only omit calling the base implementation if your class has a requirement to replace the base implementation logic, if any. Whether you call the base implementation before or after your overriding code depends on the nature of your implementation.
|
||||
|
||||
In the preceding code sample, the base class `OnKeyDown` virtual method is overridden in both the `ComponentWrapper` and `ComponentWrapperBase` classes. Since the WPF event system only invokes the `ComponentWrapper.OnKeyDown` override class event handler, that handler uses `base.OnKeyDown(e)` to call the `ComponentWrapperBase.OnKeyDown` override class event handler, which in turn uses `base.OnKeyDown(e)` to call the `StackPanel.OnKeyDown` virtual method. The order of events in the preceding code sample is:
|
||||
|
||||
1. The instance handler attached to `componentWrapper` is triggered by the `PreviewKeyDown` routed event.
|
||||
1. The static class handler attached to `componentWrapper` is triggered by the `KeyDown` routed event.
|
||||
1. The static class handler attached to `componentWrapperBase` is triggered by the `KeyDown` routed event.
|
||||
1. The override class handler attached to `componentWrapper` is triggered by the `KeyDown` routed event.
|
||||
1. The override class handler attached to `componentWrapperBase` is triggered by the `KeyDown` routed event.
|
||||
1. The `KeyDown` routed event is marked as handled.
|
||||
1. The instance handler attached to `componentWrapper` is triggered by the `KeyDown` routed event. The handler was registered with the `handledEventsToo` parameter set to `true`.
|
||||
|
||||
## Input event suppression in composite controls
|
||||
|
||||
Some composite controls suppress [input events](/dotnet/desktop/wpf/advanced/input-overview) at the component-level in order to replace them with a customized high-level event that carries more information or implies a more specific behavior. A composite control is by definition composed of multiple practical controls or control base classes. A classic example is the <xref:System.Windows.Controls.Button> control, which transforms various mouse events into a <xref:System.Windows.Controls.Primitives.ButtonBase.Click> routed event. The `Button` base class is <xref:System.Windows.Controls.Primitives.ButtonBase>, which indirectly derives from <xref:System.Windows.UIElement>. Much of the event infrastructure needed for control input processing is available at the `UIElement` level. `UIElement` exposes several <xref:System.Windows.Input.Mouse> events such as <xref:System.Windows.UIElement.MouseLeftButtonDown> and <xref:System.Windows.UIElement.MouseRightButtonDown>. `UIElement` also implements the empty virtual methods <xref:System.Windows.UIElement.OnMouseLeftButtonDown%2A> and <xref:System.Windows.UIElement.OnMouseRightButtonDown%2A> as preregistered class handlers. `ButtonBase` overrides these class handlers, and within the override handler sets the <xref:System.Windows.RoutedEventArgs.Handled%2A> property to `true` and raises a `Click` event. The end result for most listeners is that the `MouseLeftButtonDown` and `MouseRightButtonDown` events are hidden, and the high-level `Click` event is visible.
|
||||
|
||||
### Working around input event suppression
|
||||
|
||||
Sometimes event suppression within individual controls can interfere with the event handling logic in your application. For example, if your application used XAML attribute syntax to attach a handler for the <xref:System.Windows.UIElement.MouseLeftButtonDown> event on the XAML root element, that handler won't be invoked because the <xref:System.Windows.Controls.Button> control marks the `MouseLeftButtonDown` event as handled. If you want elements toward the root of your application to be invoked for a handled routed event, you can either:
|
||||
|
||||
- Attach handlers by calling the <xref:System.Windows.UIElement.AddHandler(System.Windows.RoutedEvent,System.Delegate,System.Boolean)?displayProperty=nameWithType> method with the `handledEventsToo` parameter set to `true`. This approach requires attaching the event handler in code-behind, after obtaining an object reference for the element that it will attach to.
|
||||
|
||||
- If the event marked as handled is a bubbling input event, attach handlers for the paired preview event, if available. For example, if a control suppresses the `MouseLeftButtonDown` event, you can attach a handler for the <xref:System.Windows.UIElement.PreviewMouseLeftButtonDown> event instead. This approach only works for preview and bubbling input event pairs, which share event data. Be careful not to mark the `PreviewMouseLeftButtonDown` as handled since that would completely suppress the <xref:System.Windows.Controls.Primitives.ButtonBase.Click> event.
|
||||
|
||||
For an example of how to work around input event suppression, see [Working around event suppression by controls](preview-events.md#working-around-event-suppression-by-controls).
|
||||
|
||||
## See also
|
||||
|
||||
- <xref:System.Windows.EventManager>
|
||||
- [Preview events](preview-events.md)
|
||||
- [Create a custom routed event](how-to-create-a-custom-routed-event.md)
|
||||
- [Routed events overview](/dotnet/desktop/wpf/advanced/routed-events-overview?view=netframeworkdesktop-4.8&preserve-view=true)
|
||||
@@ -32,9 +32,9 @@ For [input events](/dotnet/desktop/wpf/advanced/input-overview), event data is s
|
||||
> [!NOTE]
|
||||
> Not all preview events are [tunneling](<xref:System.Windows.RoutingStrategy.Tunnel>) events. For example, the <xref:System.Windows.UIElement.PreviewMouseLeftButtonDown> input event follows a downward route through the element tree, but is a [direct](<xref:System.Windows.RoutingStrategy.Direct>) routed event that's raised and reraised by each <xref:System.Windows.UIElement> in the route.
|
||||
|
||||
## Preview events in composite controls
|
||||
## Working around event suppression by 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.
|
||||
Some composite controls suppress input events at the component-level in order to replace them with a customized high-level event. For example, the WPF <xref:System.Windows.Controls.Primitives.ButtonBase> marks the <xref:System.Windows.UIElement.MouseLeftButtonDown> bubbling 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:
|
||||
|
||||
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
<Application x:Class="CodeSampleCsharp.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:CodeSampleCsharp"
|
||||
StartupUri="MainWindow.xaml">
|
||||
<Application.Resources>
|
||||
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace CodeSampleCsharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for App.xaml
|
||||
/// </summary>
|
||||
public partial class App : Application
|
||||
{
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
using System.Windows;
|
||||
|
||||
[assembly: ThemeInfo(
|
||||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||
//(used if a resource is not found in the page,
|
||||
// or application resource dictionaries)
|
||||
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||
//(used if a resource is not found in the page,
|
||||
// app, or any theme specific resource dictionaries)
|
||||
)]
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<UseWPF>true</UseWPF>
|
||||
<NeutralLanguage>en-us</NeutralLanguage>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Properties\Resources.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
|
||||
namespace CodeSampleCsharp
|
||||
{
|
||||
internal static class Handler
|
||||
{
|
||||
public static void InstanceEventInfo(object sender, RoutedEventArgs e)
|
||||
{
|
||||
string senderName = ((FrameworkElement)sender).Name;
|
||||
string sourceName = ((FrameworkElement)e.Source).Name;
|
||||
string eventName = e.RoutedEvent.Name;
|
||||
string handledEventsToo = e.Handled ? " Parameter handledEventsToo set to true." : "";
|
||||
|
||||
Debug.WriteLine($"The instance handler attached to {senderName} " +
|
||||
$"was triggered by the {eventName} routed event raised on {sourceName}.{handledEventsToo}");
|
||||
}
|
||||
|
||||
public static void ClassEventInfo_Static(object sender, RoutedEventArgs e)
|
||||
{
|
||||
string senderName = ((FrameworkElement)sender).Name;
|
||||
string sourceName = ((FrameworkElement)e.Source).Name;
|
||||
string eventName = e.RoutedEvent.Name;
|
||||
string handledEventsToo = e.Handled ? " Parameter handledEventsToo set to true." : "";
|
||||
|
||||
Debug.WriteLine($"The static class handler attached to {senderName} " +
|
||||
$"was triggered by the {eventName} routed event raised on {sourceName}.{handledEventsToo}");
|
||||
}
|
||||
|
||||
public static void ClassEventInfo_Override(object sender, RoutedEventArgs e)
|
||||
{
|
||||
string senderName = ((FrameworkElement)sender).Name;
|
||||
string sourceName = ((FrameworkElement)e.Source).Name;
|
||||
string eventName = e.RoutedEvent.Name;
|
||||
string handledEventsToo = e.Handled ? " Parameter handledEventsToo set to true." : "";
|
||||
|
||||
Debug.WriteLine($"The override class handler attached to {senderName} " +
|
||||
$"was triggered by the {eventName} routed event raised on {sourceName}.{handledEventsToo}");
|
||||
}
|
||||
|
||||
public static void ClassEventInfoBase_Static(object sender, RoutedEventArgs e)
|
||||
{
|
||||
string senderName = ((FrameworkElement)sender).Name + "Base";
|
||||
string sourceName = ((FrameworkElement)e.Source).Name;
|
||||
string eventName = e.RoutedEvent.Name;
|
||||
string handledEventsToo = e.Handled ? " Parameter handledEventsToo set to true." : "";
|
||||
|
||||
Debug.WriteLine($"The static class handler attached to {senderName} " +
|
||||
$"was triggered by the {eventName} routed event raised on {sourceName}.{handledEventsToo}");
|
||||
}
|
||||
|
||||
public static void ClassEventInfoBase_Override(object sender, RoutedEventArgs e)
|
||||
{
|
||||
string senderName = ((FrameworkElement)sender).Name + "Base";
|
||||
string sourceName = ((FrameworkElement)e.Source).Name;
|
||||
string eventName = e.RoutedEvent.Name;
|
||||
string handledEventsToo = e.Handled ? " Parameter handledEventsToo set to true." : "";
|
||||
|
||||
Debug.WriteLine($"The override class handler attached to {senderName} " +
|
||||
$"was triggered by the {eventName} routed event raised on {sourceName}.{handledEventsToo}");
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
<Window x:Class="CodeSampleCsharp.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:custom="clr-namespace:CodeSampleCsharp"
|
||||
Title="Preview events" Height="100" Width="300">
|
||||
|
||||
<!--<InstanceEventHandling>-->
|
||||
<StackPanel Name="outerStackPanel" VerticalAlignment="Center">
|
||||
<custom:ComponentWrapper
|
||||
x:Name="componentWrapper"
|
||||
TextBox.PreviewKeyDown="HandlerInstanceEventInfo"
|
||||
HorizontalAlignment="Center">
|
||||
<TextBox Name="componentTextBox" Width="200" />
|
||||
</custom:ComponentWrapper>
|
||||
</StackPanel>
|
||||
<!--</InstanceEventHandling>-->
|
||||
|
||||
</Window>
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace CodeSampleCsharp
|
||||
{
|
||||
//<InstanceEventHandling>
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
// Attach an instance handler on componentWrapper that will be invoked by handled KeyDown events.
|
||||
componentWrapper.AddHandler(KeyDownEvent, new RoutedEventHandler(Handler.InstanceEventInfo),
|
||||
handledEventsToo: true);
|
||||
}
|
||||
|
||||
// The handler attached to componentWrapper in XAML.
|
||||
public void HandlerInstanceEventInfo(object sender, KeyEventArgs e) =>
|
||||
Handler.InstanceEventInfo(sender, e);
|
||||
}
|
||||
//</InstanceEventHandling>
|
||||
|
||||
//<ClassEventHandling>
|
||||
public class ComponentWrapper : ComponentWrapperBase
|
||||
{
|
||||
static ComponentWrapper()
|
||||
{
|
||||
// Class event handler implemented in the static constructor.
|
||||
EventManager.RegisterClassHandler(typeof(ComponentWrapper), KeyDownEvent,
|
||||
new RoutedEventHandler(Handler.ClassEventInfo_Static));
|
||||
}
|
||||
|
||||
// Class event handler that overrides a base class virtual method.
|
||||
protected override void OnKeyDown(KeyEventArgs e)
|
||||
{
|
||||
Handler.ClassEventInfo_Override(this, e);
|
||||
|
||||
// Call the base OnKeyDown implementation on ComponentWrapperBase.
|
||||
base.OnKeyDown(e);
|
||||
}
|
||||
}
|
||||
|
||||
public class ComponentWrapperBase : StackPanel
|
||||
{
|
||||
// Class event handler implemented in the static constructor.
|
||||
static ComponentWrapperBase()
|
||||
{
|
||||
EventManager.RegisterClassHandler(typeof(ComponentWrapperBase), KeyDownEvent,
|
||||
new RoutedEventHandler(Handler.ClassEventInfoBase_Static));
|
||||
}
|
||||
|
||||
// Class event handler that overrides a base class virtual method.
|
||||
protected override void OnKeyDown(KeyEventArgs e)
|
||||
{
|
||||
Handler.ClassEventInfoBase_Override(this, e);
|
||||
|
||||
e.Handled = true;
|
||||
Debug.WriteLine("The KeyDown routed event is marked as handled.");
|
||||
|
||||
// Call the base OnKeyDown implementation on StackPanel.
|
||||
base.OnKeyDown(e);
|
||||
}
|
||||
}
|
||||
//</ClassEventHandling>
|
||||
|
||||
/* Debug output:
|
||||
The instance handler attached to componentWrapper was triggered by the PreviewKeyDown routed event raised on componentTextBox.
|
||||
The static class handler attached to componentWrapper was triggered by the KeyDown routed event raised on componentTextBox.
|
||||
The static class handler attached to componentWrapperBase was triggered by the KeyDown routed event raised on componentTextBox.
|
||||
The override class handler attached to componentWrapper was triggered by the KeyDown routed event raised on componentTextBox.
|
||||
The override class handler attached to componentWrapperBase was triggered by the KeyDown routed event raised on componentTextBox.
|
||||
The KeyDown routed event is marked as handled.
|
||||
The instance handler attached to componentWrapper was triggered by the KeyDown routed event raised on componentTextBox. Parameter handledEventsToo set to true.
|
||||
*/
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace CodeSampleCsharp.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CodeSampleCsharp.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
<Application x:Class="Application"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:CodeSampleVb"
|
||||
StartupUri="MainWindow.xaml">
|
||||
<Application.Resources>
|
||||
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
Class Application
|
||||
|
||||
' Application-level events, such as Startup, Exit, and DispatcherUnhandledException
|
||||
' can be handled in this file.
|
||||
|
||||
End Class
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
'The ThemeInfo attribute describes where any theme specific and generic resource dictionaries can be found.
|
||||
'1st parameter: where theme specific resource dictionaries are located
|
||||
'(used if a resource is not found in the page,
|
||||
' or application resource dictionaries)
|
||||
|
||||
'2nd parameter: where the generic resource dictionary is located
|
||||
'(used if a resource is not found in the page,
|
||||
'app, and any theme specific resource dictionaries)
|
||||
<Assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)>
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<RootNamespace>CodeSampleVb</RootNamespace>
|
||||
<NeutralLanguage>en-us</NeutralLanguage>
|
||||
<UseWPF>true</UseWPF>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Import Include="System.Windows" />
|
||||
<Import Include="System.Windows.Controls" />
|
||||
<Import Include="System.Windows.Data" />
|
||||
<Import Include="System.Windows.Documents" />
|
||||
<Import Include="System.Windows.Input" />
|
||||
<Import Include="System.Windows.Media" />
|
||||
<Import Include="System.Windows.Media.Imaging" />
|
||||
<Import Include="System.Windows.Navigation" />
|
||||
<Import Include="System.Windows.Shapes" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
Friend Module Handler
|
||||
Sub InstanceEventInfo(sender As Object, e As RoutedEventArgs)
|
||||
Dim senderName As String = (CType(sender, FrameworkElement)).Name
|
||||
Dim sourceName As String = (CType(e.Source, FrameworkElement)).Name
|
||||
Dim eventName As String = e.RoutedEvent.Name
|
||||
Dim handledEventsToo As String = If(e.Handled, " Parameter handledEventsToo set to true.", "")
|
||||
Debug.WriteLine($"The instance handler attached to {senderName} " & $"was triggered by the {eventName} routed event raised on {sourceName}.{handledEventsToo}")
|
||||
End Sub
|
||||
|
||||
Sub ClassEventInfo_Static(sender As Object, e As RoutedEventArgs)
|
||||
Dim senderName As String = (CType(sender, FrameworkElement)).Name
|
||||
Dim sourceName As String = (CType(e.Source, FrameworkElement)).Name
|
||||
Dim eventName As String = e.RoutedEvent.Name
|
||||
Dim handledEventsToo As String = If(e.Handled, " Parameter handledEventsToo set to true.", "")
|
||||
Debug.WriteLine($"The static class handler attached to {senderName} " & $"was triggered by the {eventName} routed event raised on {sourceName}.{handledEventsToo}")
|
||||
End Sub
|
||||
|
||||
Sub ClassEventInfo_Override(sender As Object, e As RoutedEventArgs)
|
||||
Dim senderName As String = (CType(sender, FrameworkElement)).Name
|
||||
Dim sourceName As String = (CType(e.Source, FrameworkElement)).Name
|
||||
Dim eventName As String = e.RoutedEvent.Name
|
||||
Dim handledEventsToo As String = If(e.Handled, " Parameter handledEventsToo set to true.", "")
|
||||
Debug.WriteLine($"The override class handler attached to {senderName} " & $"was triggered by the {eventName} routed event raised on {sourceName}.{handledEventsToo}")
|
||||
End Sub
|
||||
|
||||
Sub ClassEventInfoBase_Static(sender As Object, e As RoutedEventArgs)
|
||||
Dim senderName As String = (CType(sender, FrameworkElement)).Name & "Base"
|
||||
Dim sourceName As String = (CType(e.Source, FrameworkElement)).Name
|
||||
Dim eventName As String = e.RoutedEvent.Name
|
||||
Dim handledEventsToo As String = If(e.Handled, " Parameter handledEventsToo set to true.", "")
|
||||
Debug.WriteLine($"The static class handler attached to {senderName} " & $"was triggered by the {eventName} routed event raised on {sourceName}.{handledEventsToo}")
|
||||
End Sub
|
||||
|
||||
Sub ClassEventInfoBase_Override(sender As Object, e As RoutedEventArgs)
|
||||
Dim senderName As String = (CType(sender, FrameworkElement)).Name & "Base"
|
||||
Dim sourceName As String = (CType(e.Source, FrameworkElement)).Name
|
||||
Dim eventName As String = e.RoutedEvent.Name
|
||||
Dim handledEventsToo As String = If(e.Handled, " Parameter handledEventsToo set to true.", "")
|
||||
Debug.WriteLine($"The override class handler attached to {senderName} " & $"was triggered by the {eventName} routed event raised on {sourceName}.{handledEventsToo}")
|
||||
End Sub
|
||||
End Module
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
<Window x:Class="MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:custom="clr-namespace:CodeSampleVb"
|
||||
Title="Preview events" Height="100" Width="300">
|
||||
|
||||
<!--<InstanceEventHandling>-->
|
||||
<StackPanel Name="outerStackPanel" VerticalAlignment="Center">
|
||||
<custom:ComponentWrapper
|
||||
x:Name="componentWrapper"
|
||||
TextBox.PreviewKeyDown="HandlerInstanceEventInfo"
|
||||
HorizontalAlignment="Center">
|
||||
<TextBox Name="componentTextBox" Width="200" />
|
||||
</custom:ComponentWrapper>
|
||||
</StackPanel>
|
||||
<!--</InstanceEventHandling>-->
|
||||
|
||||
</Window>
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
'<InstanceEventHandling>
|
||||
Partial Public Class MainWindow
|
||||
Inherits Window
|
||||
|
||||
Public Sub New()
|
||||
InitializeComponent()
|
||||
|
||||
' Attach an instance handler on componentWrapper that will be invoked by handled KeyDown events.
|
||||
componentWrapper.[AddHandler](KeyDownEvent, New RoutedEventHandler(AddressOf InstanceEventInfo),
|
||||
handledEventsToo:=True)
|
||||
End Sub
|
||||
|
||||
' The handler attached to componentWrapper in XAML.
|
||||
Public Sub HandlerInstanceEventInfo(sender As Object, e As KeyEventArgs)
|
||||
InstanceEventInfo(sender, e)
|
||||
End Sub
|
||||
|
||||
End Class
|
||||
'</InstanceEventHandling>
|
||||
|
||||
'<ClassEventHandling>
|
||||
Public Class ComponentWrapper
|
||||
Inherits ComponentWrapperBase
|
||||
|
||||
Shared Sub New()
|
||||
' Class event handler implemented in the static constructor.
|
||||
EventManager.RegisterClassHandler(GetType(ComponentWrapper), KeyDownEvent,
|
||||
New RoutedEventHandler(AddressOf ClassEventInfo_Static))
|
||||
End Sub
|
||||
|
||||
' Class event handler that overrides a base class virtual method.
|
||||
Protected Overrides Sub OnKeyDown(e As KeyEventArgs)
|
||||
ClassEventInfo_Override(Me, e)
|
||||
|
||||
' Call the base OnKeyDown implementation on ComponentWrapperBase.
|
||||
MyBase.OnKeyDown(e)
|
||||
End Sub
|
||||
|
||||
End Class
|
||||
|
||||
Public Class ComponentWrapperBase
|
||||
Inherits StackPanel
|
||||
|
||||
Shared Sub New()
|
||||
' Class event handler implemented in the static constructor.
|
||||
EventManager.RegisterClassHandler(GetType(ComponentWrapperBase), KeyDownEvent,
|
||||
New RoutedEventHandler(AddressOf ClassEventInfoBase_Static))
|
||||
End Sub
|
||||
|
||||
' Class event handler that overrides a base class virtual method.
|
||||
Protected Overrides Sub OnKeyDown(e As KeyEventArgs)
|
||||
ClassEventInfoBase_Override(Me, e)
|
||||
|
||||
e.Handled = True
|
||||
Debug.WriteLine("The KeyDown event is marked as handled.")
|
||||
|
||||
' Call the base OnKeyDown implementation on StackPanel.
|
||||
MyBase.OnKeyDown(e)
|
||||
End Sub
|
||||
|
||||
End Class
|
||||
'</ClassEventHandling>
|
||||
|
||||
' Debug output:
|
||||
'
|
||||
' The instance handler attached to componentWrapper was triggered by the PreviewKeyDown routed event raised on componentTextBox.
|
||||
' The static class handler attached to componentWrapper was triggered by the KeyDown routed event raised on componentTextBox.
|
||||
' The static class handler attached to componentWrapperBase was triggered by the KeyDown routed event raised on componentTextBox.
|
||||
' The override class handler attached to componentWrapper was triggered by the KeyDown routed event raised on componentTextBox.
|
||||
' The override class handler attached to componentWrapperBase was triggered by the KeyDown routed event raised on componentTextBox.
|
||||
' The KeyDown event is marked as handled.
|
||||
' The instance handler attached to componentWrapper was triggered by the KeyDown routed event raised on componentTextBox. Parameter handledEventsToo set to true.
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
<Window x:Class="CodeSampleVb.MainWindow"
|
||||
xmlns:local="clr-namespace:CodeSampleVb.CodeSampleVb"
|
||||
<Window x:Class="MainWindow"
|
||||
xmlns:local="clr-namespace:CodeSampleVb"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="Property value inheritance" Height="200" Width="400" Background="Yellow">
|
||||
@@ -18,7 +18,7 @@
|
||||
</Canvas>
|
||||
<!--</XamlElementTree>-->
|
||||
|
||||
<local:Canvas_AllowDropInheritDisabled Grid.Column="1" Margin="20" Background="Orange" AllowDrop="True">
|
||||
<local:Canvas_AllowDropInheritDisabled x:Name="canvas11" Grid.Column="1" Margin="20" Background="Orange" AllowDrop="True">
|
||||
<StackPanel Name="stackPanel11" Margin="20" Background="Green">
|
||||
<Label Name="label11" Margin="20" Height="40" Width="40" Background="Blue"/>
|
||||
</StackPanel>
|
||||
|
||||
+134
-136
@@ -1,157 +1,156 @@
|
||||
Namespace CodeSampleVb
|
||||
Partial Public Class MainWindow
|
||||
Inherits Window
|
||||
Partial Public Class MainWindow
|
||||
Inherits Window
|
||||
|
||||
Public Sub New()
|
||||
InitializeComponent()
|
||||
Public Sub New()
|
||||
InitializeComponent()
|
||||
|
||||
' Code tests.
|
||||
TestAllowDropInheritanceInXaml()
|
||||
TestAllowDropInheritanceInCode()
|
||||
TestIsTransparentInheritanceInCode()
|
||||
TestDependencyPropertyWrapper()
|
||||
End Sub
|
||||
' Code tests.
|
||||
TestAllowDropInheritanceInXaml()
|
||||
TestAllowDropInheritanceInCode()
|
||||
TestIsTransparentInheritanceInCode()
|
||||
TestDependencyPropertyWrapper()
|
||||
End Sub
|
||||
|
||||
Private Sub TestAllowDropInheritanceInXaml()
|
||||
Private Sub TestAllowDropInheritanceInXaml()
|
||||
|
||||
' Test enabled property value inheritance.
|
||||
Dim fpm1 As FrameworkPropertyMetadata =
|
||||
CType(AllowDropProperty.
|
||||
GetMetadata(GetType(Canvas)), FrameworkPropertyMetadata)
|
||||
Debug.Assert(fpm1.[Inherits] = True)
|
||||
Debug.Assert(canvas1.AllowDrop = True)
|
||||
Debug.Assert(stackPanel1.AllowDrop = True)
|
||||
Debug.Assert(label1.AllowDrop = True)
|
||||
' Test enabled property value inheritance.
|
||||
Dim fpm1 As FrameworkPropertyMetadata =
|
||||
CType(AllowDropProperty.
|
||||
GetMetadata(GetType(Canvas)), FrameworkPropertyMetadata)
|
||||
Debug.Assert(fpm1.[Inherits] = True)
|
||||
Debug.Assert(canvas1.AllowDrop = True)
|
||||
Debug.Assert(stackPanel1.AllowDrop = True)
|
||||
Debug.Assert(label1.AllowDrop = True)
|
||||
|
||||
' Test disabled property value inheritance.
|
||||
Dim fpm11 As FrameworkPropertyMetadata =
|
||||
CType(AllowDropProperty.
|
||||
GetMetadata(GetType(Canvas_AllowDropInheritDisabled)), FrameworkPropertyMetadata)
|
||||
Debug.Assert(fpm11.[Inherits] = False)
|
||||
' Debug.Assert(canvas11.AllowDrop = True)
|
||||
Debug.Assert(stackPanel11.AllowDrop = False)
|
||||
Debug.Assert(label11.AllowDrop = False)
|
||||
End Sub
|
||||
' Test disabled property value inheritance.
|
||||
Dim fpm11 As FrameworkPropertyMetadata =
|
||||
CType(AllowDropProperty.
|
||||
GetMetadata(GetType(Canvas_AllowDropInheritDisabled)), FrameworkPropertyMetadata)
|
||||
Debug.Assert(fpm11.[Inherits] = False)
|
||||
Debug.Assert(canvas11.AllowDrop = True)
|
||||
Debug.Assert(stackPanel11.AllowDrop = False)
|
||||
Debug.Assert(label11.AllowDrop = False)
|
||||
End Sub
|
||||
|
||||
Private Shared Sub TestAllowDropInheritanceInCode()
|
||||
Private Shared Sub TestAllowDropInheritanceInCode()
|
||||
|
||||
'<CodeElementTree>
|
||||
Dim canvas2 As New Canvas With {
|
||||
.AllowDrop = True
|
||||
}
|
||||
Dim stackPanel2 As New StackPanel()
|
||||
Dim label2 As New Label()
|
||||
canvas2.Children.Add(stackPanel2)
|
||||
stackPanel2.Children.Add(label2)
|
||||
'</CodeElementTree>
|
||||
'<CodeElementTree>
|
||||
Dim canvas2 As New Canvas With {
|
||||
.AllowDrop = True
|
||||
}
|
||||
Dim stackPanel2 As New StackPanel()
|
||||
Dim label2 As New Label()
|
||||
canvas2.Children.Add(stackPanel2)
|
||||
stackPanel2.Children.Add(label2)
|
||||
'</CodeElementTree>
|
||||
|
||||
' Test enabled property value inheritance.
|
||||
Dim fpm2 As FrameworkPropertyMetadata =
|
||||
CType(AllowDropProperty.
|
||||
GetMetadata(GetType(Canvas)), FrameworkPropertyMetadata)
|
||||
Debug.Assert(fpm2.[Inherits] = True)
|
||||
Debug.Assert(canvas2.AllowDrop = True)
|
||||
Debug.Assert(stackPanel2.AllowDrop = True)
|
||||
Debug.Assert(label2.AllowDrop = True)
|
||||
' Test enabled property value inheritance.
|
||||
Dim fpm2 As FrameworkPropertyMetadata =
|
||||
CType(AllowDropProperty.
|
||||
GetMetadata(GetType(Canvas)), FrameworkPropertyMetadata)
|
||||
Debug.Assert(fpm2.[Inherits] = True)
|
||||
Debug.Assert(canvas2.AllowDrop = True)
|
||||
Debug.Assert(stackPanel2.AllowDrop = True)
|
||||
Debug.Assert(label2.AllowDrop = True)
|
||||
|
||||
' Test disabled property value inheritance.
|
||||
Dim canvas3 As New Canvas_AllowDropInheritDisabled With {
|
||||
.AllowDrop = True
|
||||
}
|
||||
Dim stackPanel3 As New StackPanel()
|
||||
Dim label3 As New Label()
|
||||
canvas3.Children.Add(stackPanel3)
|
||||
stackPanel3.Children.Add(label3)
|
||||
Dim fpm3 As FrameworkPropertyMetadata =
|
||||
CType(AllowDropProperty.
|
||||
GetMetadata(GetType(Canvas_AllowDropInheritDisabled)), FrameworkPropertyMetadata)
|
||||
Debug.Assert(fpm3.[Inherits] = False)
|
||||
Debug.Assert(canvas3.AllowDrop = True)
|
||||
Debug.Assert(stackPanel3.AllowDrop = False)
|
||||
Debug.Assert(label3.AllowDrop = False)
|
||||
' Test disabled property value inheritance.
|
||||
Dim canvas3 As New Canvas_AllowDropInheritDisabled With {
|
||||
.AllowDrop = True
|
||||
}
|
||||
Dim stackPanel3 As New StackPanel()
|
||||
Dim label3 As New Label()
|
||||
canvas3.Children.Add(stackPanel3)
|
||||
stackPanel3.Children.Add(label3)
|
||||
Dim fpm3 As FrameworkPropertyMetadata =
|
||||
CType(AllowDropProperty.
|
||||
GetMetadata(GetType(Canvas_AllowDropInheritDisabled)), FrameworkPropertyMetadata)
|
||||
Debug.Assert(fpm3.[Inherits] = False)
|
||||
Debug.Assert(canvas3.AllowDrop = True)
|
||||
Debug.Assert(stackPanel3.AllowDrop = False)
|
||||
Debug.Assert(label3.AllowDrop = False)
|
||||
|
||||
End Sub
|
||||
End Sub
|
||||
|
||||
Private Shared Sub TestIsTransparentInheritanceInCode()
|
||||
Private Shared Sub TestIsTransparentInheritanceInCode()
|
||||
|
||||
' Test enabled property value inheritance.
|
||||
Dim myCanvas1 As New Canvas_IsTransparentInheritEnabled With {
|
||||
.IsTransparent = True
|
||||
}
|
||||
Dim myCanvas2 As New Canvas_IsTransparentInheritEnabled2()
|
||||
Dim myCanvas3 As New Canvas_IsTransparentInheritEnabled3()
|
||||
myCanvas1.Children.Add(myCanvas2)
|
||||
myCanvas2.Children.Add(myCanvas3)
|
||||
Dim fpm1 As FrameworkPropertyMetadata =
|
||||
CType(Canvas_IsTransparentInheritEnabled.IsTransparentProperty.
|
||||
GetMetadata(GetType(Canvas_IsTransparentInheritEnabled)), FrameworkPropertyMetadata)
|
||||
Debug.Assert(fpm1.[Inherits] = True)
|
||||
Debug.Assert(myCanvas1.IsTransparent = True)
|
||||
Debug.Assert(myCanvas2.IsTransparent = True)
|
||||
Debug.Assert(myCanvas3.IsTransparent = True)
|
||||
' Test enabled property value inheritance.
|
||||
Dim myCanvas1 As New Canvas_IsTransparentInheritEnabled With {
|
||||
.IsTransparent = True
|
||||
}
|
||||
Dim myCanvas2 As New Canvas_IsTransparentInheritEnabled2()
|
||||
Dim myCanvas3 As New Canvas_IsTransparentInheritEnabled3()
|
||||
myCanvas1.Children.Add(myCanvas2)
|
||||
myCanvas2.Children.Add(myCanvas3)
|
||||
Dim fpm1 As FrameworkPropertyMetadata =
|
||||
CType(Canvas_IsTransparentInheritEnabled.IsTransparentProperty.
|
||||
GetMetadata(GetType(Canvas_IsTransparentInheritEnabled)), FrameworkPropertyMetadata)
|
||||
Debug.Assert(fpm1.[Inherits] = True)
|
||||
Debug.Assert(myCanvas1.IsTransparent = True)
|
||||
Debug.Assert(myCanvas2.IsTransparent = True)
|
||||
Debug.Assert(myCanvas3.IsTransparent = True)
|
||||
|
||||
' Test disabled property value inheritance.
|
||||
Dim myCanvas4 As New Canvas_IsTransparentInheritDisabled With {
|
||||
.IsTransparent = True
|
||||
}
|
||||
Dim myCanvas5 As New Canvas_IsTransparentInheritDisabled2()
|
||||
Dim myCanvas6 As New Canvas_IsTransparentInheritDisabled3()
|
||||
myCanvas4.Children.Add(myCanvas5)
|
||||
myCanvas5.Children.Add(myCanvas6)
|
||||
Dim fpm2 As FrameworkPropertyMetadata =
|
||||
CType(Canvas_IsTransparentInheritDisabled.IsTransparentProperty.
|
||||
GetMetadata(GetType(Canvas_IsTransparentInheritDisabled)), FrameworkPropertyMetadata)
|
||||
Debug.Assert(fpm2.[Inherits] = False)
|
||||
Debug.Assert(myCanvas4.IsTransparent = True)
|
||||
Debug.Assert(myCanvas5.IsTransparent = False)
|
||||
Debug.Assert(myCanvas6.IsTransparent = False)
|
||||
' Test disabled property value inheritance.
|
||||
Dim myCanvas4 As New Canvas_IsTransparentInheritDisabled With {
|
||||
.IsTransparent = True
|
||||
}
|
||||
Dim myCanvas5 As New Canvas_IsTransparentInheritDisabled2()
|
||||
Dim myCanvas6 As New Canvas_IsTransparentInheritDisabled3()
|
||||
myCanvas4.Children.Add(myCanvas5)
|
||||
myCanvas5.Children.Add(myCanvas6)
|
||||
Dim fpm2 As FrameworkPropertyMetadata =
|
||||
CType(Canvas_IsTransparentInheritDisabled.IsTransparentProperty.
|
||||
GetMetadata(GetType(Canvas_IsTransparentInheritDisabled)), FrameworkPropertyMetadata)
|
||||
Debug.Assert(fpm2.[Inherits] = False)
|
||||
Debug.Assert(myCanvas4.IsTransparent = True)
|
||||
Debug.Assert(myCanvas5.IsTransparent = False)
|
||||
Debug.Assert(myCanvas6.IsTransparent = False)
|
||||
|
||||
End Sub
|
||||
End Sub
|
||||
|
||||
Private Shared Sub TestDependencyPropertyWrapper()
|
||||
Private Shared Sub TestDependencyPropertyWrapper()
|
||||
|
||||
' Test Canvas_IsTransparentInheritEnabled.
|
||||
Dim myCanvas1 As New Canvas_IsTransparentInheritEnabled()
|
||||
Dim myCanvas2 As New Canvas_IsTransparentInheritEnabled2()
|
||||
Dim myCanvas3 As New Canvas_IsTransparentInheritEnabled3()
|
||||
' Test property wrapper.
|
||||
myCanvas1.IsTransparent = True
|
||||
myCanvas2.IsTransparent = False
|
||||
myCanvas3.IsTransparent = True
|
||||
Debug.Assert(myCanvas1.IsTransparent = True)
|
||||
Debug.Assert(myCanvas2.IsTransparent = False)
|
||||
Debug.Assert(myCanvas3.IsTransparent = True)
|
||||
' Test individual get/set accessors.
|
||||
Canvas_IsTransparentInheritEnabled.SetIsTransparent(myCanvas1, False)
|
||||
Canvas_IsTransparentInheritEnabled.SetIsTransparent(myCanvas2, True)
|
||||
Canvas_IsTransparentInheritEnabled.SetIsTransparent(myCanvas3, False)
|
||||
Debug.Assert(Canvas_IsTransparentInheritEnabled.GetIsTransparent(myCanvas1) = False)
|
||||
Debug.Assert(Canvas_IsTransparentInheritEnabled.GetIsTransparent(myCanvas2) = True)
|
||||
Debug.Assert(Canvas_IsTransparentInheritEnabled.GetIsTransparent(myCanvas3) = False)
|
||||
' Test Canvas_IsTransparentInheritEnabled.
|
||||
Dim myCanvas1 As New Canvas_IsTransparentInheritEnabled()
|
||||
Dim myCanvas2 As New Canvas_IsTransparentInheritEnabled2()
|
||||
Dim myCanvas3 As New Canvas_IsTransparentInheritEnabled3()
|
||||
' Test property wrapper.
|
||||
myCanvas1.IsTransparent = True
|
||||
myCanvas2.IsTransparent = False
|
||||
myCanvas3.IsTransparent = True
|
||||
Debug.Assert(myCanvas1.IsTransparent = True)
|
||||
Debug.Assert(myCanvas2.IsTransparent = False)
|
||||
Debug.Assert(myCanvas3.IsTransparent = True)
|
||||
' Test individual get/set accessors.
|
||||
Canvas_IsTransparentInheritEnabled.SetIsTransparent(myCanvas1, False)
|
||||
Canvas_IsTransparentInheritEnabled.SetIsTransparent(myCanvas2, True)
|
||||
Canvas_IsTransparentInheritEnabled.SetIsTransparent(myCanvas3, False)
|
||||
Debug.Assert(Canvas_IsTransparentInheritEnabled.GetIsTransparent(myCanvas1) = False)
|
||||
Debug.Assert(Canvas_IsTransparentInheritEnabled.GetIsTransparent(myCanvas2) = True)
|
||||
Debug.Assert(Canvas_IsTransparentInheritEnabled.GetIsTransparent(myCanvas3) = False)
|
||||
|
||||
' Test Canvas_IsTransparentInheritDisabled.
|
||||
Dim myCanvas4 As New Canvas_IsTransparentInheritDisabled()
|
||||
Dim myCanvas5 As New Canvas_IsTransparentInheritDisabled2()
|
||||
Dim myCanvas6 As New Canvas_IsTransparentInheritDisabled3()
|
||||
' Test property wrapper.
|
||||
myCanvas4.IsTransparent = True
|
||||
myCanvas5.IsTransparent = False
|
||||
myCanvas6.IsTransparent = True
|
||||
Debug.Assert(myCanvas4.IsTransparent = True)
|
||||
Debug.Assert(myCanvas5.IsTransparent = False)
|
||||
Debug.Assert(myCanvas6.IsTransparent = True)
|
||||
' Test individual get/set accessors.
|
||||
Canvas_IsTransparentInheritDisabled.SetIsTransparent(myCanvas4, False)
|
||||
Canvas_IsTransparentInheritDisabled.SetIsTransparent(myCanvas5, True)
|
||||
Canvas_IsTransparentInheritDisabled.SetIsTransparent(myCanvas6, False)
|
||||
Debug.Assert(Canvas_IsTransparentInheritDisabled.GetIsTransparent(myCanvas4) = False)
|
||||
Debug.Assert(Canvas_IsTransparentInheritDisabled.GetIsTransparent(myCanvas5) = True)
|
||||
Debug.Assert(Canvas_IsTransparentInheritDisabled.GetIsTransparent(myCanvas6) = False)
|
||||
' Test Canvas_IsTransparentInheritDisabled.
|
||||
Dim myCanvas4 As New Canvas_IsTransparentInheritDisabled()
|
||||
Dim myCanvas5 As New Canvas_IsTransparentInheritDisabled2()
|
||||
Dim myCanvas6 As New Canvas_IsTransparentInheritDisabled3()
|
||||
' Test property wrapper.
|
||||
myCanvas4.IsTransparent = True
|
||||
myCanvas5.IsTransparent = False
|
||||
myCanvas6.IsTransparent = True
|
||||
Debug.Assert(myCanvas4.IsTransparent = True)
|
||||
Debug.Assert(myCanvas5.IsTransparent = False)
|
||||
Debug.Assert(myCanvas6.IsTransparent = True)
|
||||
' Test individual get/set accessors.
|
||||
Canvas_IsTransparentInheritDisabled.SetIsTransparent(myCanvas4, False)
|
||||
Canvas_IsTransparentInheritDisabled.SetIsTransparent(myCanvas5, True)
|
||||
Canvas_IsTransparentInheritDisabled.SetIsTransparent(myCanvas6, False)
|
||||
Debug.Assert(Canvas_IsTransparentInheritDisabled.GetIsTransparent(myCanvas4) = False)
|
||||
Debug.Assert(Canvas_IsTransparentInheritDisabled.GetIsTransparent(myCanvas5) = True)
|
||||
Debug.Assert(Canvas_IsTransparentInheritDisabled.GetIsTransparent(myCanvas6) = False)
|
||||
|
||||
End Sub
|
||||
End Class
|
||||
End Sub
|
||||
End Class
|
||||
|
||||
Public Class Canvas_AllowDropInheritDisabled
|
||||
Public Class Canvas_AllowDropInheritDisabled
|
||||
Inherits Canvas
|
||||
Shared Sub New()
|
||||
' Disable property value inheritance in a new property metadata object.
|
||||
@@ -250,4 +249,3 @@
|
||||
Public Class Canvas_IsTransparentInheritDisabled3
|
||||
Inherits Canvas_IsTransparentInheritDisabled
|
||||
End Class
|
||||
End Namespace
|
||||
|
||||
@@ -80,6 +80,8 @@ items:
|
||||
items:
|
||||
- name: Events
|
||||
items:
|
||||
- name: Marking routed events as handled, and class handling
|
||||
href: events/marking-routed-events-as-handled-and-class-handling.md
|
||||
- name: Preview events
|
||||
href: events/preview-events.md
|
||||
- name: Visual Basic and WPF event handling
|
||||
|
||||
@@ -348,6 +348,11 @@
|
||||
"SourceUrl": "/dotnet/desktop/wpf/advanced/preview-events?view=netframeworkdesktop-4.8",
|
||||
"TargetUrl": "/dotnet/desktop/wpf/events/preview-events?view=netdesktop-6.0"
|
||||
},
|
||||
{
|
||||
"Redirect": "TwoWay",
|
||||
"SourceUrl": "/dotnet/desktop/wpf/advanced/marking-routed-events-as-handled-and-class-handling?view=netframeworkdesktop-4.8",
|
||||
"TargetUrl": "/dotnet/desktop/wpf/events/marking-routed-events-as-handled-and-class-handling?view=netdesktop-6.0"
|
||||
},
|
||||
|
||||
// Systems - Properties
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user