【WPF.NET开发】如何创建自定义路由事件

2024-01-03 06:10:16

本文内容

  1. 先决条件
  2. 路由事件步骤
  3. 示例

Windows Presentation Foundation (WPF) 应用程序开发人员和组件作者可以创建自定义路由事件,用于扩展公共语言运行时 (CLR) 事件的功能。 本文介绍创建自定义路由事件的基本知识。

1、先决条件

本文假定你对路由事件有基本的了解,并且已阅读
路由事件概述。 若要遵循本文中的示例,如果熟悉 Extensible Application Markup Language (XAML) 并知道如何编写 Windows Presentation Foundation (WPF) 应用程序,将会很有帮助。

2、路由事件步骤

创建路由事件的基本步骤如下:

  1. 使用?RegisterRoutedEvent?方法注册?RoutedEvent

  2. 注册调用返回一个?RoutedEvent?实例,称为路由事件标识符,该标识符包含已注册的事件名、路由策略
    和其他事件详细信息。 将该标识符分配给静态只读字段。 按照惯例:

    • 具有浮升
      策略的路由事件的标识符命名为?<event name>Event。 例如,如果事件名为?Tap,则标识符应命名为?TapEvent
    • 具有
      隧道策略的路由事件的标识符命名为?Preview<event name>Event。 例如,如果事件名为?Tap,则标识符应命名为?PreviewTapEvent
  3. 定义 CLR?add?和?remove?事件访问器。 如果没有 CLR 事件访问器,你就只能通过直接调用?UIElement.AddHandler?和?UIElement.RemoveHandler?方法来添加或删除事件处理程序。 使用 CLR 事件访问器时,你会获得以下事件处理程序分配机制:

    • 对于 Extensible Application Markup Language (XAML),可以使用属性语法来添加事件处理程序。
    • 对于 C#,可以使用?+=?和?-=?运算符来添加或删除事件处理程序。
    • 对于 VB,可以使用?AddHandler?和?RemoveHandler?语句来添加或删除事件处理程序。
  4. 添加用于触发路由事件的自定义逻辑。 例如,你的逻辑可能会基于用户输入和应用程序状态触发事件。

3、示例

以下示例在自定义控件库中实现?CustomButton?类。 派生自?Button?的?CustomButton?类:

  1. 使用?RegisterRoutedEvent?方法注册一个名为?ConditionalClick?的?RoutedEvent,并在注册期间指定浮升
    策略。
  2. 将从注册调用返回的?RoutedEvent?实例分配给名为?ConditionalClickEvent?的静态只读字段。
  3. 定义 CLR?add?和?remove?事件访问器。
  4. 添加自定义逻辑,以在单击?CustomButton?并应用外部条件时引发自定义路由事件。 虽然示例代码从重写的?OnClick?虚拟方法内引发?ConditionalClick?路由事件,但你可选用任何方式来引发事件。
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();
    }
}

该示例包含一个单独的 WPF 应用程序,该应用程序使用 XAML 标记将?CustomButton?实例添加到?StackPanel,并将?Handler_ConditionalClick?方法分配为?CustomButton?和?StackPanel1?元素的?ConditionalClick?事件处理程序。

<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>

WPF 应用程序在代码隐藏中定义?Handler_ConditionalClick?事件处理程序方法。 事件处理程序方法只能在代码隐藏中实现。

// 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.

单击?CustomButton?时:

  1. ConditionalClick?路由事件在?CustomButton?上引发。
  2. 触发了附加到?CustomButton?的?Handler_ConditionalClick?事件处理程序。
  3. ConditionalClick?路由事件在元素树中向上遍历到?StackPanel1
  4. 触发了附加到?StackPanel1?的?Handler_ConditionalClick?事件处理程序。
  5. ConditionalClick?路由事件继续向上遍历元素树,可能会触发附加到其他已遍历元素的其他?ConditionalClick?事件处理程序。

Handler_ConditionalClick?事件处理程序获取有关触发它的事件的以下信息:

  • sender?对象,它是事件处理程序附加到的元素。 处理程序首次运行时,sender?为?CustomButton,第二次运行时则为?StackPanel1
  • RoutedEventArgs.Source?对象,它是最初引发事件的元素。 在本示例中,Source?始终为?CustomButton

?备注

路由事件和 CLR 事件之间的一个主要区别是,路由事件遍历元素树来查找处理程序,而 CLR 事件不遍历元素树,处理程序只能附加到引发事件的源对象。 因此,路由事件?sender?可以是元素树中的任何已遍历的元素。

你可以像创建浮升事件一样创建隧道事件,但将在?Tunnel?事件注册调用中设置路由策略。

文章来源:https://blog.csdn.net/m0_51887793/article/details/135350913
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。