路由事件的三类传播方式
-
冒泡事件(Bubbling)
事件从源元素向上传递到根元素(如
Button.Click)。XML<StackPanel Button.Click="StackPanel_Click"> <Button Content="Click Me"/> </StackPanel>csharpprivate void StackPanel_Click(object sender, RoutedEventArgs e) { // 处理按钮点击事件 } -
隧道事件(Tunneling)
事件从根元素向下传递到源元素(命名以
Preview开头,如PreviewMouseDown)。XML<StackPanel PreviewMouseDown="StackPanel_PreviewMouseDown"> <Button Content="Click Me"/> </StackPanel>csharpprivate void StackPanel_PreviewMouseDown(object sender, MouseButtonEventArgs e) { // 在事件到达按钮前拦截 } -
直接事件(Direct)
仅触发在源元素上,不传播(如
MouseEnter)。 -
添加/移除事件处理器
csharpbutton.AddHandler(Button.ClickEvent, new RoutedEventHandler(HandleClick)); button.RemoveHandler(Button.ClickEvent, new RoutedEventHandler(HandleClick)); -
终止事件传播
在事件处理器中设置
e.Handled = true,阻止事件继续冒泡或隧道。csharpprivate void HandleClick(object sender, RoutedEventArgs e) { e.Handled = true; // 停止传播 } -
输入事件
MouseDown(冒泡)、PreviewKeyDown(隧道) -
控件事件
Button.Click(冒泡)、TextBox.TextChanged(直接) -
全局快捷键
在窗口级处理PreviewKeyDown事件,拦截特定按键组合。 -
控件组合交互
父容器监听子控件的冒泡事件(如ListBox中按钮的点击)。 -
INotifyPropertyChanged实现:csharppublic 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接口实现:csharppublic 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)。
样式与模板
-
控件模板示例:
XML<ControlTemplate TargetType="Button"> <Border Background="{TemplateBinding Background}" CornerRadius="5"> <ContentPresenter HorizontalAlignment="Center"/> </Border> </ControlTemplate> -
触发器类型:
PropertyTrigger、DataTrigger、EventTrigger。
性能优化
-
虚拟化技术:
VirtualizingStackPanel用于ListBox等控件,延迟加载可视项。 -
依赖属性机制:静态注册节省内存,支持值继承、动画等。
csharppublic 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.Invoke或Dispatcher.BeginInvoke。 - 自定义绘图:继承
FrameworkElement,重写OnRender方法使用DrawingContext。
调试技巧
- 使用Snoop或WPF Inspector工具实时查看视觉树。
- 绑定失败时查看Output窗口的绑定错误日志。
PresentationTraceSources.TraceLevel=High诊断绑定问题。