当前位置: 首页 > news >正文

WPF路由事件:冒泡、隧道与直接全解析

路由事件的三类传播方式

  • 冒泡事件(Bubbling)
    事件从源元素向上传递到根元素(如Button.Click)。

    <StackPanel Button.Click="StackPanel_Click"><Button Content="Click Me"/>
    </StackPanel>
    

    private void StackPanel_Click(object sender, RoutedEventArgs e) {// 处理按钮点击事件
    }
    

  • 隧道事件(Tunneling)
    事件从根元素向下传递到源元素(命名以Preview开头,如PreviewMouseDown)。

    <StackPanel PreviewMouseDown="StackPanel_PreviewMouseDown"><Button Content="Click Me"/>
    </StackPanel>
    

    private void StackPanel_PreviewMouseDown(object sender, MouseButtonEventArgs e) {// 在事件到达按钮前拦截
    }
    

  • 直接事件(Direct)
    仅触发在源元素上,不传播(如MouseEnter)。

  • 添加/移除事件处理器

    button.AddHandler(Button.ClickEvent, new RoutedEventHandler(HandleClick));
    button.RemoveHandler(Button.ClickEvent, new RoutedEventHandler(HandleClick));
    

  • 终止事件传播
    在事件处理器中设置e.Handled = true,阻止事件继续冒泡或隧道。

    private void HandleClick(object sender, RoutedEventArgs e) {e.Handled = true; // 停止传播
    }
    

  • 输入事件
    MouseDown(冒泡)、PreviewKeyDown(隧道)
  • 控件事件
    Button.Click(冒泡)、TextBox.TextChanged(直接)
  • 全局快捷键
    在窗口级处理PreviewKeyDown事件,拦截特定按键组合。
  • 控件组合交互
    父容器监听子控件的冒泡事件(如ListBox中按钮的点击)。
  • INotifyPropertyChanged实现:
    public class Model : INotifyPropertyChanged {private string _name;public string Name {get => _name;set { _name = value; OnPropertyChanged(nameof(Name)); }}public event PropertyChangedEventHandler PropertyChanged;protected void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    

命令与MVVM

  • ICommand接口实现:
    public class RelayCommand : ICommand {private readonly Action _execute;public RelayCommand(Action execute) => _execute = execute;public bool CanExecute(object parameter) => true;public void Execute(object parameter) => _execute();public event EventHandler CanExecuteChanged;
    }
    

  • MVVM优势:解耦视图与逻辑,利于单元测试,支持设计时数据(d:DataContext)。

样式与模板

  • 控件模板示例:
    <ControlTemplate TargetType="Button"><Border Background="{TemplateBinding Background}" CornerRadius="5"><ContentPresenter HorizontalAlignment="Center"/></Border>
    </ControlTemplate>
    

  • 触发器类型:PropertyTriggerDataTriggerEventTrigger

性能优化

  • 虚拟化技术:VirtualizingStackPanel用于ListBox等控件,延迟加载可视项。
  • 依赖属性机制:静态注册节省内存,支持值继承、动画等。
    public static readonly DependencyProperty IsActiveProperty = DependencyProperty.Register("IsActive", typeof(bool), typeof(MyControl));public bool IsActive {get => (bool)GetValue(IsActiveProperty);set => SetValue(IsActiveProperty, value);
    }
    

高级主题

  • 路由事件:Bubbling(冒泡)、Tunneling(隧道)、Direct(直接)。
  • 跨线程访问UI:Dispatcher.InvokeDispatcher.BeginInvoke
  • 自定义绘图:继承FrameworkElement,重写OnRender方法使用DrawingContext

调试技巧

  • 使用Snoop或WPF Inspector工具实时查看视觉树。
  • 绑定失败时查看Output窗口的绑定错误日志。
  • PresentationTraceSources.TraceLevel=High诊断绑定问题。
http://www.dtcms.com/a/264502.html

相关文章:

  • 【Harmony】鸿蒙企业应用详解
  • 小型水电站综合自动化系统的介绍
  • 计算机组成笔记:缓存替换算法
  • QT6 源(147)模型视图架构里的表格窗体 QTableWidget 的范例代码举例,以及其条目 QTableWidgetItem 类型的源代码。
  • Re:从零开始的 磁盘调度进程调度算法(考研向)
  • Node.js 安装使用教程
  • Spring 生态创新应用:微服务架构设计与前沿技术融合实践
  • Kuikly 与 Flutter 的全面对比分析,结合技术架构、性能、开发体验等核心维度
  • 对于3DGS的理解
  • Redisson 与 Java 驻内存数据网格:分布式缓存的高可用解决方案
  • 【强化学习】深度解析 GRPO:从原理到实践的全攻略
  • 微信小程序入门实例_____打造你的专属单词速记小程序
  • 【并发编程】AQS原理详解笔记1
  • 基于SpringBoot和Leaflet的区域冲突可视化系统(2025企业级实战方案)
  • 服务器异常宕机或重启导致 RabbitMQ 启动失败问题分析与解决方案
  • 使用tensorflow的线性回归的例子(五)
  • 界面组件DevExpress WPF中文教程:Grid - 如何获取节点?
  • 【办公类-53-05】20250701Python模仿制作2025学年第一学期校历(excel+pdf)
  • 计算机网络(五)数据链路层 MAC和ARP协议
  • Mabl 基于云端的智能化自动化测试平台
  • 解决Python升级后CMD仍显示旧版本:环境变量优先级问题详解
  • vue中ref()和reactive()区别
  • 聚类算法学习
  • PAL(程序辅助语言模型)技术详解
  • 通讯录管理系统设计与实现(C++)
  • URL时间戳参数深度解析:缓存破坏与前端优化的前世今生
  • 调试 WebView 旧资源缓存问题:一次从偶发到复现的实战经历
  • 安装Pillow失败,无libjpeg包
  • OWASP Top 10 是什么?
  • Docker+vLLM内网离线部署DeepSeek