路由事件的三类传播方式
冒泡事件(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>
- 触发器类型:
PropertyTrigger
、DataTrigger
、EventTrigger
。
性能优化
- 虚拟化技术:
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.Invoke
或Dispatcher.BeginInvoke
。 - 自定义绘图:继承
FrameworkElement
,重写OnRender
方法使用DrawingContext
。
调试技巧
- 使用Snoop或WPF Inspector工具实时查看视觉树。
- 绑定失败时查看Output窗口的绑定错误日志。
PresentationTraceSources.TraceLevel=High
诊断绑定问题。