为何Application.DispatcherUnhandledException提前捕获FindResource异常?
为什么WPF中FindResource抛出的异常会触发DispatcherUnhandledException而非被catch捕获?
问题场景
以下代码中,MyStyle是不存在的资源:
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); Application.Current.DispatcherUnhandledException += (sender, args) => { // 标记异常为已处理 args.Handled = true; MessageBox.Show("D"); }; try { Style style = FindResource("MyStyle") as Style; // 预期抛出ResourceReferenceKeyNotFoundException MessageBox.Show("A"); } catch (ResourceReferenceKeyNotFoundException exception) { MessageBox.Show("B"); } MessageBox.Show("C"); } }
预期结果:弹出B → C
实际结果:弹出D → A → C
而手动抛出异常的代码:
try { throw new ResourceReferenceKeyNotFoundException(); MessageBox.Show("A"); } catch (ResourceReferenceKeyNotFoundException exception) { MessageBox.Show("B"); }
则符合预期弹出B → C。
原因分析
核心差异在于异常的抛出路径不同:
- 手动抛出异常:异常直接在当前调用栈的
try块内抛出,属于普通的CLR异常传递逻辑,会被上层的catch块直接捕获,不会经过WPF的Dispatcher异常处理管道。 - FindResource抛出的异常:WPF的
FindResource方法内部在找不到目标资源时,抛出的ResourceReferenceKeyNotFoundException会先进入WPF的Dispatcher异常处理流程——也就是触发Application.Current.DispatcherUnhandledException事件。
你在事件处理中设置了args.Handled = true,这会告诉WPF:该异常已经被处理完毕,不需要再继续向调用栈传递(包括不会被try/catch捕获)。因此catch块不会执行,代码会继续执行MessageBox.Show("A"),最后执行MessageBox.Show("C")。
如果移除args.Handled = true的设置,DispatcherUnhandledException触发后,异常会继续传递给try/catch块,此时就会弹出D → B → C。
内容的提问来源于stack exchange,提问作者Renegade Nemo
相关产品推荐
相关产品推荐

