当主UI线程繁忙时显示取消对话框

本文关键字:显示 取消 对话框 UI 线程 当主 | 更新日期: 2023-09-27 18:15:37

我有一个主表单,它包含一个占据整个表单的编辑控件。还有另一个工作线程不断地将日志消息写入此编辑控件。现在我想显示一个对话框,只有一个取消按钮,而主UI的编辑控件显示的东西。问题是,取消对话框是无响应的,而更新发生在它背后,我不能点击取消按钮。知道怎么解决吗。我正在考虑创建另一个UI线程并从中显示取消按钮。还有其他选择吗?

编辑# 1

  1. 我应该澄清,我已经使用一个工作线程来完成工作。
  2. DisplayLogs()在单独的线程中。
  3. DisplayLogs()从其他线程调用。
  4. LogMessage是在主界面中指向UpdateMessage方法的委托。
  5. 使用的控件是一个文本框。我尝试过其他控件,如listview,richtextbox等仍然是相同的结果。

工作线程
void DisplayLogs()
{
    lock (this)
    {
        while (logQueue.Count > 0)
        {
            string logMessagemessage = logQueue.Dequeue();
            LogMessage(string.Concat(logMessagemessage, Environment.NewLine));
        }
    }
}

主UI

public void UpdateMessage( string message)
{
    if (!txtLog.IsHandleCreated)
    {
        return;
    }
    if (txtLog.InvokeRequired)
        txtLog.BeginInvoke( new UpdateLogDelegate( UpdateLog), message);
    else
        txtLog.AppendText(message);
}

当主UI线程繁忙时显示取消对话框

主要的解决方案是将昂贵的代码卸载到后台工作线程上,并让UI线程响应UI操作。然后,你的表单可以简单地显示一个模态对话框或其他东西。

MSDN -如何使用后台Worker

在这种情况下,有必要将大部分工作移到一个新线程中,并清除UI线程以取消消息等

你是在反着做这件事。理论上,主线程应该始终可用以接受用户输入。任何可能长时间阻塞的事情(繁重的计算、数据库访问、网络访问)都应该在后台线程中完成。这个想法是让编辑控件的数据被一个后台线程计算和填充(BackgroundWorker对象在这里工作得很好),这样主线程总是可用的,如果用户单击取消按钮

你的问题是你的UI线程总是很忙。我这么说的前提是logQueue中的项目数量相当大。while循环在队列为空之前不会退出。所以它会不断地向UI线程请求更新。

if (txtLog.InvokeRequired)是一种毫无意义的,因为你总是从一个工作线程调用方法。

因此,由于。net WinForm应用程序只有一个UI,在您的情况下,它太忙而无法处理其他通知,新窗口似乎卡住了(因为油漆消息被困在消息队列中,无法处理,因为它已经被文本框更新消息淹没了)

您可以在循环中放置一个Application.DoEvents,这将给消息循环一些时间来处理挂起的通知。然而,在我看来,这是一种hack,因为UI行为有时是不可预测的。它可能会导致移动对话框时出现口吃,对点击事件的响应延迟等问题。

另一个点,MessageBox.ShowForm.ShowDialog(如果这是您用于取消按钮)是阻塞调用。显示它的线程将挂起,直到您取消对话框。尝试Form.Show,并将父属性设置为主窗体。

另一种选择是添加一个计时器,每Y秒只处理X个通知。这将给UI线程一些喘息的空间来执行其他活动。