如何获取WPF MessageBox的PresentationSource?避免关联异常
解决方案:WPF MessageBox 抛出 InvalidOperationException 问题
问题根源
关闭控件时触发LostFocus事件,此时控件的Visual已经脱离了PresentationSource(控件正在卸载/已卸载),调用MessageBox.Show时找不到有效的视觉上下文,从而抛出异常。
可行解决方法
1. 直接用用户控件自身作为Visual对象检查
用户控件本身就是Visual的子类,直接用PresentationSource.FromVisual(this)判断是否仍处于有效上下文:
private void UserControl_LostFocus(object sender, RoutedEventArgs e) { // 检查当前控件是否仍关联到PresentationSource if (PresentationSource.FromVisual(this) != null) { MessageBox.Show("提示内容"); } }
2. 结合控件加载状态与Dispatcher延迟执行
通过IsLoaded判断控件是否仍处于加载状态,并用Dispatcher延迟执行,避免在卸载过程中触发:
private void UserControl_LostFocus(object sender, RoutedEventArgs e) { Dispatcher.InvokeAsync(() => { if (this.IsLoaded && PresentationSource.FromVisual(this) != null) { MessageBox.Show("提示内容"); } }, DispatcherPriority.Background); }
3. 标记控件卸载状态
在Unloaded事件中标记控件已卸载,LostFocus事件先判断该状态:
private bool _hasUnloaded = false; private void UserControl_Unloaded(object sender, RoutedEventArgs e) { _hasUnloaded = true; } private void UserControl_LostFocus(object sender, RoutedEventArgs e) { if (!_hasUnloaded && PresentationSource.FromVisual(this) != null) { MessageBox.Show("提示内容"); } }
4. 使用自定义窗口替代MessageBox
自定义窗口可以明确指定Owner为当前窗口,确保有有效的视觉上下文:
private void UserControl_LostFocus(object sender, RoutedEventArgs e) { var parentWindow = Window.GetWindow(this); if (parentWindow != null && PresentationSource.FromVisual(parentWindow) != null) { var dialog = new Window { Title = "提示", Width = 300, Height = 150, WindowStyle = WindowStyle.ToolWindow, Owner = parentWindow, WindowStartupLocation = WindowStartupLocation.CenterOwner }; dialog.Content = new TextBlock { Text = "提示内容", HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center }; dialog.ShowDialog(); } }
内容的提问来源于stack exchange,提问作者VivekDev
相关产品推荐
相关产品推荐

