wpf路由事件

前言

1、什么是路由事件?

路由事件 是一种能在 元素树(Visual Tree) 中沿着传播方向(向上/向下)被多个元素处理的事件。

传统的 .NET 事件:事件只会在触发它的控件上被处理。

WPF 路由事件:事件可以从一个元素"路由"到其他元素。

本质:解决了 UI 树中深层嵌套控件的通信与事件处理问题。

2、三种路由策略

3、事件参数与传播控制

所有路由事件都使用 RoutedEventArgs(或其派生类):

csharp 复制代码
public class RoutedEventArgs : EventArgs
{
    public RoutedEvent RoutedEvent { get; set; } // 当前事件
    public object Source { get; set; }           // 逻辑树上的源
    public object OriginalSource { get; set; }   // 视觉树上的真实源
    public bool Handled { get; set; }            // 是否已处理
}

重要方法:e.Handled = true 可以阻止事件继续传播。

4、系统常用路由事件(你遇到过/提到的)

4.1、冒泡事件

4.1.1(系统自带的冒泡事件)

冒泡事件的传播方向是:从触发事件的元素开始,沿着 UI 树向上(向根元素)逐级传递,就像气泡从水底往水面上升一样,事件从深层控件一层层往上"冒"到顶层窗口,比如一个StackPanel中放了Buttton,从Button传到StackPanel就是冒泡事件,冒泡事件一般在统一处理多个子控件的相同操作时需要使用冒泡事件。ButtonBase类中的Click是一个冒泡事件,当点击按钮"保存"、"删除" 、"编辑"时,触发冒泡事件,这时候事件被传递到上一层StackPanel,又因为StackPanel监听了

ButtonBase.Click事件,所以就能看到StackPanel_Click方法被触发。

csharp 复制代码
 <StackPanel  Grid.Column=" 2" ButtonBase.Click="StackPanel_Click">
            <Button Content="保存" Tag="Save"/>
            <Button Content="删除" Tag="Delete"/>
            <Button Content="编辑" Tag="Edit"/>
        </StackPanel>
csharp 复制代码
 private void StackPanel_Click(object sender, RoutedEventArgs e)
        {

        }

4.1.2(自定义的冒泡事件)

1)注册路由事件

路由事件也是定义在控件自身的类当中,使用EventManager.RegisterRoutedEvent方法注册路由事件,该方法第一个参数是"事件名称";第二个参数是路由策略,路由策略分为冒泡、隧道、直接三种;第3个参数是委托类型,这个委托类型不是固定的,RoutedEventHandler是标准的写法;第4个参数是事件所在的类。

2)添加CLR事件包装器

事件包装器与属性包装器类似,它是为路由事件提供一个标准的 .NET 事件访问接口,让开发者能够用熟悉的方式使用事件。

3)触发自定义路由事件

重写OnClick方法,首先调用base.OnClick()让标准的Click事件进行触发,接下来调用 RaiseEvent(new RoutedEventArgs(MyClickEvent, this));从而让自定义的路由事件MyClick触发。

csharp 复制代码
 public class MyButton : Button
    {
        // 1. 注册路由事件(静态只读)
        public static readonly RoutedEvent MyClickEvent =
            EventManager.RegisterRoutedEvent(
                name: "MyClick",                    // 事件名称
                routingStrategy: RoutingStrategy.Bubble,  // 路由策略
                handlerType: typeof(RoutedEventHandler),    // 委托类型
                ownerType: typeof(MyButton)                 // 所属类型
            );

        // 2. 添加CLR事件包装器(供代码使用 += / -=)
        public event RoutedEventHandler MyClick
        {
            add { AddHandler(MyClickEvent, value); }
            remove { RemoveHandler(MyClickEvent, value); }
        }

        // 3. 触发事件的受保护方法(供派生类调用)
        protected override void OnClick()
        {
            base.OnClick();  // 先触发原生 Click 事件
            RaiseEvent(new RoutedEventArgs(MyClickEvent, this));
        }
    }

xaml界面代码

下面的代码中

csharp 复制代码
 <StackPanel Grid.Column=" 0"  Orientation="Horizontal"   local:MyButton.MyClick="StackPanel_MyClick" Background="Red" >
            <local:MyButton Content="点我"    Width="100" Height="30"/>
        </StackPanel >

private void StackPanel_MyClick(object sender, RoutedEventArgs e)

{

复制代码
}

当点击按钮"点我"时,会触发MyClick路由事件,由于StackPanel监听了MyClick事件,所以StackPanel_MyClick方法就会被执行。

4.2、隧道事件

4.3.1 (系统自带的隧道事件)

PreviewMouseDown是系统自带的隧道事件,它在鼠标按钮被按下时发生,从根元素向下传递到实际被点击的元素。

下面的代码中StackPanel和"按钮2"都监听了PreviewMouseDown事件,当点击"按钮1"时,由于隧道事件从根元素开始传递,所以StackPanel的StackPanel_PreviewMouseDown方法先执行;当点击"按钮2"时,由于隧道事件从根元素开始传递,所以StackPanel的StackPanel_PreviewMouseDown方法先执行,然后"按钮2"的Button_PreviewMouseDown方法再执行,这样就能看出隧道事件都是先从根元素开始触发的。

csharp 复制代码
<StackPanel  Grid.Column=" 3"  PreviewMouseDown="StackPanel_PreviewMouseDown">
            <Button Content="按钮1"/>
            <Button Content="按钮2" PreviewMouseDown="Button_PreviewMouseDown"/>
        </StackPanel>
csharp 复制代码
private void StackPanel_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            Console.WriteLine("隧道StackPanel_PreviewMouseDown");
        }

        private void Button_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            Console.WriteLine("隧道Button_PreviewMouseDown");
        }

4.3.2 (自定义的隧道事件)

4.3、直接事件(自定义路由事件)

相关推荐
nashane6 小时前
HarmonyOS 鸿蒙 2026 全栈实战:从手势驱动到分布式数据落地的完整架构
wpf·harmony app
秋雨雁南飞8 小时前
WPF 国际化(全球化)管理
wpf
nashane1 天前
HarmonyOS 6.0 分布式数据库进阶:设备协同与高效数据同步实战(API 11 Stage 模型)
wpf·harmonyos 5
极客智造1 天前
WPF InputBindings MVVM详解
wpf
nashane1 天前
HarmonyOS 6.0 分布式数据实战:KVStore跨设备同步与高性能查询指南(API 11 Stage模型)
wpf·harmonyos 5
SEO-狼术2 天前
Easily Reorder Rows in WPF Grids
wpf
烟话66 天前
MVVM核心机制:属性通知与命令绑定解析
wpf
不知名君6 天前
WPF 的原生窗体标题栏主题自适应系统深浅主题
wpf
碎碎念的安静6 天前
WPF 与 Qt 进程间通信(IPC)
开发语言·qt·wpf