RunWorkerCompleted在DoWork完成之前更新了UI
本文关键字:更新 UI DoWork RunWorkerCompleted | 更新日期: 2023-09-27 18:25:58
我很想知道为什么RunWorkerCompleted在进度条完成之前更新了UI,textBox1文本为"完成"。为什么会发生这种情况?
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 1; i <= 100; i++)
{
Thread.Sleep(10);
backgroundWorker1.ReportProgress(i);
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
textBox1.Text = "Done";
}
如果我使用
for (int i = 1; i <= 100; i++)
{
Thread.Sleep(20);
backgroundWorker1.ReportProgress(i);
MessageBox.Show(i.ToString());
}
然后它就达到了我所期望的
如果我在下面尝试,文本框会按预期更新,但进度条不会更新
public void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
textBox1.Text = e.ProgressPercentage.ToString();
progressBar1.Refresh();
}
一点滞后是可能的,也是意料之中的。
ReportProgress()
机制可能使用BeginInvoke()
,因此对更新进行排队。这会造成一点延迟,但通常不会引起注意。
ProgressBar有自己的内部更新机制。这似乎有意将反馈延迟几百毫秒。我想是一些用户规模的调整。
Derek Will设计了一个非常简单的解决方案来解决这个问题(本质上是关于ProgressBar控件),在撰写本文时,可以在这里找到:https://derekwill.com/2014/06/24/combating-the-lag-of-the-winforms-progressbar/
诀窍是将ProgressBar的值调整得比必要的值高一点,然后回落到所需的值。这消除了滞后,因为它只在条形图的值增加时发生(必须根据设计进行假设),而不是在条形图值减少时发生。
以下扩展方法将更新ProgressBar的值,不会有任何延迟。所有的功劳都归功于Derek Will的解决方案;我只是稍微简化了代码,并将值限制在控件的范围内,我将在这里发布我的版本,以供后人使用。Increment和PerformStep方法的无滞后版本可以使用相同的模式来定义。
using System;
using System.Windows.Forms;
public static class ProgressBarEM
{
public static void ValueNoLag(this ProgressBar bar, int value)
{
value = Math.Max(bar.Minimum, Math.Min(value, bar.Maximum));
bar.Maximum += 1;
bar.Value = value + 1;
bar.Value = value;
bar.Maximum -= 1;
}
}