【问题标题】:What does messageBox.Show() do in order to stop the execution of a UI thread?messageBox.Show() 做了什么来停止 UI 线程的执行?
【发布时间】:2019-08-27 08:42:09
【问题描述】:

在 WPF 应用程序中,我将消息输出到文本框,在这些消息之间,我调用了一个设置仪器的函数。但是,消息都同时出现(在函数调用结束时)。

我真的不知道如何清楚地解释我的问题。我会尽力... 我有一个 WPF 应用程序,它使用串行端口从仪器获取数据。该应用程序包含一些按钮和一个用于输出消息的文本框。按下按钮后,应用程序向仪器发送命令以更改某些参数(通过函数Set_COMM_MODE()),然后返回。更改大约需要 5-10 秒。因此,我所做的是:我在通话前输出了一条“请稍候”消息,在通话返回后输出了一条“完成”消息。 代码中的OuputText()函数只调用了TextBox.AppendText()方法。 我的问题:在调用返回时,所有输出文本都会在文本框中显示出来。我预计会收到 请稍候...,然后 5-10 秒后会收到 “完成” 消息。但这一切都是同时出现的。但是,当我在第一条消息之后(在函数调用之前)放置 MessageBox 时,该消息会出现在文本框输出中(没有被调用的函数)。但是问题是我必须在MessageBox 上按确定才能继续。

Q(1):我怎样才能让后者发生而不必求助于MessageBox
Q(2):MessageBox 做了什么来创建这种行为?

我试过:使用Dispatch.Invoke() 方法在另一个线程上运行OutputText。 这个 (Pause a window like MessageBox.Show()) 和我遇到的问题类似,但似乎没有得到明确的答案,我也没有很好地理解解决方案。

void StartTest_btn_Click(object sender, RoutedEventArgs e)
{
    OutputText("Please Wwait\r\n"); //<---- This should appear at once.

    MessageBox.Show("Please Wwait"); //<--without this, both messages appear at same time after 10s.

    Set_COMM_MODE("02"); //<--- This takes around 5-10s

    OutputText("Done\r\n"); //<--- This should appear 5-10s later
}

我希望立即显示“请稍候”,然后在函数Set_COMM_MODE() 返回后,5-10 秒后显示“完成” 消息。

【问题讨论】:

  • 您可能需要Task
  • 消息框是一个模式对话框,它有自己的消息泵。因此,当消息框在前台时,调用者的消息泵继续工作。这允许 WPF 调度程序处理事件并更新文本框。这就是您在显示消息框时看到更新的原因。如果没有该框,您将阻塞 UI 线程,因此 Dispatcher 无法更新 UI。对于您的问题,解决方案是:不要将 UI 线程用于 UI 之外的任何内容!在工作线程上执行长时间运行的任务。
  • 这是由于调度程序在 Windows 上的工作方式。同样的问题已经在微软的社交论坛中详细解释过:social.msdn.microsoft.com/Forums/vstudio/en-US/…
  • @dymanoid 我只是想在这里给出微软的链接,因为它与这个问题非常相似。我认为消息框在表单应用程序和 wpf 中的后台工作方式相似。我只是想在你用谷歌搜索时声明它是第一个出现的网站。
  • 你可以看看Popup。它更适合您的情况。与 MessageBox 相反,它在等待用户交互时不会阻塞 UI。同时使Set_COMM_MODE异步。

标签: c# .net wpf messagebox


【解决方案1】:

正如我在评论中所写,您应该只将(主)UI 线程用于 UI。 在工作线程上执行任何其他长时间运行的非 UI 操作。

您可能不介意“挂起”用户界面 10 秒,但用户肯定会感到恼火。此外,阻塞 UI 线程会导致 Windows 认为您的应用程序已冻结,因此您将获得漂亮的“未响应”徽章和所有相关内容。这不仅看起来很糟糕,而且会导致各种副作用。

您真的应该环顾四周,看看 .NET 为您提供了哪些解决此类问题的方法。

看,这是你的工作流程:

  1. 打印消息
  2. 开始初始化
  3. ???
  4. 初始化完成 --> 打印“完成”
  5. 开始操作

这是什么?这是一个异步处理。您开始一个动作并异步继续 - 这意味着,只有当动作完成时。

.NET 为此提供了很多工具,例如APM(异步编程模型)。但实现异步处理的最简洁和最强大的方式是 TAP - 基于任务的异步编程模式,更广为人知的是 async/await

看,你的问题可以用 TAP 几行来解决:

async void StartTest_btn_Click(object sender, RoutedEventArgs e)
{
    OutputText("Please Wait\r\n");      

    // Set_COMM_MODE will be executed on a worker thread!
    // The main (UI) thread won't block. It will continue.
    // But the StartTest_btn_Click method itself will pause until the task is finished.
    await Task.Run(() => Set_COMM_MODE("02"));

    // This line will only be executed, after the Set_COMM_MODE call is completed;
    // furthermore, it will be executed on the UI thread again!
    OutputText("Done\r\n");
}

您真的应该更多地了解现代编程技术,TAP 就是其中之一。

【讨论】:

  • 非常感谢。这就是我一直在寻找的。我之前尝试过异步/等待,但不是你展示的方式。我想我不明白它是如何工作的。你是对的,我需要更新自己的现代技术。我的问题是我不是 IT 人,我是电子行业的。所以每次我有这样的项目时,总会有新的东西要学。再次感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-29
  • 2016-06-30
  • 2020-12-28
  • 1970-01-01
相关资源
最近更新 更多