【问题标题】:C# Update elapse time while doing work on the main UI threadC# 在主 UI 线程上工作时更新经过时间
【发布时间】:2016-01-26 17:03:09
【问题描述】:

我有以下代码在后台线程中使用经过时间更新标签。在通过按下按钮模拟的主 UI 线程上做大量工作时,我希望继续这样做。我想让 UI 保持忙碌,这样用户就无法完成其他操作。如何做到这一点?

using System.ComponentModel;
using System.Windows.Forms;
using System.Diagnostics;
using System.Threading;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        private BackgroundWorker _worker;

        Stopwatch _watch = null;

        public Form1()
        {
            InitializeComponent();
            InitWorker();
            _watch = Stopwatch.StartNew();
        }

        private void InitWorker()
        {
            if (_worker != null)
            {
                _worker.Dispose();
            }

            _worker = new BackgroundWorker
            {
                WorkerReportsProgress = true,
                WorkerSupportsCancellation = true
            };
            _worker.DoWork += DoWork;
            _worker.RunWorkerAsync();
        }


        void DoWork(object sender, DoWorkEventArgs e)
        {
            while (_watch != null)
            {
                label1.Invoke((MethodInvoker)delegate
                {
                    label1.Text = _watch.Elapsed.ToString(@"hh\:mm\:ss");
                });

                Thread.Sleep(1000);
            }
        }

        private void button1_Click(object sender, System.EventArgs e)
        {
            for (int i = 0; i < 1000000000; i++)
            {
                double a = 600000000000000.5;
                a = a / 4.54;
            }
        }
    }
}

【问题讨论】:

  • 阻止用户在 WinForms 中执行某些操作的简单解决方案是使用 FormDialog,它将接管应用程序,直到它被隐藏或关闭。在这种情况下,当按下按钮时,只需 someForm.ShowDialog() 插入 someForm.Show() (模态与非模态),一旦 bgw 工作人员完成,只需取消隐藏关闭按钮。
  • SpaceSteak 的想法很可能是您想要的方式。另一种选择是简单地禁用您不希望用户在您工作时使用的任何按钮/控件。
  • SpaceSteak,不确定这是否是解决方案,因为在我的情况下,按下按钮时完成的工作也是使用 GUI 在输出窗口中打印内容。我的应用程序是 2 个树视图,我在它们之间拖放(正在完成的工作并打印到输出窗口)+ 一个带有计时器的标签,显示工作完成时经过的时间。
  • 底线是您不能使用 UI 来执行长时间运行的过程,因为一切都会冻结 - 甚至更新。所以 button1_click 中的代码需要进入异步任务

标签: c# multithreading timer


【解决方案1】:

只要您阻塞 UI 线程,UI 就会被冻结,无法处理任何 Invoke(他们怎么可能?他们将代码编组到繁忙的 UI 线程)。

这个策略不起作用。

如果您想阻止 UI,请不要冻结它。您可能应该禁用您关心的所有输入元素。一个激进的解决方案是在表单的整个客户区域上覆盖一个透明面板。不过,这对用户来说很奇怪。

如果您不知道:您可以使用await Task.Run(...); 在后台线程上轻松运行昂贵的工作。 BackgroundWorker 已过时。

【讨论】:

  • 一个不太激进的解决方案是将控件剪切并粘贴到面板上,然后禁用面板...
  • 是的,好建议。我通常会创建一个中心方法,我可以使用它来禁用和启用所有相关控件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-09-03
  • 1970-01-01
  • 2017-12-14
  • 1970-01-01
  • 1970-01-01
  • 2023-03-12
  • 2013-05-05
相关资源
最近更新 更多