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、直接事件(自定义路由事件)

相关推荐
慧都小妮子4 小时前
SciChart WPF v9.0 更新详解:矢量场图表、堆叠箱线图与 MVVM 轴同步来了
c#·.net·wpf·数据可视化·图表控件·图表
He BianGu10 小时前
【笔记】WPF中 Brush 的类型、继承关系、使用方式和注意事项
笔记·wpf
FuckPatience2 天前
WPF GridView 列绑定时前端没有属性提示
wpf
界面开发小八哥2 天前
界面控件DevExpress WPF v26.1新版亮点 - 模板工具包 & MVVM功能全新升级
wpf·界面控件·devexpress·ui开发·.net 10
记忆停留w4 天前
Celery+Redis 分布式异步任务队列工程落地业务逻辑
大数据·人工智能·redis·分布式·缓存·架构·wpf
雪靡4 天前
WPF PerMonitorV2 下的跨窗口问题
c#·wpf
listening7775 天前
HarmonyOS 6.1 分布式文件服务实战:跨设备商品图片/视频秒开方案
wpf·harmonyos
Macbethad5 天前
基于WPF的半导体设备EAP控制程序架构设计与实现
wpf
国服第二切图仔6 天前
HarmonyOS APP《画伴梦工厂》开发第60篇-分布式软总线2.0——多设备协同新范式
分布式·wpf·harmonyos
精神底层6 天前
拒绝 UI 卡死!我用 CSnakes 实时拦截 Python 训练流,在 WPF 中重构了 ScottPlot 5 高性能 AI 看板
python·ui·wpf