diff --git a/.openpublishing.redirection.json b/.openpublishing.redirection.json index 2ea2fcc661..a208fdbbeb 100644 --- a/.openpublishing.redirection.json +++ b/.openpublishing.redirection.json @@ -604,6 +604,14 @@ { "source_path": "dotnet-desktop-guide/framework/wpf/properties/xaml-loading-and-dependency-properties.md", "redirect_url": "/dotnet/desktop/wpf/advanced/xaml-loading-and-dependency-properties?view=netframeworkdesktop-4.8" + }, + { + "source_path": "dotnet-desktop-guide/net/wpf/advanced/how-to-add-an-event-handler-using-code.md", + "redirect_url": "/dotnet/desktop/wpf/events/how-to-add-an-event-handler-using-code?view=netdesktop-6.0" + }, + { + "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" } ] } diff --git a/dotnet-desktop-guide/net/wpf/events/how-to-add-an-event-handler-using-code.md b/dotnet-desktop-guide/net/wpf/events/how-to-add-an-event-handler-using-code.md new file mode 100644 index 0000000000..4bc909490d --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/events/how-to-add-an-event-handler-using-code.md @@ -0,0 +1,76 @@ +--- +title: "How to add an event handler using code" +description: Learn how to add an event handler in code-behind for an element in Windows Presentation Foundation (WPF). +ms.date: "02/01/2021" +dev_langs: + - "csharp" + - "vb" +helpviewer_keywords: + - "event handlers [WPF], adding" + - "XAML [WPF], adding event handlers" +--- + + +# How to add an event handler using code (WPF .NET) + +You can assign an event handler to an element in Windows Presentation Foundation (WPF) using markup or code-behind. Although it's customary to assign an event handler in Extensible Application Markup Language (XAML), sometimes you might have to assign an event handler in code-behind. For instance, use code when: + +- You assign an event handler to an element after the markup page that contains the element loads. +- You add an element and assign its event handler after the markup page that will contain the element loads. +- You define the element tree for your application entirely in code. + +[!INCLUDE [desktop guide under construction](../../includes/desktop-guide-preview-note.md)] + +## Syntax for event handler assignment + +C# supports event handler assignment using: + +- The `+=` operator, which is also used in the common language runtime (CLR) event handling model. +- The method. + +VB supports event handler assignment using: + +- The [AddHandler](/dotnet/visual-basic/language-reference/statements/addhandler-statement) statement with the [AddressOf](/dotnet/visual-basic/language-reference/operators/addressof-operator) operator, which is also used in the CLR event handling model. +- The [Handles](/dotnet/visual-basic/language-reference/statements/handles-clause) keyword in the event handler definition. For more information, see [Visual Basic and WPF event handling](/dotnet/desktop/wpf/advanced/visual-basic-and-wpf-event-handling?view=netframeworkdesktop-4.8&preserve-view=true). +- The method, together with the `AddressOf` operator to reference the event handler. + +## Example + +The following example uses XAML to define a named `ButtonCreatedByXaml` and to assign the `ButtonCreatedByXaml_Click` method as its event handler. `Click` is a built-in routed event for buttons that derive from . + +:::code language="xaml" source="./snippets/how-to-add-an-event-handler-using-code/csharp/MainWindow.xaml" id="ButtonCreatedByXaml"::: + +The example uses code-behind to implement the `ButtonCreatedByXaml_Click` and `ButtonCreatedByCode_Click` handlers, and to assign the `ButtonCreatedByCode_Click` handler to the `ButtonCreatedByCode` and `StackPanel1` elements. Event handler methods can only be implemented in code-behind. + +:::code language="csharp" source="./snippets/how-to-add-an-event-handler-using-code/csharp/MainWindow.xaml.cs" id="ButtonEventHandlers"::: +:::code language="vb" source="./snippets/how-to-add-an-event-handler-using-code/vb/MainWindow.xaml.vb" id="ButtonEventHandlers"::: + +When `ButtonCreatedByXaml` is clicked and its event handler runs, `ButtonCreatedByXaml_Click` programmatically: + +1. Adds a new button named `ButtonCreatedByCode` to the already constructed XAML element tree. +1. Specifies properties for the new button, such as the name, content, and background color. +1. Assigns the `ButtonCreatedByCode_Click` event handler to `ButtonCreatedByCode`. +1. Assigns the same `ButtonCreatedByCode_Click` event handler to `StackPanel1`. + +When `ButtonCreatedByCode` is clicked: + +1. The routed event is raised on `ButtonCreatedByCode`. +1. The `ButtonCreatedByCode_Click` event handler assigned to `ButtonCreatedByCode` is triggered. +1. The `Click` routed event traverses up the element tree to `StackPanel1`. +1. The `ButtonCreatedByCode_Click` event handler assigned to `StackPanel1` is triggered. +1. The `Click` routed event continues up the element tree potentially triggering other `Click` event handlers assigned to other traversed elements. + +The `ButtonCreatedByCode_Click` 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 `ButtonCreatedByCode` the first time the handler runs, and `StackPanel1` the second time. +- The object, which is the element that originally raised the event. In this example, the `Source` is always `ButtonCreatedByCode`. + +> [!NOTE] +> A key difference between a routed event and a CLR event is that a routed event traverses the element tree, whereas a CLR event occurs only on the `sender`. As a result, a routed event `sender` can be any traversed element in the element tree. + +For more information on how to create and handle routed events, see [How to create a custom routed event](/dotnet/desktop/wpf/advanced/how-to-create-a-custom-routed-event?view=netframeworkdesktop-4.8&preserve-view=true) and [Handle a routed event](/dotnet/desktop/wpf/advanced/how-to-handle-a-routed-event?view=netframeworkdesktop-4.8&preserve-view=true). + +## See also + +- [Routed events overview](/dotnet/desktop/wpf/advanced/routed-events-overview?view=netframeworkdesktop-4.8&preserve-view=true) +- [XAML in WPF](/dotnet/desktop/wpf/advanced/xaml-in-wpf?view=netframeworkdesktop-4.8&preserve-view=true) diff --git a/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/csharp/App.xaml.cs b/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/csharp/App.xaml.cs new file mode 100644 index 0000000000..31285520b3 --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/csharp/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace CodeSampleCsharp +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/csharp/AssemblyInfo.cs b/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/csharp/AssemblyInfo.cs new file mode 100644 index 0000000000..8b5504ecfb --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/csharp/AssemblyInfo.cs @@ -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) +)] diff --git a/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/csharp/CodeSampleCsharp.csproj b/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/csharp/CodeSampleCsharp.csproj new file mode 100644 index 0000000000..5621ca97f6 --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/csharp/CodeSampleCsharp.csproj @@ -0,0 +1,25 @@ + + + + WinExe + net6.0-windows + true + en-us + + + + + True + True + Resources.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + diff --git a/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/csharp/MainWindow.xaml b/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/csharp/MainWindow.xaml new file mode 100644 index 0000000000..0b1f7b6091 --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/csharp/MainWindow.xaml @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/csharp/MainWindow.xaml.cs b/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/csharp/MainWindow.xaml.cs new file mode 100644 index 0000000000..2b96682248 --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/csharp/MainWindow.xaml.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Media; + +namespace CodeSampleCsharp +{ + /// + /// Interaction logic for MainWindow.xaml. + /// + public partial class MainWindow : Window + { + public MainWindow() + { + InitializeComponent(); + } + + // + // The click event handler for the existing button 'ButtonCreatedByXaml'. + private void ButtonCreatedByXaml_Click(object sender, RoutedEventArgs e) + { + // Create a new button. + Button ButtonCreatedByCode = new(); + + // Specify button properties. + ButtonCreatedByCode.Name = "ButtonCreatedByCode"; + ButtonCreatedByCode.Content = "New button and event handler created in code"; + ButtonCreatedByCode.Background = Brushes.Yellow; + + // Add the new button to the StackPanel. + StackPanel1.Children.Add(ButtonCreatedByCode); + + // Assign an event handler to the new button using the '+=' operator. + ButtonCreatedByCode.Click += new RoutedEventHandler(ButtonCreatedByCode_Click); + + // Assign an event handler to the new button using the AddHandler method. + // AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(ButtonCreatedByCode_Click); + + // Assign an event handler to the StackPanel using the AddHandler method. + StackPanel1.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(ButtonCreatedByCode_Click)); + } + + // The Click event handler for the new button 'ButtonCreatedByCode'. + private void ButtonCreatedByCode_Click(object sender, RoutedEventArgs e) + { + string sourceName = ((FrameworkElement)e.Source).Name; + string senderName = ((FrameworkElement)sender).Name; + + Debug.WriteLine($"Routed event handler attached to {senderName}, " + + $"triggered by the Click routed event raised by {sourceName}."); + } + // + + // Debug output when ButtonCreatedByCode is clicked: + // Routed event handler attached to ButtonCreatedByCode, triggered by the Click routed event raised by ButtonCreatedByCode. + // Routed event handler attached to StackPanel1, triggered by the Click routed event raised by ButtonCreatedByCode. + } +} diff --git a/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/csharp/Properties/Resources.Designer.cs b/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/csharp/Properties/Resources.Designer.cs new file mode 100644 index 0000000000..64552f96fd --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/csharp/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// 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. +// +//------------------------------------------------------------------------------ + +namespace CodeSampleCsharp.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // 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", "16.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() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [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; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/csharp/Properties/Resources.resx b/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/csharp/Properties/Resources.resx new file mode 100644 index 0000000000..1af7de150c --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/csharp/Properties/Resources.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/csharp/app.xaml b/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/csharp/app.xaml new file mode 100644 index 0000000000..867d2f015f --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/csharp/app.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/vb/Application.xaml b/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/vb/Application.xaml new file mode 100644 index 0000000000..f225972592 --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/vb/Application.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/vb/Application.xaml.vb b/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/vb/Application.xaml.vb new file mode 100644 index 0000000000..084cbe917e --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/vb/Application.xaml.vb @@ -0,0 +1,6 @@ +Class Application + + ' Application-level events, such as Startup, Exit, and DispatcherUnhandledException + ' can be handled in this file. + +End Class diff --git a/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/vb/AssemblyInfo.vb b/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/vb/AssemblyInfo.vb new file mode 100644 index 0000000000..025ee7271e --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/vb/AssemblyInfo.vb @@ -0,0 +1,11 @@ +Imports System.Windows + +'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) + diff --git a/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/vb/CodeSampleVb.vbproj b/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/vb/CodeSampleVb.vbproj new file mode 100644 index 0000000000..90d032bcab --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/vb/CodeSampleVb.vbproj @@ -0,0 +1,23 @@ + + + + WinExe + net6.0-windows + CodeSampleVb + en-us + true + + + + + + + + + + + + + + + diff --git a/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/vb/MainWindow.xaml b/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/vb/MainWindow.xaml new file mode 100644 index 0000000000..f125d1b821 --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/vb/MainWindow.xaml @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/vb/MainWindow.xaml.vb b/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/vb/MainWindow.xaml.vb new file mode 100644 index 0000000000..0fccfa5dbc --- /dev/null +++ b/dotnet-desktop-guide/net/wpf/events/snippets/how-to-add-an-event-handler-using-code/vb/MainWindow.xaml.vb @@ -0,0 +1,57 @@ +Imports System.Windows.Controls.Primitives + +Namespace CodeSampleVb + + ' + ' Interaction logic for MainWindow.xaml. + ' + Partial Public Class MainWindow + Inherits Window + + Public Sub New() + InitializeComponent() + End Sub + + ' + ' The click event handler for the existing button 'ButtonCreatedByXaml'. + Private Sub ButtonCreatedByXaml_Click(sender As Object, e As RoutedEventArgs) + + ' Create a new button and specify button properties. + Dim ButtonCreatedByCode As New Button With { + .Name = "ButtonCreatedByCode", + .Content = "New button and event handler created in code", + .Background = Brushes.Yellow + } + + ' Add the new button to the StackPanel. + StackPanel1.Children.Add(ButtonCreatedByCode) + + ' Assign an event handler to the new button using the AddHandler statement. + AddHandler ButtonCreatedByCode.Click, AddressOf ButtonCreatedByCode_Click + + ' Assign an event handler to the new button using the AddHandler method. + ' ButtonCreatedByCode.AddHandler(ButtonBase.ClickEvent, New RoutedEventHandler(AddressOf ButtonCreatedByCode_Click)) + + ' Assign an event handler to the StackPanel using the AddHandler method. + StackPanel1.AddHandler(ButtonBase.ClickEvent, New RoutedEventHandler(AddressOf ButtonCreatedByCode_Click)) + + End Sub + + ' The Click event handler for the new button 'ButtonCreatedByCode'. + Private Sub ButtonCreatedByCode_Click(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 Click routed event raised by {sourceName}.") + + End Sub + ' + + ' Debug output when ButtonCreatedByCode is clicked: + ' Routed event handler attached to ButtonCreatedByCode, triggered by the Click routed event raised by ButtonCreatedByCode. + ' Routed event handler attached to StackPanel1, triggered by the Click routed event raised by ButtonCreatedByCode. + End Class + +End Namespace diff --git a/dotnet-desktop-guide/net/wpf/toc.yml b/dotnet-desktop-guide/net/wpf/toc.yml index 9e6946542f..d6e19dc536 100644 --- a/dotnet-desktop-guide/net/wpf/toc.yml +++ b/dotnet-desktop-guide/net/wpf/toc.yml @@ -78,6 +78,12 @@ items: - name: Systems expanded: true items: + - name: Events + items: + - name: Common tasks + items: + - name: Add an event handler using code + href: events/how-to-add-an-event-handler-using-code.md - name: Properties items: - name: Dependency properties diff --git a/redirects_generator/definitions.json b/redirects_generator/definitions.json index df0732df01..031c6aaa6a 100644 --- a/redirects_generator/definitions.json +++ b/redirects_generator/definitions.json @@ -327,6 +327,13 @@ "TargetUrl": "/dotnet/desktop/wpf/documents/how-to-print-xps-files?view=netdesktop-6.0" }, + // Systems - Events + { + "Redirect": "TwoWay", + "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" + }, + // Systems - Properties { "Redirect": "TwoWay",