在我的程序中,C# + winforms。我有进度条和列表视图。
通过一种方法,我执行了一些操作&然后在Listview中更新数据。添加的记录数是我为ProgressBar.value属性设置的值。我想要的是,根据进度条的值,它应该显示它的进度。但是,进度条没有更新。只有在方法执行结束时,进度条才会显示整个进度,即100%
有人能在这方面帮助我吗?
谢谢,阿米特
发布于 2009-07-01 11:56:07
这听起来像是你阻塞了UI线程--也就是说,你还没有释放系统来做任何绘画。
一个老生常谈的答案是将Application.DoEvents()注入到你的代码中--但这是有风险的,并且在可重入性等方面存在问题;而且它只是有点老生常谈。
一个更好的选择可能是在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());
}
}发布于 2009-07-01 12:21:57
真的很抱歉朋友们
实际上,我给ProgressBar.value字段赋值,但没有使用update()方法。我使用了它&我的问题得到了解决。
感谢所有人的回复
发布于 2009-07-01 12:13:19
正如Marc所说,您希望确保您创建了一个新线程来执行您的长时间运行的计算。这样,每当您更改完成百分比时,用户界面线程(必须执行所有屏幕更新的线程)就可以重新绘制进度条。
需要注意的是,只有UI线程才能更新界面。因此,一旦您在单独的线程上运行,就必须经历额外的循环,以确保UI更改在UI线程上得到处理。如果你不确定你在哪个线程上运行,你可以检查InvokeRequired的值(如果你的类是一个System.Windows.Form),看看你是否真的在UI线程中。
若要在UI线程上处理命令,请使用Control.Invoke()函数确保在正在使用的控件的UI线程上处理更新。
在我下面的示例代码中,我创建了一个委托函数类型,并提前声明了被调用的函数……我没有用任何很酷的Lamba3.5函数来做这件事,但我打赌你可以用一个C#表达式来做同样的事情。
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 manual page和MSDN Control.Invoke manual page。
https://stackoverflow.com/questions/1068720
复制相似问题