【问题标题】:How to properly close winforms application from console application如何从控制台应用程序正确关闭 winforms 应用程序
【发布时间】:2016-08-11 08:07:37
【问题描述】:

我想从控制台应用程序中正确关闭 winform 应用程序。所以我尝试这样的事情:

                var cancelSource = new CancellationTokenSource();
                if (runUI)
                {
                    var UI = new FormUI(somedata);

                    //cancel request if form is closing.
                    UI.FormClosing += (sender, args) =>
                    {
                        cancelSource.Cancel();
                    };


                    Task.Factory.StartNew(() =>
                    {
                        //run form from console app.
                          Application.Run(UI);

                    }, cancelSource.Token);
                }

但是当我单击表单上的 X 按钮时,我得到了空引用异常,我不知道它是在哪里抛出的。 那么如何正确地做呢?

更新: 要更清楚。我的控制台应用程序只是读取用户命令,然后执行一些处理数据的方法。如果用户编写命令来显示 UI,我想打开新表单并通过构造函数传递数据。这些数据会发生变化,因此我每 5 秒刷新一次此表单视图。主要目的是使数据处理独立于表格。但是当我关闭该表单时,会引发空引用异常。使用取消只是试图在表单关闭时终止此任务。

在回答之后我做了这样的事情:

            var data = new Data(...)
            var thread = new Thread(() =>
            {
                data.Execute();
            });
            thread.Start();

            if (runUI)
            {
                var UI = new FormUI(data);
                Application.Run(UI);
            }

但是当我关闭表单时它仍然给我错误。

【问题讨论】:

  • 您的 UI 表单正在主线程上创建,但随后您在另一个线程上启动了消息循环。表单及其消息循环的创建应该在同一个线程上。如果您的 UI 表单退出,那么 Application.Run 消息循环也将退出,因此您的线程也将退出。我不明白您为什么需要取消令牌。如果您让我们知道您的主线程在做什么,我们可以为您提供一些关于如何在 ui 表单关闭时退出的指示。
  • 控制台应用程序通过构造函数将数据传递给此表单。表单仅每 5 秒刷新一次数据并显示。
  • 我建议您简单地交换线程。当程序启动时启动你的数据线程。然后在主程序线程上调用 Application.Run(UI)。如果数据线程设置为后台线程,那么它会在 ui 时自动退出。
  • 但我不想在 ui 退出时退出数据线程。 UI 只显示数据。因此,当我退出 UI 时,我希望数据处理仍在进行中。
  • 您必须显示堆栈跟踪以提供发生 NRE 的提示。然而,起点非常糟糕,Task 类使用的线程根本无法显示 UI。它必须是一个合适的线程,必须调用它的 SetApartmentState() 来选择 STA。并且它需要用于显示 all UI,当 SystemEvents 类开始在错误的线程上引发事件时,忽略它会给您带来巨大的麻烦。尝试在非 GUI 程序上附加 UI 永远不会奏效。

标签: c# winforms task-parallel-library


【解决方案1】:

我不确定您究竟想对取消逻辑等做什么。但是如果您使用主线程上的表单来构建您的应用程序,那么这很简单。

尽管表单关闭,_dataThread 仍将继续运行。

_dataThread = new Thread(MyDataProcessingLoop)
_dataThread.Start()
if(runUI){
    _uiForm = new UIForm();
    Application.Run(_uiForm);
}else{
    Application.Run(); //Keep the application running
}

【讨论】:

  • 我更新了帖子以更清晰。我尝试了您的解决方案,但仍然给我空引用异常。
  • 确保 Debug -> Exceptions -> Clr Exceptions -> Throw 被勾选。每当发生异常时,这将停止执行。检查您的堆栈跟踪。问题不是关闭表单,而是表单在退出时所做的事情,计时器在退出后仍试图修改它,应用程序在关闭后试图与之交互。此外,你应该在你的应用程序中实现一些日志记录,这样你就不需要做这个猜测工作了。
  • 你是对的。感谢您让我知道如何检查此异常。问题是我试图在关闭表单后对不再存在的东西进行操作。
  • 没问题,很高兴能帮上忙。
猜你喜欢
  • 1970-01-01
  • 2010-11-24
  • 1970-01-01
  • 2015-10-19
  • 2012-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多