如何实现在C#中的数据库调用一个进度条和BackgroundWorker的?
我确实有一些方法处理大量数据的处理。 它们是相对长期运行的操作,所以我想实现一个进度条,让用户知道什么是真正发生。
我想用进度栏或状态条的标签,但由于只有一个UI线程,在那里被执行的数据库处理方法的线程,不更新UI控件,使得进度栏或状态条标签是对我没用。
我已经看到了一些例子,但他们处理的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);
}
我在寻找更好的例子。
有些人可能不喜欢它,但是这是我做的:
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;
}
选取框风格需要启用VISUALSTYLES,但它自身的不断滚动,而无需进行更新。 我使用的不报告其进度的数据库操作。
如果你不知道的进展,你不应该滥用进度条假的,而不是仅仅显示了某种类似en.wikipedia.org/wiki/Throbber#Spinning_wheel忙图标的启动任务时,它显示和隐藏它时,它的完了。 这将使一个更“老实” GUI。
当您执行在后台线程操作,并且您想更新UI,你不能打电话或设置从后台线程什么。 在WPF的情况下,你需要Dispatcher.BeginInvoke和WinForms的情况下,你需要调用方法。
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:
// 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);
});
}
对于的WinForms代表可能需要一些铸造或你可能需要一些帮助那里,现在不记得确切的语法。
报告背后与后台工作进展的想法是通过发送“已完成百分比”事件。 你是你自己负责确定莫名其妙“多少”工作已经完成。 很不幸,这往往是最困难的部分。
在你的情况下,大部分工作是数据库相关的。 目前就我所知,没有办法直接从数据库中获取进度信息。 你可以尝试但做的,是动态拆分工作。 例如,如果你需要阅读大量的数据,一个简单的方式来实现,这可能是。
因为它是为一个概念证明我还没有编译这一点。 这就是我已经实现了在过去的数据库访问一个进度条。 这个例子显示了访问使用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);
}
这将Helpfull.Easy落实,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
}