翻译:

原文:

Using the BackgroundWorker Component in .NET 2 applications

- 在 .NET 2.0 中使用 BackgroundWorker 组件

本周热门

其它收藏服务:

Yahoo书签 QQ书签 百度搜藏 Del.icio.us Google书签 和讯网摘 天极网摘 添加到饭否 收客网

欢迎参加奥运翻译大赛


金牌译作 在 .NET 2.0 中使用 BackgroundWorker 组件

2193个读者 翻译: lilyonwin...  08/03/2007 原文 引用 双语对照及眉批

在.NET 2.0应用程序中使用BackgroundWorker组件

年7月3日

BackgroundWorker可以让窗体异步地完成一个操作。在我们需要执行诸如『数据库事务』或者『图片下载』之类的操作时,这个功能非常有 用。此时,我们的可以让用户界面停止响应(或者隐藏起来直到操作结束)。在这篇文章中,我会一步一步教会你如何在.NET 2.0程序中使用BackgroundWorker组件以便处理较耗时的操作。示例程序使用C#编写。

与往常一样,我们创建一个测试工程,取名为"TestBGW",使之只包含一个窗体("FormBGW"):

Image1.jpg

图1.

我们将使用BackgroundWorker完成一些数据库的事务操作(比如,获取一些DataTable)。首先拖一个BackgroundWorker组件到我们窗体上。
Image2.jpg
图2.

我们将用DataTable来设置DataGridView1的DataSource属性。我们还应该刷新我们的用户界面,并告诉用户:所有的操作已经全部“OK”,他/她不用再操心啦。因此,我们还要需要一个StatusStrip和一个Timer.

Image3.jpg
图3.

为了让用户看到我们的处理过程正在运行之中,我们将用到toolStripProgressBar1:
Image4.jpg
图4.

用toolStripStatusLabel1和toolStripStatusLabelTime是来向用户显示处理过程的状态和已经花费的时间。

我们窗体看上去是这样子的:

Image5.jpg
图5.

为了模拟数据库的事务操作,我们将用到 GetData.dll(当然你也可以连接到一个真实的数据库;这个模拟的目的只是为了测试而已)。出于这个目的,我们把GetData.dll添加到引用中,然后写因getDataTable方法:

private DataTable getDataTable(int Rows)

{

    GetData.GetDataHelp getData = new GetData.GetDataHelp();

    return (getData.getDataSetCities(Rows).Tables[0]);

}


我们调用RunWokerAsync方法开始我们的异步操作:


private void FormBGW_Activated(object sender, EventArgs e)

{

    backgroundWorker1.RunWorkerAsync();

}


BackGroundWorker组件有三个事件:

Image6.jpg

图6.


DoWork事件发生在RunWokerAsync方法被调用时。在这个事件的处理函数中,我们“完成”那些的耗时的工作(我们载入至少100000行数据以便使我们的处理过程变得“耗时”),并通知用户载入工作正在进行中,最后将我们的DataTable置为我们的异步操作的结果。


private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)

{

    DataTable dt;

    toolStripStatusLabel1.Text = "Loading ... " + "Thanks for your patience";

    dt = getDataTable(1000000);

    e.Result = dt;

}


就我们面对的情况而言(我是指真实的情况,即从数据库获得一些DataTable的情况),我们没办法“插入”处理过程以“追踪”已获取的数据行数量(一行接一行)。当然,我们同样也没有办法知道,根据我们的请求最终可以从数据库获得多少数据行。所以呢,我们不会用DoWorkEventArgs(译注:应为BackgroudWorker的笔误)的ReportProgress 方法来触发ProgressChanged事件。我们将用Timer1,向用户显示处理过程正在进行中(我们将把 toolStripProgressBar1“增加”到最大程度,然后再从最短长度继续开始;就是说,我们会制造一些循环)。因此我们给 timer1_Tick加上下面的代码:

if (toolStripProgressBar1.Value == toolStripProgressBar1.Maximum)

{

    toolStripProgressBar1.Value = 0;

}


为了让用户知道加载已经花费了多长时间,我们还得给这个方法加上一点代码,比如这个样子:

string sTime ="  ..." + ts.Minutes.ToString("00") +

   ":" + ts.Seconds.ToString("00") +

   ":" + ts.Milliseconds.ToString("000");

toolStripStatusLabelTime.Text = sTime;


其中ts指现在的时间(参见下面完整的代码)。

顺便说一句,如果仅仅为了测试ReportProgress如何工作,你可以给backgroundWorker1_DoWork方法加上下面的代码:

//-------to try percentage ...

int iMax = 100000;

for(int i = 0; i < iMax; i++)

{

    backgroundWorker1.ReportProgress((i * 100) / (iMax - 1));

}


然后把这些代码加入到backgroundWorker1_ProgressChanged :

privatevoid backgroundWorker1_ProgressChanged(object sender,ProgressChangedEventArgs e)

{

    //-------to try percentage ...

    toolStripProgressBar1.Value = e.ProgressPercentage;

    toolStripStatusLabel1.Text = "Loading ... " +

        e.ProgressPercentage.ToString() + "%";

    //-------------------------

}


RunWorkerCompleted事件发生在后台操作完成的时候。此时我们将“关闭”所有的关于加载的提示信息,并且把通过使用事件的参数RunWorkerComletedEventArgs,把dataGridViewCites绑定到dataTable:

dataGridViewCities.DataSource = e.Result;

