You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 00:25:57