WPF登录加载窗口仅运行一次,线程跨访问异常求助
问题解决:WPF登录Loading窗口二次运行跨线程访问错误
错误原因
首次运行后,proszeCzekaj对象已被关闭且关联的Dispatcher已调用InvokeShutdown,二次运行时仍尝试访问该已失效对象的Dispatcher,导致跨线程访问异常;同时线程资源未正确清理,残留的无效引用引发问题。
修复方案及代码修改
1. ViewModel.cs 修改(核心修复)
将全局的proszeCzekaj改为局部变量,确保每次登录都创建新的Loading窗口实例,同时优化线程和窗口关闭逻辑:
private async void ZalogujExecute(object obj) { try { ProszeCzekaj proszeCzekaj = null; Thread loadingThread = new Thread(() => { proszeCzekaj = new ProszeCzekaj(); // 窗口关闭时终止Dispatcher循环,让线程自然退出 proszeCzekaj.Closed += (sender2, e2) => { if (proszeCzekaj.Dispatcher.Thread.IsAlive) { proszeCzekaj.Dispatcher.BeginInvokeShutdown(DispatcherPriority.Normal); } }; proszeCzekaj.Show(); Dispatcher.Run(); // 启动Dispatcher循环,维持窗口线程 }); loadingThread.SetApartmentState(ApartmentState.STA); loadingThread.Start(); // 等待登录验证完成 var odp = await SprawdzLogowanie(); if (odp == 1) { // 登录成功后的逻辑 } // 安全关闭Loading窗口:检查窗口是否存在且Dispatcher未关闭 if (proszeCzekaj != null && !proszeCzekaj.Dispatcher.HasShutdownStarted) { proszeCzekaj.Dispatcher.Invoke(() => proszeCzekaj.Close()); } } catch (Exception ex) { MessageBox.Show(ex.Message); } } async Task<int> SprawdzLogowanie() { await Task.Run(() => { AplikacjaDbContext db = new AplikacjaDbContext(); // 移除后台线程的MessageBox,避免UI阻塞和跨线程问题 var users = db.UsersTable.ToList(); // 测试可改为日志输出或其他非UI操作 }); return 1; }
2. Loading.xaml.cs 优化(可选)
移除不必要的委托定义,直接调用窗口的Close方法,简化逻辑:
namespace PGSQL.View { public partial class ProszeCzekaj : Window { public ProszeCzekaj() { InitializeComponent(); IntPtr hWnd = new WindowInteropHelper(GetWindow(this)).EnsureHandle(); var attribute = DWMWINDOWATTRIBUTE.DWMWA_WINDOW_CORNER_PREFERENCE; var preference = DWM_WINDOW_CORNER_PREFERENCE.DWMWCP_ROUND; DwmSetWindowAttribute(hWnd, attribute, ref preference, sizeof(uint)); ProszeCzekajViewModel model = new ProszeCzekajViewModel(); this.DataContext = model; } // 移除多余的委托,直接通过Close方法关闭窗口 public enum DWMWINDOWATTRIBUTE { DWMWA_WINDOW_CORNER_PREFERENCE = 33 } public enum DWM_WINDOW_CORNER_PREFERENCE { DWMWCP_DEFAULT = 0, DWMWCP_DONOTROUND = 1, DWMWCP_ROUND = 2, DWMWCP_ROUNDSMALL = 3 } [DllImport("dwmapi.dll", CharSet = CharSet.Unicode, PreserveSig = false)] internal static extern void DwmSetWindowAttribute(IntPtr hwnd, DWMWINDOWATTRIBUTE attribute, ref DWM_WINDOW_CORNER_PREFERENCE pvAttribute, uint cbAttribute); } }
关键修复点说明
- 局部变量替代全局引用:每次登录创建新的Loading窗口,避免复用已释放的对象
- Dispatcher安全管理:窗口关闭时调用
BeginInvokeShutdown让线程自然退出,而非强制终止 - 跨线程操作校验:关闭窗口前检查Dispatcher状态,确保操作在窗口所属线程执行
- 后台线程UI操作移除:移除
SprawdzLogowanie中的MessageBox,后台线程禁止直接操作UI控件
内容的提问来源于stack exchange,提问作者McStar
相关产品推荐
相关产品推荐

