如何在 C# 中实现进度条?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1259949/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I implement a progress bar in C#?
提问by
How do I implement a progress bar and backgroundworker for database calls in C#?
如何在 C# 中为数据库调用实现进度条和后台工作器?
I do have some methods that deal with large amounts of data. They are relatively long running operations, so I want to implement a progress bar to let the user know that something is actually happening.
我确实有一些处理大量数据的方法。它们是运行时间相对较长的操作,所以我想实现一个进度条,让用户知道某些事情正在实际发生。
I thought of using progress bar or status strip label, but since there is a single UI thread, the thread where the database-dealing methods are executed, UI controls are not updated, making the progress bar or status strip label are useless to me.
我想过使用进度条或状态条标签,但由于只有一个 UI 线程,即执行数据库处理方法的线程,UI 控件没有更新,因此进度条或状态条标签对我来说毫无用处。
I've already seen some examples, but they deal with for-loops, ex:
我已经看过一些例子,但它们处理 for 循环,例如:
for(int i = 0; i < count; i++)
{
System.Threading.Thread.Sleep(70);
// ... do analysis ...
bgWorker.ReportProgress((100 * i) / count);
}
private void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar.Value = Math.Min(e.ProgressPercentage, 100);
}
I'm looking for better examples.
我正在寻找更好的例子。
采纳答案by Kyle Gagnet
Some people may not like it, but this is what I do:
有些人可能不喜欢它,但这就是我所做的:
private void StartBackgroundWork() {
if (Application.RenderWithVisualStyles)
progressBar.Style = ProgressBarStyle.Marquee;
else {
progressBar.Style = ProgressBarStyle.Continuous;
progressBar.Maximum = 100;
progressBar.Value = 0;
timer.Enabled = true;
}
backgroundWorker.RunWorkerAsync();
}
private void timer_Tick(object sender, EventArgs e) {
if (progressBar.Value < progressBar.Maximum)
progressBar.Increment(5);
else
progressBar.Value = progressBar.Minimum;
}
The Marquee style requires VisualStyles to be enabled, but it continuously scrolls on its own without needing to be updated. I use that for database operations that don't report their progress.
Marquee 样式需要启用 VisualStyles,但它会自行连续滚动而无需更新。我将它用于不报告进度的数据库操作。
回答by Akash Kava
When you perform operations on Background thread and you want to update UI, you can not call or set anything from background thread. In case of WPF you need Dispatcher.BeginInvoke and in case of WinForms you need Invoke method.
当您在后台线程上执行操作并想要更新 UI 时,您不能从后台线程调用或设置任何内容。在 WPF 的情况下,您需要 Dispatcher.BeginInvoke,在 WinForms 的情况下,您需要 Invoke 方法。
WPF:
WPF:
// assuming "this" is the window containing your progress bar..
// following code runs in background worker thread...
for(int i=0;i<count;i++)
{
DoSomething();
this.Dispatcher.BeginInvoke((Action)delegate(){
this.progressBar.Value = (int)((100*i)/count);
});
}
WinForms:
WinForms:
// assuming "this" is the window containing your progress bar..
// following code runs in background worker thread...
for(int i=0;i<count;i++)
{
DoSomething();
this.Invoke(delegate(){
this.progressBar.Value = (int)((100*i)/count);
});
}
for WinForms delegate may require some casting or you may need little help there, dont remember the exact syntax now.
对于 WinForms 委托,可能需要进行一些转换,或者您可能几乎不需要帮助,现在不记得确切的语法。
回答by jeroenh
The idea behind reporting progress with the background worker is through sending a 'percent completed' event. You are yourself responsible for determining somehow 'how much' work has been completed. Unfortunately this is often the most difficult part.
向后台工作人员报告进度背后的想法是通过发送“完成百分比”事件。您自己负责以某种方式确定已完成“多少”工作。不幸的是,这通常是最困难的部分。
In your case, the bulk of the work is database-related. There is to my knowledge no way to get progress information from the DB directly. What you can try to do however, is split up the work dynamically. E.g., if you need to read a lot of data, a naive way to implement this could be.
在您的情况下,大部分工作与数据库相关。据我所知,无法直接从数据库获取进度信息。但是,您可以尝试做的是动态拆分工作。例如,如果您需要读取大量数据,那么实现这一点可能是一种天真的方法。
- Determine how many rows are to be retrieved (SELECT COUNT(*) FROM ...)
Divide the actual reading in smaller chunks, reporting progress every time one chunk is completed:
for (int i = 0; i < count; i++) { bgWorker.ReportProgress((100 * i) / count); // ... (read data for step i) }
- 确定要检索的行数 (SELECT COUNT(*) FROM ...)
将实际阅读分成更小的块,每完成一个块就报告进度:
for (int i = 0; i < count; i++) { bgWorker.ReportProgress((100 * i) / count); // ... (read data for step i) }
回答by user282727
If you can't know the progress you should not fake it by abusing a progress bar, instead just display some sort of busy icon like en.wikipedia.org/wiki/Throbber#Spinning_wheel Show it when starting the task and hide it when it's finished. That would make for a more "honest" GUI.
如果你不知道进度,你不应该通过滥用进度条来伪造它,而只是显示某种忙碌的图标,比如 en.wikipedia.org/wiki/Throbber#Spinning_wheel 在开始任务时显示它并在它完成时隐藏它完成的。这将形成一个更“诚实”的 GUI。
回答by galford13x
I have not compiled this as it is meant for a proof of concept. This is how I have implemented a Progress bar for database access in the past. This example shows access to a SQLite database using the System.Data.SQLite module
我没有编译这个,因为它是为了概念证明。这就是我过去为数据库访问实现进度条的方式。此示例显示使用 System.Data.SQLite 模块访问 SQLite 数据库
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
// Get the BackgroundWorker that raised this event.
BackgroundWorker worker = sender as BackgroundWorker;
using(SQLiteConnection cnn = new SQLiteConnection("Data Source=MyDatabase.db"))
{
cnn.Open();
int TotalQuerySize = GetQueryCount("Query", cnn); // This needs to be implemented and is not shown in example
using (SQLiteCommand cmd = cnn.CreateCommand())
{
cmd.CommandText = "Query is here";
using(SQLiteDataReader reader = cmd.ExecuteReader())
{
int i = 0;
while(reader.Read())
{
// Access the database data using the reader[]. Each .Read() provides the next Row
if(worker.WorkerReportsProgress) worker.ReportProgress(++i * 100/ TotalQuerySize);
}
}
}
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.progressBar1.Value = e.ProgressPercentage;
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Notify someone that the database access is finished. Do stuff to clean up if needed
// This could be a good time to hide, clear or do somthign to the progress bar
}
public void AcessMySQLiteDatabase()
{
BackgroundWorker backgroundWorker1 = new BackgroundWorker();
backgroundWorker1.DoWork +=
new DoWorkEventHandler(backgroundWorker1_DoWork);
backgroundWorker1.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(
backgroundWorker1_RunWorkerCompleted);
backgroundWorker1.ProgressChanged +=
new ProgressChangedEventHandler(
backgroundWorker1_ProgressChanged);
}
回答by Gayan Chinthaka Dharmarathna
This will Helpfull.Easy to implement,100% tested.
这将很有帮助。易于实施,100% 测试。
for(int i=1;i<linecount;i++)
{
progressBar1.Value = i * progressBar1.Maximum / linecount; //show process bar counts
LabelTotal.Text = i.ToString() + " of " + linecount; //show number of count in lable
int presentage = (i * 100) / linecount;
LabelPresentage.Text = presentage.ToString() + " %"; //show precentage in lable
Application.DoEvents(); keep form active in every loop
}