FormBGW.cs的全部代码如下:

using System; using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

 

namespace TestBGW

{

    public partial class FormBGW : Form

    {

        public FormBGW()

        {

            InitializeComponent();

            ////to try percentage ...

            //backgroundWorker1.WorkerReportsProgress = true;

        }

        #region "forClass"

        DateTime startDate = DateTime.Now;

        #endregion

 

        private void FormBGW_Activated(object sender, EventArgs e)

        {

            backgroundWorker1.RunWorkerAsync();

            timer1.Start();

        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)

        {

            DataTable dt;

            toolStripStatusLabel1.Text = "Loading ... " +

                "Thanks for your patience";

            dt = getDataTable(1000000);

            ////-------to try percentage ...

            //int iMax = 100000;

            //for (int i = 0; i < iMax; i++)

            //{

            //    backgroundWorker1.ReportProgress

            //        ((i * 100) / (iMax - 1));

            //}

            ////-------------------------

            e.Result = dt;

            toolStripStatusLabel1.Text = "Please, wait ...";

        }

 

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)

        {

            ////-------to try percentage ...

            //toolStripProgressBar1.Value = e.ProgressPercentage;

            //toolStripStatusLabel1.Text = "Loading ... " +

            //    e.ProgressPercentage.ToString() + "%"$$

            ////-------------------------

        }

 

        private void backgroundWorker1_RunWorkerCompleted(object sender,RunWorkerCompletedEventArgs e)

        {

            toolStripProgressBar1.Value = 100;

            dataGridViewCities.DataSource = e.Result;

            toolStripStatusLabel1.Text = "";

            toolStripProgressBar1.Value = 0;

            timer1.Stop();

            toolStripStatusLabelTime.Text = "";

        }

 

        private DataTable getDataTable(int Rows)

        {

            GetData.GetDataHelp getData = new GetData.GetDataHelp();

            return (getData.getDataSetCities(Rows).Tables[0]);

        }

 

        private void timer1_Tick(object sender, EventArgs e)

        {

            TimeSpan ts = DateTime.Now.Subtract(startDate);

            string sTime ="  ..." + ts.Minutes.ToString("00") +

               ":" + ts.Seconds.ToString("00") +

               ":" + ts.Milliseconds.ToString("000");

            toolStripStatusLabelTime.Text = sTime;

            if (toolStripProgressBar1.Value ==

                toolStripProgressBar1.Maximum)

            {

                toolStripProgressBar1.Value = 0;

            }

            toolStripProgressBar1.PerformStep();

        }

    }

}


现在,如果我们运行我们的工程,我们会看到:


Image7.jpg

图7.


加载结束之后:


Image8.jpg

图8.


结论


我希望这篇文中可以帮助你在你的.NET 2.0程序中使用BakcgroundWorker组件以便执行一些耗时的操作。


祝好运与编程同在!


--------------

译者的话,这是我在译言翻译的第一篇。从我的角度讲,我是不赞同一个看不懂这篇文章原文的人做程序员的。不过我天生不爱放弃,既然接下了翻译任务,就完成了它吧。

作者超喜欢用we/our,我酌情删去了一些,不过还是有太多的“我们”。
继续阅读
  • .NET牛人应该知道些什么

    本文将告诉你一个.NET牛人应该掌握哪些知识,希望对那些打算去知名软件公司参加面试的朋友有所帮助。

  • 微软的.NET源代码:可远观而不可亵玩也

    微软 允许其开发者查看.Net的源代码了。 通过独立的安装,开发者可以借助文本查看器查看.NET的源代码,但是无法编辑源代码。 .Net 源码的公布主要是给开发者一个了解代码运行机制的机会,以及.N...

  • 软件工程师必须知道的10个概念|读写网

      随着技术的发展,开发一个项目再也不需要像一个村落那么多的人了。有些程序员发现他们可以独立开发一个系统。本文所述的10个技术就能帮助你实现这一点。

  • 微软开放.NET源代码

    微软今天早上宣布.NET 框架库源码将向全世界开放,以允许广大的.NET 框架开发者察看其核心代码,从而有助于他们开发自己的软件。  这很难说微软这一举动的动机是什么,或许是在开发者团队当中,.NE...

  • 百年语言

    百年语言 Paul Graham  2003年4月 (本文出自2003年Python大会上的一篇主题讲话)   很难预测人们的生活在一百年后会是什么样子,我们只能给很少的事物一个确切的预测。我们知道...

  • 创业阶段软件公司的8条建议

    *要有程序代码 - 工作的代码是公司业务的起点。 *要有(软件)工程背景的人做合伙人 - 一个既有工程背景又投入和开创公司业务的人。 *聘用A+级的热衷于编写程序的工程师 - 聘用那些知道他们在“作...

  • 实例分析: 使用 C 扩展 Python

    实例分析: 使用 C 扩展 Python

  • Monad 速成教程1(介绍)

    关于 Monad 的一篇教程

标签:

内容有问题?请与我们联络。

译作评分

  • Currently 5.00/5
  • 1
  • 2
  • 3
  • 4
  • 5
 5.0  |  3 个评分

1条评论    0眉批

  • 1.

    Shiny 童生 | Blog

    不错.我支持.我也喜欢编程,非常喜欢看国外那些讲述编程的blog.有我能翻译的我也翻译过来:)

    10/11/2007

添加评论

欢迎访问译言网。在这里,您可以。。。

阅读
发现
翻译