首页 > 解决方案 > 使用已用秒表时间更新标签时遇到问题

问题描述

我想每隔一段时间更新一个标签,它需要一个方法来完成。我创建了一个秒表来获取经过的时间,并创建了一个 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);           
        }
    }
}

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

标签: c#winformstimerstopwatch

解决方案


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

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

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

如果要测量方法的执行时间,则必须在单独的线程中运行它,以免阻塞 GUI 线程并获得更准确的结果(因为主线程上的 GUI 处理不会过多地影响执行时间)。


推荐阅读