WPF从子窗口修改主窗口可见性时MainWindow指向异常
WPF中Application.Current.MainWindow的默认赋值逻辑是自动将应用中第一个调用Show()方法展示的窗口设为主窗口,并不会默认绑定你在App.xaml中配置的启动窗口。
你的代码在MainWindow的构造函数中直接执行了LoadWindow.Show(),此时MainWindow自身还未完成初始化、尚未调用Show方法展示,Window2反而成为了第一个被展示的窗口,因此被WPF自动赋值为Application.Current.MainWindow,这就是你获取到错误实例的核心原因。
另外补充一个细节:BackgroundWorker的RunWorkerCompleted回调本身就会自动封送到UI线程执行,你在回调里写的Dispatcher.Invoke是多余的,可以删掉。
你可以根据自己的场景选下面任意一种方式修复:
1. 显式指定主窗口(改动最小)
直接在MainWindow构造函数中手动给Application.Current.MainWindow赋值,跳过WPF的自动识别逻辑,同时建议把Window2的展示逻辑挪到主窗口Loaded事件中,避免主窗口未初始化完成就操作子窗口引发异常:
public static Window2 LoadWindow = new Window2(); public MainWindow() { InitializeComponent(); // 手动指定当前MainWindow实例为应用主窗口 Application.Current.MainWindow = this; // 等主窗口加载完成后再展示子窗口 this.Loaded += (s, e) => { LoadWindow.Show(); }; }
修复后你在worker_Completed中通过Application.Current.MainWindow就能拿到正确的MainWindow实例,使用前建议做类型强转和空判断:
private void worker_Completed(object sender, RunWorkerCompletedEventArgs e) { if (Application.Current.MainWindow is MainWindow mainWin) { mainWin.Visibility = Visibility.Visible; } }
2. 通过Owner属性传递主窗口引用(耦合度更低)
展示Window2时给它的Owner属性赋值为MainWindow实例,后续在Window2中直接通过Owner获取主窗口即可,完全不依赖全局的Application.Current.MainWindow属性,更不容易出问题:
首先修改MainWindow中展示Window2的代码:
public MainWindow() { InitializeComponent(); this.Loaded += (s, e) => { LoadWindow.Owner = this; // 指定所有者为主窗口实例 LoadWindow.Show(); }; }
之后在Window2的完成回调中直接取Owner即可:
private void worker_Completed(object sender, RunWorkerCompletedEventArgs e) { if (this.Owner is MainWindow mainWin) { mainWin.Visibility = Visibility.Visible; } }
- 你当前用
public static Window2 LoadWindow = new Window2();静态持有窗口实例的写法存在隐患:WPF窗口关闭后对应实例会被释放,无法再次调用Show(),且静态引用会导致窗口实例无法被GC回收,容易引发内存泄漏。建议窗口使用时再按需创建,不要长期用静态变量持有。 - 不存在所谓“MainWindow特殊实例名”的概念,MainWindow本质就是和Window2一样的普通窗口类,在类内部访问当前实例用
this关键字即可,类外部只要拿到对应实例的引用就能访问成员,和普通类的访问规则完全一致。
内容的提问来源于stack exchange,提问作者Crestfallen Vulpes

