【问题标题】:Having trouble updating label with elapsed stopwatch time使用已用秒表时间更新标签时遇到问题
【发布时间】:2021-11-09 01:36:24
【问题描述】:

我想每隔一段时间更新一个标签,其中包含一个方法完成所花费的时间。我创建了一个秒表来获取经过的时间,并创建了一个 Windows 窗体计时器来通过 Tick 事件用经过的时间更新标签。我整理了一个关于我的问题的简短示例,请参见下文。

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

namespace SOWinFormsTest
{
    public partial class Form1 : Form
    {
        private static Stopwatch watch = new Stopwatch();
        private static System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            timer.Interval = 1000;
            timer.Tick += timer_Tick;
            timer.Start();

            watch.Start();
            SomeMethod();
            watch.Stop();

        }
        private void timer_Tick(Object sender, EventArgs e)
        {
            label1.Text = GetTimeString(watch.Elapsed);
        }

        private string GetTimeString(TimeSpan elapsed)
        {
            string time = string.Empty;
            time = string.Format("{0:00}:{1:00}:{2:00}.{3:000}",
                elapsed.Hours,
                elapsed.Minutes,
                elapsed.Seconds,
                elapsed.Milliseconds);

            return time;
        }

        // Mimicking a method that takes 5 seconds to complete 
        // My actual code could take a lot longer
        private void SomeMethod()
        {
            Thread.Sleep(5000);           
        }
    }
}

当我运行这个程序并单击我的按钮时,标签只更新一次,那是在 SomeMethod() 完成的 5 秒之后。我希望标签随着经过的时间每秒更新一次。有谁知道为什么这不能按预期工作?这是多线程问题吗?我需要BackgroundWorker吗?还是我完全错过了什么?

【问题讨论】:

  • 注意:每次单击按钮时,都会分配多个刻度事件:timer.Tick += timer_Tick; 在构造函数中只执行一次。
  • 当前您的代码正在主线程上运行。在主线程上休眠会阻塞该线程上的其他事情,包括 UI 消息泵。使用后台工作人员执行长时间任务是保持消息泵运行的关键。
  • 在您删除 Button.Cllick 处理程序中的 Tick 事件订阅后(这是悲剧),Task.Run() 你的SomeMethod()。和await它。 -- 不需要string.Format()
  • @LarsTech,已注明,感谢您的反馈!
  • @Jimi 啊哈!那是为我做的!非常感谢!

标签: c# winforms timer stopwatch


【解决方案1】:

您正在 主 GUI 线程上执行您的 SomeMethod。这将停止消息泵送。 .NET WinForms 在隐藏 Windows 内部方面做得并不好,所以这成了一个问题。

简而言之,GUI 线程在“无限循环”中工作并处理来自 Windows 的消息,其中包括任何 GUI 更新消息、定时器消息、用户输入等(消息可能不仅来自来自 Windows,但这与这个问题无关)。

这里提到了这一点,假设您使用的是 .NET Framework 4.8:Timer class

如果你想测量一个方法的执行时间,你必须在单独的线程中运行它,以免阻塞 GUI 线程并获得更准确的结果(因为主线程上的 GUI 处理不会混淆执行时间,因为很多)。

【讨论】:

    猜你喜欢
    • 2019-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多