无法使用经过的秒表时间更新标签
Having trouble updating label with elapsed stopwatch time
我想每隔一段时间就用方法完成所用的时间来更新标签。我创建了一个秒表来获取经过的时间,并创建了一个 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 吗?还是我完全漏掉了一些东西?
您正在 主 GUI 线程 上执行 SomeMethod
。这将停止消息泵送。 .NET WinForms 没有很好地隐藏 Windows 内部结构,因此这成为一个问题。
简而言之,GUI 线程在“无限循环”中工作并处理来自 Windows 的消息,其中包括任何 GUI 更新消息、计时器消息、用户输入等(消息可能不仅来自Windows,但这与此问题无关)。
此处提到了这一点,假设您使用的是 .NET Framework 4.8:Timer class。
如果您想测量一个方法的执行时间,您必须 运行 它在单独的线程中,以免阻塞 GUI 线程并获得更准确的结果(因为主线程上的 GUI 处理不会把执行时间搞得一团糟)。
我想每隔一段时间就用方法完成所用的时间来更新标签。我创建了一个秒表来获取经过的时间,并创建了一个 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 吗?还是我完全漏掉了一些东西?
您正在 主 GUI 线程 上执行 SomeMethod
。这将停止消息泵送。 .NET WinForms 没有很好地隐藏 Windows 内部结构,因此这成为一个问题。
简而言之,GUI 线程在“无限循环”中工作并处理来自 Windows 的消息,其中包括任何 GUI 更新消息、计时器消息、用户输入等(消息可能不仅来自Windows,但这与此问题无关)。
此处提到了这一点,假设您使用的是 .NET Framework 4.8:Timer class。
如果您想测量一个方法的执行时间,您必须 运行 它在单独的线程中,以免阻塞 GUI 线程并获得更准确的结果(因为主线程上的 GUI 处理不会把执行时间搞得一团糟)。