路由事件的三类传播方式
-
冒泡事件(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
诊断绑定问题。