Winforms进度条不更新(C#)

在我的程序[C#+ winforms]中。 我有进度条和列表视图。

通过一种方法,我正在执行一些操作,然后更新Listview中的数据。 添加的记录数是我为ProgressBar.value属性设置的值。 我想要的是,根据进度条的价值,它应该显示其进展。 但是进度条没有更新。 仅在方法执行结束时,进度条显示整个进度,即100%

有人可以在这方面帮助我吗?

谢谢,阿米特

听起来你正在阻止UI线程 – 即你还没有释放系统来做任何绘画。

一个hacky的答案是将Application.DoEvents()注入到您的代码中 – 但这是有风险的,并且具有重入等问题; 它只是有点hacky。

更好的选择可能是在BackgroundWorker上进行处理,定期切换到UI线程来更新内容(Control.Invoke) – 但如果要向ListView添加大量项目,这可能会很棘手。

完整示例(尽管您可能希望批量处理UI更新 – 但不是一次一行):

 using System; using System.ComponentModel; using System.Threading; using System.Windows.Forms; class MyForm : Form { BackgroundWorker worker; ListView list; Button btn; ProgressBar bar; public MyForm() { Text = "Loader"; worker = new BackgroundWorker(); worker.WorkerReportsProgress = true; worker.ProgressChanged += worker_ProgressChanged; worker.DoWork += worker_DoWork; worker.RunWorkerCompleted += worker_RunWorkerCompleted; list = new ListView(); list.Dock = DockStyle.Fill; Controls.Add(list); btn = new Button(); btn.Text = "Load"; btn.Dock = DockStyle.Bottom; Controls.Add(btn); btn.Click += btn_Click; bar = new ProgressBar(); bar.Dock = DockStyle.Top; Controls.Add(bar); } void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { btn.Enabled = true; } void btn_Click(object sender, EventArgs e) { worker.RunWorkerAsync(); btn.Enabled = false; } void worker_DoWork(object sender, DoWorkEventArgs e) { for (int i = 0; i < 100; i++) { string newRow = "Row " + i.ToString(); worker.ReportProgress(i, newRow); Thread.Sleep(100); } } void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) { list.Items.Add((string)e.UserState); bar.Value = e.ProgressPercentage; } [STAThread] static void Main() { Application.EnableVisualStyles(); Application.Run(new MyForm()); } } 

对不起朋友,

实际上,我正在为ProgressBar.value字段赋值,但没有使用update()方法。 我用过那个,我的问题得到了解决。

谢谢大家的回复

正如Marc所说,你想确保你创建一个新线程来进行长时间运行的计算。 这样,每当您更改完成百分比时,用户界面线程(必须执行所有屏幕更新的线程)都可以重绘进度条。

重要的是要注意只有 UI线程才能更新界面。 因此,一旦你在一个单独的线程上运行,你必须经过一个额外的箍,以确保在UI线程上处理你的UI更改。 如果您不确定正在运行什么线程,可以检查InvokeRequired的值(如果您的类是System.Windows.Form),以查看您是否在UI线程中是实际的。

要在UI线程上处理命令,请使用Control.Invoke()函数确保在您正在使用的控件的UI线程上处理更新。

在下面的示例代码中,我正在创建一个委托函数类型并提前声明调用的函数….我没有使用任何很酷的C#3.5函数,但我打赌你可以编写一个lamba表达式做同样的事。

  private void bCreateInvoices_Click(object sender, EventArgs e) { BackgroundWorker worker = new BackgroundWorker(); worker.DoWork += new DoWorkEventHandler(CreateInvoices); worker.RunWorkerAsync(this); } // Here is the long running function that needs to update the progress bar public void CreateInvoices(object sernder, DoWorkEventArgs e) { int totalChecked = CountCheckedServiceOrders(); int totalCompleted = 0; foreach (...data to process...) { totalCompleted++; if (InvokeRequired) { Invoke(new Change(OnChange), "status text", totalCompleted, totalChecked); } } } // this code updates the status while a background thread works private delegate void Change(string status, int complete, int total); private void OnChange(string status, int complete, int total) { if (status == null) { progressBar.Visible = false; lStatus.Text = "Task complete"; progressBar.Value = 0; } else { progressBar.Visible = true; progressBar.Minimum = 0; progressBar.Maximum = total; progressBar.Value = complete; lStatus.Text = status; } } 

请查看MSDN Control.InvokeRequired手册页和MSDN Control.Invoke手册页以获取更多信息。

ProgressBar.Value必须介于0到100之间。

我的猜测是你的问题是你正在更新GUI线程上的ListView。 这意味着您需要在更改ProgressBar.Value属性后调用Application.DoEvents()

最好在BackgroundWorker上运行并使用ProgressChanged事件来处理ProgressBar更新。

这是关于同一主题的另一个问题 。