红着眼 2023-11-24 09:25 采纳率: 27.8%
浏览 4
已结题

WPF多线程导致其他UI操作问题。蒙版消息提示。UI线程。

WPF不正确的方式关闭窗体导致自定义带蒙版的MessageBox弹出后,界面无法操作的问题。
这两天在项目中改造了自定义的MessageBox,在MessageBox加入了蒙版,在改造的途中,发现MessageBox弹窗弹出后,整个系统都无法点击了,只能通过任务管理器去关闭窗体了。
刚开始以为MessageBox的蒙版代码有问题,不停的修改,最后还是一模一样的结果。于是试着新建了一个全新的项目,用相同的蒙版代码,发现一切正常。
于是一句一句代码的删除调试我的项目。最终终于找到了问题的所在。

这句“问题”代码就出现在App.xaml代码中,App.xaml逻辑是:系统启动后加载启动动画,然后线程检查数据是否正常,检查完毕后,关闭动画。打开主窗体。
删除如下这句代码,我的蒙版就正常了,弹出来的窗体可以点击了。

请问是什么情况导致的这样的问题呢?
另外我应该怎么正确的关闭splashScreenWd呢?

//在窗体初始化完毕后,关闭加载动画的窗口
splashScreenWd.Dispatcher.Invoke(new System.Windows.Forms.MethodInvoker(delegate { splashScreenWd.Close(); }));

App.xaml代码如下。

Window openWindow = null;
SplashScreenWd splashScreenWd = null;
 
protected override void OnStartup(StartupEventArgs e)
{
    #region 打开启动动画
    Thread thread = new Thread(() =>
    {
        splashScreenWd = new SplashScreenWd("正在初始化系统", new SolidColorBrush(Colors.Gainsboro));
        splashScreenWd.ShowDialog();
    });
    thread.SetApartmentState(ApartmentState.STA);
    thread.Start();
    #endregion
    RefObj refObj = new RefObj();
    Service service = null;
    BackgroundWorker worker = new BackgroundWorker();
    worker.DoWork += (s, ee) =>
    {
        #region 检查系统更新
        SystemMethod systemMethod = new SystemMethod();
        List<string> updateFiles = systemMethod.GetSysUpdateFiles();
        #region 强制更新系统,更新文件丢失则无法使用系统
        if (updateFiles.Count > 0)
        {
            string VersionNo = systemMethod.GetSysVersionNo();
            this.Dispatcher.BeginInvoke((Action)delegate
            {
                if (File.Exists("Startup.exe"))
                {
                    new ShowUpdateInfoWd(null, String.Format("\n检测到新版本:{0}", VersionNo)).ShowDialog();
                    Process.Start("Startup.exe");
                }
                else new ShowMessageWd(null, "\n" + "检测到新版本,但更新文件Startup.exe丢失").ShowDialog();
                Environment.Exit(0);
                return;
            });
        }
        #endregion
        #endregion
        #region 查询该设备是否有效
        refObj = systemMethod.GetDeviceInfo();
        #endregion
    };
    worker.RunWorkerCompleted += (s, ee) =>
    {
        #region 系统检查,系统缓存完毕,打开主窗体
        openWindow = refObj.IsSuccess ?
                     openWindow = new MainWd(service) :
                     openWindow = new ShowMessageWd(refObj.ExecuteNum > 0 ? service : null, refObj.Message);
        openWindow.Show();
        #region 窗体初始化完毕
        openWindow.ContentRendered += (ss, ev) =>
        {
            //在窗体初始化完毕后,关闭加载动画的窗口
            splashScreenWd.Dispatcher.Invoke(new System.Windows.Forms.MethodInvoker(delegate { splashScreenWd.Close(); }));
            IntPtr handle = new WindowInteropHelper(openWindow).Handle;
            SetForegroundWindow(handle);
        };
        #endregion
        #endregion
        worker.Dispose();
    };
    worker.RunWorkerAsync();
}

  • 写回答

2条回答 默认 最新

  • 呈两面包夹芝士 2023-11-24 09:54
    关注

    引自讯飞星火
    这个问题可能是由于在关闭SplashScreenWd窗口时,UI线程被阻塞导致的。你可以尝试使用Dispatcher.InvokeAsync来解决这个问题。将以下代码:

    splashScreenWd.Dispatcher.Invoke(new System.Windows.Forms.MethodInvoker(delegate { splashScreenWd.Close(); }));
    

    替换为:

    splashScreenWd.Dispatcher.InvokeAsync(new Action(() => splashScreenWd.Close()));
    

    这样,关闭窗口的操作将在UI线程中异步执行,不会导致界面无法操作的问题。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 11月24日
  • 已采纳回答 11月24日
  • 创建了问题 11月24日

悬赏问题

  • ¥50 AI大模型精调(百度千帆、飞浆)
  • ¥15 关于#c语言#的问题:我在vscode和codeblocks中编写c语言时出现打不开源文件该怎么办
  • ¥15 非科班怎么跑代码?如何导数据和调参
  • ¥15 福州市的全人群死因监测点死亡原因报表
  • ¥15 Altair EDEM中生成一个颗粒,并且各个方向没有初始速度
  • ¥15 系统2008r2 装机配置推荐一下
  • ¥500 服务器搭建cisco AnyConnect vpn
  • ¥15 悬赏Python-playwright部署在centos7上
  • ¥15 psoc creator软件有没有人能远程安装啊
  • ¥15 快速扫描算法求解Eikonal方程咨询