gpt4 book ai didi

c# - RunWorkerCompleted 没有在主 UI 线程中执行?

转载 作者:行者123 更新时间:2023-11-30 21:18:58 25 4
gpt4 key购买 nike

RunWorkerCompleted 事件中重新抛出异常时,我遇到了 BackgroundWorker 或 .NET 框架的奇怪行为。

后台线程中发生的异常被传递给RunWorkerCompleted。我在那里做了一个 object temp = e.Result 来重新抛出异常。由于这应该发生在主 UI 线程中,我希望异常传播到 Application.Run(...),我用 try-catch block 将其包围。

在 Visual Studio 中运行应用程序时,这工作正常。但是,当我在 Visual Studio 外部执行 exe 文件时,异常未得到处理并导致应用程序崩溃。

会不会是 RunWorkerCompleted 事件没有在主 UI 线程中执行?

这些帖子不是重复的,而是确认我的情况很奇怪:

这是一个重现错误的极其简化的代码示例:创建一个 WinForms 项目并添加:

[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);

try
{
Form form = new Form();

form.Load += delegate
{
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += (sender, e) =>
{
// do nothing
};
bw.RunWorkerCompleted += (sender, e) =>
{
throw new Exception("Booo!");
};
bw.RunWorkerAsync();
};

Application.Run(form);
}
catch (Exception ex)
{
while (ex is TargetInvocationException && ex.InnerException != null)
ex = ex.InnerException;

MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}

然后尝试:

  1. 在 Visual Studio 中运行它。在应用程序退出之前,您会收到一个友好的消息框。
  2. 在 Visual Studio 之外运行编译后的可执行文件。您将收到一条 .NET 框架“未处理的异常”消息。

有趣的是,如果我在 2 中点击“继续”,应用程序会继续存在,显示表单并接受用户输入。这一定意味着崩溃的不是主 UI 线程,而是后台线程。主线程仍然存在。

(为什么我要做这些事情?我显示一个闪屏,虽然一些应用程序启动工作是在后台完成的,但闪屏通过标签和进度条显示进度。所以我有创建并显示启动画面,然后获取主 UI 线程以启动 BackgroundWorker。在原始代码中,它向主线程报告进度,主线程更新启动画面。如果在启动期间发生异常, 我想捕获它。在某些情况下,它们是具有特定含义的“业务异常”,例如“您无权使用此应用程序”。在这些情况下,我会在让应用程序死掉之前显示一个友好的消息框。此外,我还有一个 finally block 来清理资源。我不确定 .NET 框架“未处理的异常”对话框是否在终止应用程序之前执行了 finally block 。)

最佳答案

在 Application.Run() 中的消息循环代码周围有一个 try/catch block ,用于捕获事件处理程序引发的未处理异常。 catch 子句引发 Application.ThreadException 事件。该事件有一个默认处理程序,它显示一个 ThreadExceptionDialog。为用户提供忽略错误或中止程序的选项。

当您使用调试器运行程序时,此 catch 子句将被禁用。这使您可以轻松调试异常。禁用它后,CLR 将在您的 Main() 方法中找到 catch 子句。要禁用此行为,请将这行代码添加到 Main() 方法的顶部:

  Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);

它现在的行为方式与在调试器中的行为方式相同。此处更好的捕鼠器是为 AppDomain.CurrentDomain.UnhandledException 实现事件处理程序。这会捕获所有未处理的异常,包括在工作线程中引发的异常。并允许您调试未处理的异常,调试器在 throw 语句处停止。

关于c# - RunWorkerCompleted 没有在主 UI 线程中执行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3997856/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com