merge main branch

This commit is contained in:
CXWTool Service Account
2022-02-11 06:01:52 +00:00
24 changed files with 622 additions and 0 deletions
+8
View File
@@ -612,6 +612,14 @@
{
"source_path": "dotnet-desktop-guide/framework/wpf/events/how-to-add-an-event-handler-using-code.md",
"redirect_url": "/dotnet/desktop/wpf/advanced/how-to-add-an-event-handler-using-code?view=netframeworkdesktop-4.8"
},
{
"source_path": "dotnet-desktop-guide/net/wpf/advanced/how-to-create-a-custom-routed-event.md",
"redirect_url": "/dotnet/desktop/wpf/events/how-to-create-a-custom-routed-event?view=netdesktop-6.0"
},
{
"source_path": "dotnet-desktop-guide/framework/wpf/events/how-to-create-a-custom-routed-event.md",
"redirect_url": "/dotnet/desktop/wpf/advanced/how-to-create-a-custom-routed-event?view=netframeworkdesktop-4.8"
}
]
}
@@ -0,0 +1,82 @@
---
title: "How to create a custom routed event"
description: Learn how to implement a custom routed event for an element in Windows Presentation Foundation (WPF).
ms.date: "02/02/2022"
dev_langs:
- "csharp"
- "vb"
helpviewer_keywords:
- "routed events [WPF], creating"
- "events [WPF], routing"
---
<!-- The acrolinx score was 93 on 02/02/2021-->
# How to create a custom routed event (WPF .NET)
Windows Presentation Foundation (WPF) application developers and component authors can create custom routed events to extend the functionality of common language runtime (CLR) events. For information on routed event capabilities, see [Why use routed events](/dotnet/desktop/wpf/advanced/routed-events-overview?view=netframeworkdesktop-4.8&preserve-view=true#why-use-routed-events). This article covers the basics of creating a custom routed event.
[!INCLUDE [desktop guide under construction](../../includes/desktop-guide-preview-note.md)]
## Routed event steps
The basic steps to create a routed event are:
1. Register a <xref:System.Windows.RoutedEvent> using the <xref:System.Windows.EventManager.RegisterRoutedEvent%2A> method.
1. The registration call returns a `RoutedEvent` instance, known as a routed event identifier, which holds the registered event name, [routing strategy](/dotnet/desktop/wpf/advanced/routed-events-overview?view=netframeworkdesktop-4.8&preserve-view=true#routing-strategies), and other event details. Assign the identifier to a static readonly field. By convention:
- The identifier for a routed event with a [bubbling](<xref:System.Windows.RoutingStrategy.Bubble>) strategy is named `<event name>Event`. For example, if the event name is `Tap` then the identifier should be named `TapEvent`.
- The identifier for a routed event with a [tunneling](<xref:System.Windows.RoutingStrategy.Tunnel>) strategy is named `Preview<event name>Event`. For example, if the event name is `Tap` then the identifier should be named `PreviewTapEvent`.
1. Define CLR [add](<xref:System.Windows.UIElement.AddHandler%2A>) and [remove](<xref:System.Windows.UIElement.RemoveHandler%2A>) event accessors. Without CLR event accessors, you'll only be able to add or remove event handlers through direct calls to the <xref:System.Windows.UIElement.AddHandler%2A?displayProperty=nameWithType> and <xref:System.Windows.UIElement.RemoveHandler%2A?displayProperty=nameWithType> methods. With CLR event accessors, you gain these event handler assignment mechanisms:
- For Extensible Application Markup Language (XAML), you can use attribute syntax to add event handlers.
- For C#, you can use the `+=` and `-=` operators to add or remove event handlers.
- For VB, you can use the [AddHandler](/dotnet/visual-basic/language-reference/statements/addhandler-statement) and [RemoveHandler](/dotnet/visual-basic/language-reference/statements/removehandler-statement) statements to add or remove event handlers.
1. Add custom logic for triggering your routed event. For example, your logic might trigger the event based on user-input and application state.
## Example
The following example implements the `CustomButton` class in a custom control library. The `CustomButton` class, which derives from <xref:System.Windows.Controls.Button>:
1. Registers a <xref:System.Windows.RoutedEvent> named `ConditionalClick` using the <xref:System.Windows.EventManager.RegisterRoutedEvent%2A> method, and specifies the [bubbling](<xref:System.Windows.RoutingStrategy.Bubble>) strategy during registration.
1. Assigns the `RoutedEvent` instance returned from the registration call to a static readonly field named `ConditionalClickEvent`.
1. Defines CLR [add](<xref:System.Windows.UIElement.AddHandler%2A>) and [remove](<xref:System.Windows.UIElement.RemoveHandler%2A>) event accessors.
1. Adds custom logic to raise the custom routed event when the `CustomButton` is clicked and an external condition applies. Although the example code raises the `ConditionalClick` routed event from within the overridden `OnClick` virtual method, you can raise your event any way you choose.
:::code language="csharp" source="./snippets/how-to-create-a-custom-routed-event/WpfControlLibraryCsharp/CustomButton.cs" id="CustomButton":::
:::code language="vb" source="./snippets/how-to-create-a-custom-routed-event/WpfControlLibraryVb/CustomButton.vb" id="CustomButton":::
The example includes a separate WPF application that uses XAML markup to add an instance of the `CustomButton` to a <xref:System.Windows.Controls.StackPanel>, and to assign the `Handler_ConditionalClick` method as the `ConditionalClick` event handler for the `CustomButton` and `StackPanel1` elements.
:::code language="xaml" source="./snippets/how-to-create-a-custom-routed-event/csharp/MainWindow.xaml" id="MainWindowXaml":::
In code-behind, the WPF application defines the `Handler_ConditionalClick` event handler method. Event handler methods can only be implemented in code-behind.
:::code language="csharp" source="./snippets/how-to-create-a-custom-routed-event/csharp/MainWindow.xaml.cs" id="EventHandler":::
:::code language="vb" source="./snippets/how-to-create-a-custom-routed-event/vb/MainWindow.xaml.vb" id="EventHandler":::
When `CustomButton` is clicked:
1. The `ConditionalClick` routed event is raised on `CustomButton`.
1. The `Handler_ConditionalClick` event handler assigned to `CustomButton` is triggered.
1. The `ConditionalClick` routed event traverses up the element tree to `StackPanel1`.
1. The `Handler_ConditionalClick` event handler assigned to `StackPanel1` is triggered.
1. The `ConditionalClick` routed event continues up the element tree potentially triggering other `ConditionalClick` event handlers assigned to other traversed elements.
The `Handler_ConditionalClick` event handler obtains the following information about the event that triggered it:
- The [sender](xref:System.Windows.RoutedEventHandler) object, which is the element that the event handler is assigned to. The `sender` will be `CustomButton` the first time the handler runs, and `StackPanel1` the second time.
- The <xref:System.Windows.RoutedEventArgs.Source?displayProperty=nameWithType> object, which is the element that originally raised the event. In this example, the `Source` is always `CustomButton`.
> [!NOTE]
> A key difference between a routed event and a CLR event is that a routed event traverses the element tree, looking for handlers, whereas a CLR event is created by a source object and handled by an event subscriber. As a result, a routed event `sender` can be any traversed element in the element tree.
You can create a tunneling event the same way as a bubbling event, except you'll set the routing strategy in the event registration call to <xref:System.Windows.RoutingStrategy.Tunnel>. For more information on tunneling events, see [WPF input events](/dotnet/desktop/wpf/advanced/routed-events-overview?view=netframeworkdesktop-4.8&preserve-view=true#wpf-input-events).
## See also
- [Routed events overview](/dotnet/desktop/wpf/advanced/routed-events-overview?view=netframeworkdesktop-4.8&preserve-view=true)
- [Input overview](/dotnet/desktop/wpf/advanced/input-overview?view=netframeworkdesktop-4.8&preserve-view=true)
- [Control authoring overview](/dotnet/desktop/wpf/controls/control-authoring-overview?view=netframeworkdesktop-4.8&preserve-view=true)
- [Handle a routed event](/dotnet/desktop/wpf/advanced/how-to-handle-a-routed-event?view=netframeworkdesktop-4.8&preserve-view=true).
@@ -0,0 +1,45 @@
using System;
using System.Windows;
using System.Windows.Controls;
namespace WpfControl
{
//<CustomButton>
public class CustomButton : Button
{
// Register a custom routed event using the Bubble routing strategy.
public static readonly RoutedEvent ConditionalClickEvent = EventManager.RegisterRoutedEvent(
name: "ConditionalClick",
routingStrategy: RoutingStrategy.Bubble,
handlerType: typeof(RoutedEventHandler),
ownerType: typeof(CustomButton));
// Provide CLR accessors for assigning an event handler.
public event RoutedEventHandler ConditionalClick
{
add { AddHandler(ConditionalClickEvent, value); }
remove { RemoveHandler(ConditionalClickEvent, value); }
}
void RaiseCustomRoutedEvent()
{
// Create a RoutedEventArgs instance.
RoutedEventArgs routedEventArgs = new(routedEvent: ConditionalClickEvent);
// Raise the event, which will bubble up through the element tree.
RaiseEvent(routedEventArgs);
}
// For demo purposes, we use the Click event as a trigger.
protected override void OnClick()
{
// Some condition combined with the Click event will trigger the ConditionalClick event.
if (DateTime.Now > new DateTime())
RaiseCustomRoutedEvent();
// Call the base class OnClick() method so Click event subscribers are notified.
base.OnClick();
}
}
//</CustomButton>
}
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWPF>true</UseWPF>
</PropertyGroup>
</Project>
@@ -0,0 +1,53 @@
Imports System.Windows
Imports System.Windows.Controls
'<CustomButton>
Public Class CustomButton
Inherits Button
' Register a custom routed event with the Bubble routing strategy.
Public Shared ReadOnly ConditionalClickEvent As RoutedEvent = EventManager.RegisterRoutedEvent(
name:="ConditionalClick",
routingStrategy:=RoutingStrategy.Bubble,
handlerType:=GetType(RoutedEventHandler),
ownerType:=GetType(CustomButton))
' Provide CLR accessors to support event handler assignment.
Public Custom Event ConditionalClick As RoutedEventHandler
AddHandler(value As RoutedEventHandler)
[AddHandler](ConditionalClickEvent, value)
End AddHandler
RemoveHandler(value As RoutedEventHandler)
[RemoveHandler](ConditionalClickEvent, value)
End RemoveHandler
RaiseEvent(sender As Object, e As RoutedEventArgs)
[RaiseEvent](e)
End RaiseEvent
End Event
Private Sub RaiseCustomRoutedEvent()
' Create a RoutedEventArgs instance.
Dim routedEventArgs As New RoutedEventArgs(routedEvent:=ConditionalClickEvent)
' Raise the event, which will bubble up through the element tree.
[RaiseEvent](routedEventArgs)
End Sub
' For demo purposes, we use the Click event as a trigger.
Protected Overrides Sub OnClick()
' Some condition combined with the Click event will trigger the ConditionalClick event.
If Date.Now > New DateTime() Then RaiseCustomRoutedEvent()
' Call the base class OnClick() method so Click event subscribers are notified.
MyBase.OnClick()
End Sub
End Class
'</CustomButton>
@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<RootNamespace>WpfControlVb</RootNamespace>
<AssemblyName>WpfControlLibraryVb</AssemblyName>
<TargetFramework>net6.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
</PropertyGroup>
</Project>
@@ -0,0 +1,11 @@
using System.Windows;
namespace CodeSample
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
}
}
@@ -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)
)]
@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
<NeutralLanguage>en-us</NeutralLanguage>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\WpfControlLibraryCsharp\WpfControlLibrary.csproj" />
</ItemGroup>
<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>
@@ -0,0 +1,17 @@
<!--<MainWindowXaml>-->
<Window x:Class="CodeSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:custom="clr-namespace:WpfControl;assembly=WpfControlLibrary"
Title="How to create a custom routed event" Height="100" Width="300">
<StackPanel Name="StackPanel1" custom:CustomButton.ConditionalClick="Handler_ConditionalClick">
<custom:CustomButton
Name="customButton"
ConditionalClick="Handler_ConditionalClick"
Content="Click to trigger a custom routed event"
Background="LightGray">
</custom:CustomButton>
</StackPanel>
</Window>
<!--</MainWindowXaml>-->
@@ -0,0 +1,42 @@
using System.Diagnostics;
using System.Windows;
namespace CodeSample
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// Assign an event handler to the CustomButton using the '+=' operator.
// customButton.ConditionalClick += Handler_ConditionalClick;
// Assign an event handler to the CustomButton using the AddHandler method.
// customButton.AddHandler(WpfControl.CustomButton.ConditionalClickEvent,
// new RoutedEventHandler(Handler_ConditionalClick));
// Assign an event handler to the StackPanel using the AddHandler method.
// StackPanel1.AddHandler(WpfControl.CustomButton.ConditionalClickEvent,
// new RoutedEventHandler(Handler_ConditionalClick));
}
//<EventHandler>
// The ConditionalClick event handler.
private void Handler_ConditionalClick(object sender, RoutedEventArgs e)
{
string senderName = ((FrameworkElement)sender).Name;
string sourceName = ((FrameworkElement)e.Source).Name;
Debug.WriteLine($"Routed event handler attached to {senderName}, " +
$"triggered by the ConditionalClick routed event raised on {sourceName}.");
}
// Debug output when CustomButton is clicked:
// Routed event handler attached to CustomButton,
// triggered by the ConditionalClick routed event raised on CustomButton.
// Routed event handler attached to StackPanel1,
// triggered by the ConditionalClick routed event raised on CustomButton.
//</EventHandler>
}
}
@@ -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 CodeSample.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("CodeSample.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;
}
}
}
}
@@ -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>
@@ -0,0 +1,9 @@
<Application x:Class="CodeSample.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CodeSample"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>
@@ -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>
@@ -0,0 +1,6 @@
Class Application
' Application-level events, such as Startup, Exit, and DispatcherUnhandledException
' can be handled in this file.
End Class
@@ -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)>
@@ -0,0 +1,27 @@
<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>
<ItemGroup>
<ProjectReference Include="..\WpfControlLibraryVb\WpfControlLibraryVb.vbproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,17 @@
<!--<MainWindowXaml>-->
<Window x:Class="CodeSampleVb.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:custom="clr-namespace:WpfControlVb;assembly=WpfControlLibraryVb"
Title="How to create a custom routed event" Height="100" Width="300">
<StackPanel Name="StackPanel1">
<custom:CustomButton
Name="customButton"
ConditionalClick="Handler_ConditionalClick"
Content="Click to trigger a custom routed event"
Background="LightGray">
</custom:CustomButton>
</StackPanel>
</Window>
<!--</MainWindowXaml>-->
@@ -0,0 +1,39 @@
Namespace CodeSampleVb
Partial Public Class MainWindow
Inherits Window
Public Sub New()
InitializeComponent()
' Assign an event handler to CustomButton using the AddHandler statement.
' AddHandler customButton.ConditionalClick, AddressOf Handler_ConditionalClick
' Assign an event handler to CustomButton using the AddHandler method.
' customButton.[AddHandler](WpfControlVb.CustomButton.ConditionalClickEvent,
' New RoutedEventHandler(AddressOf Handler_ConditionalClick))
' Assign an event handler to StackPanel1 using the AddHandler method.
' StackPanel1.[AddHandler](WpfControlVb.CustomButton.ConditionalClickEvent,
' New RoutedEventHandler(AddressOf Handler_ConditionalClick))
End Sub
'<EventHandler>
' The ConditionalClick event handler.
Private Sub Handler_ConditionalClick(sender As Object, e As RoutedEventArgs)
Dim sourceName As String = CType(e.Source, FrameworkElement).Name
Dim senderName As String = CType(sender, FrameworkElement).Name
Debug.WriteLine($"Routed event handler attached to {senderName}, " +
$"triggered by the ConditionalClick routed event raised on {sourceName}.")
End Sub
' Debug output when CustomButton is clicked:
' Routed event handler attached to CustomButton,
' triggered by the ConditionalClick routed event raised on CustomButton.
' Routed event handler attached to StackPanel1,
' triggered by the ConditionalClick routed event raised on CustomButton.
'</EventHandler>
End Class
End Namespace
+2
View File
@@ -84,6 +84,8 @@ items:
items:
- name: Add an event handler using code
href: events/how-to-add-an-event-handler-using-code.md
- name: Create a custom routed event
href: events/how-to-create-a-custom-routed-event.md
- name: Properties
items:
- name: Dependency properties
+5
View File
@@ -333,6 +333,11 @@
"SourceUrl": "/dotnet/desktop/wpf/advanced/how-to-add-an-event-handler-using-code?view=netframeworkdesktop-4.8",
"TargetUrl": "/dotnet/desktop/wpf/events/how-to-add-an-event-handler-using-code?view=netdesktop-6.0"
},
{
"Redirect": "TwoWay",
"SourceUrl": "/dotnet/desktop/wpf/advanced/how-to-create-a-custom-routed-event?view=netframeworkdesktop-4.8",
"TargetUrl": "/dotnet/desktop/wpf/events/how-to-create-a-custom-routed-event?view=netdesktop-6.0"
},
// Systems - Properties
{