刘荣逵技术博客

Work for a better day

BackgroundWorker 类学习与实践心得


1.问题描述

    今天遇到一个问题,我有一个WinForm的程序,其中有个地方用WebClinet下载一些东西。当我选择保存路径后点确定,这个时候保存路径对话框会被卡住几秒钟后才关闭,之后开始下载流程……

    我期望的是这个路径保存对话框应该是在点击确定后立即关闭,至于要等待一会儿才能下载这个没有关系,但是不能出现保存路径对话框的假死状态。因此我开始寻求问题的解决方法

2.问题解决

    在网上查找了类似的问题,但是始终没有结果。无意中看到了一个叫BackgroundWorker,从名字上听起来似乎就能解决我的问题。于是乎上了MSDN查找这个类的相关信息,MSDN上是这样说的:

BackgroundWorker 类允许您在单独的专用线程上运行操作。耗时的操作(如下载和数据库事务)在长时间运行时可能会导致用户界面 (UI) 似乎处于停止响应状态。如果您需要能进行响应的用户界面,而且面临与这类操作相关的长时间延迟,则可以使用 BackgroundWorker 类方便地解决问题。

若要在后台执行耗时的操作,请创建一个 BackgroundWorker,侦听那些报告操作进度并在操作完成时发出信号的事件。可以通过编程方式创建 BackgroundWorker,也可以将它从“工具箱”的“组件”选项卡中拖到窗体上。如果在 Windows 窗体设计器中创建 BackgroundWorker,则它会出现在组件栏中,而且它的属性会显示在“属性”窗口中。

若要设置后台操作,请为 DoWork 事件添加一个事件处理程序。在此事件处理程序中调用耗时的操作。若要启动该操作,请调用 RunWorkerAsync。若要收到进度更新通知,请对 ProgressChanged 事件进行处理。若要在操作完成时收到通知,请对 RunWorkerCompleted 事件进行处理。

   突然感觉到这个就是我要的。于是分析了他的c#的demo

 

using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;

namespace BackgroundWorkerExample
{
public class FibonacciForm : System.Windows.Forms.Form
{
private int numberToCompute = 0;
private int highestPercentageReached = 0;

private System.Windows.Forms.NumericUpDown numericUpDown1;
private System.Windows.Forms.Button startAsyncButton;
private System.Windows.Forms.Button cancelAsyncButton;
private System.Windows.Forms.ProgressBar progressBar1;
private System.Windows.Forms.Label resultLabel;
private System.ComponentModel.BackgroundWorker backgroundWorker1;

public FibonacciForm()
{
InitializeComponent();

InitializeBackgoundWorker();
}

// Set up the BackgroundWorker object by
// attaching event handlers.
private void InitializeBackgoundWorker()
{
backgroundWorker1.DoWork
+=
new DoWorkEventHandler(backgroundWorker1_DoWork);
backgroundWorker1.RunWorkerCompleted
+=
new RunWorkerCompletedEventHandler(
backgroundWorker1_RunWorkerCompleted);
backgroundWorker1.ProgressChanged
+=
new ProgressChangedEventHandler(
backgroundWorker1_ProgressChanged);
}

private void startAsyncButton_Click(System.Object sender,
System.EventArgs e)
{
// Reset the text in the result label.
resultLabel.Text = String.Empty;

// Disable the UpDown control until
// the asynchronous operation is done.
this.numericUpDown1.Enabled = false;

// Disable the Start button until
// the asynchronous operation is done.
this.startAsyncButton.Enabled = false;

// Enable the Cancel button while
// the asynchronous operation runs.
this.cancelAsyncButton.Enabled = true;

// Get the value from the UpDown control.
numberToCompute = (int)numericUpDown1.Value;

// Reset the variable for percentage tracking.
highestPercentageReached = 0;

// Start the asynchronous operation.
backgroundWorker1.RunWorkerAsync(numberToCompute);
}

private void cancelAsyncButton_Click(System.Object sender,
System.EventArgs e)
{
// Cancel the asynchronous operation.
this.backgroundWorker1.CancelAsync();

// Disable the Cancel button.
cancelAsyncButton.Enabled = false;
}

// This event handler is where the actual,
// potentially time-consuming work is done.
private void backgroundWorker1_DoWork(object sender,
DoWorkEventArgs e)
{
// Get the BackgroundWorker that raised this event.
BackgroundWorker worker = sender as BackgroundWorker;

// Assign the result of the computation
// to the Result property of the DoWorkEventArgs
// object. This is will be available to the
// RunWorkerCompleted eventhandler.
e.Result = ComputeFibonacci((int)e.Argument, worker, e);
}

// This event handler deals with the results of the
// background operation.
private void backgroundWorker1_RunWorkerCompleted(
object sender, RunWorkerCompletedEventArgs e)
{
// First, handle the case where an exception was thrown.
if (e.Error != null)
{
MessageBox.Show(e.Error.Message);
}
else if (e.Cancelled)
{
// Next, handle the case where the user canceled
// the operation.
// Note that due to a race condition in
// the DoWork event handler, the Cancelled
// flag may not have been set, even though
// CancelAsync was called.
resultLabel.Text = "Canceled";
}
else
{
// Finally, handle the case where the operation
// succeeded.
resultLabel.Text = e.Result.ToString();
}

// Enable the UpDown control.
this.numericUpDown1.Enabled = true;

// Enable the Start button.
startAsyncButton.Enabled = true;

// Disable the Cancel button.
cancelAsyncButton.Enabled = false;
}

// This event handler updates the progress bar.
private void backgroundWorker1_ProgressChanged(object sender,
ProgressChangedEventArgs e)
{
this.progressBar1.Value = e.ProgressPercentage;
}

// This is the method that does the actual work. For this
// example, it computes a Fibonacci number and
// reports progress as it does its work.
long ComputeFibonacci(int n, BackgroundWorker worker, DoWorkEventArgs e)
{
// The parameter n must be >= 0 and <= 91.
// Fib(n), with n > 91, overflows a long.
if ((n < 0) || (n > 91))
{
throw new ArgumentException(
"value must be >= 0 and <= 91", "n");
}

long result = 0;

// Abort the operation if the user has canceled.
// Note that a call to CancelAsync may have set
// CancellationPending to true just after the
// last invocation of this method exits, so this
// code will not have the opportunity to set the
// DoWorkEventArgs.Cancel flag to true. This means
// that RunWorkerCompletedEventArgs.Cancelled will
// not be set to true in your RunWorkerCompleted
// event handler. This is a race condition.

if (worker.CancellationPending)
{
e.Cancel
= true;
}
else
{
if (n < 2)
{
result
= 1;
}
else
{
result
= ComputeFibonacci(n - 1, worker, e) +
ComputeFibonacci(n
- 2, worker, e);
}

// Report progress as a percentage of the total task.
int percentComplete =
(
int)((float)n / (float)numberToCompute * 100);
if (percentComplete > highestPercentageReached)
{
highestPercentageReached
= percentComplete;
worker.ReportProgress(percentComplete);
}
}

return result;
}


#region Windows Form Designer generated code

private void InitializeComponent()
{
this.numericUpDown1 = new System.Windows.Forms.NumericUpDown();
this.startAsyncButton = new System.Windows.Forms.Button();
this.cancelAsyncButton = new System.Windows.Forms.Button();
this.resultLabel = new System.Windows.Forms.Label();
this.progressBar1 = new System.Windows.Forms.ProgressBar();
this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
((System.ComponentModel.ISupportInitialize)(
this.numericUpDown1)).BeginInit();
this.SuspendLayout();
//
// numericUpDown1
//
this.numericUpDown1.Location = new System.Drawing.Point(16, 16);
this.numericUpDown1.Maximum = new System.Decimal(new int[] {
91,
0,
0,
0});
this.numericUpDown1.Minimum = new System.Decimal(new int[] {
1,
0,
0,
0});
this.numericUpDown1.Name = "numericUpDown1";
this.numericUpDown1.Size = new System.Drawing.Size(80, 20);
this.numericUpDown1.TabIndex = 0;
this.numericUpDown1.Value = new System.Decimal(new int[] {
1,
0,
0,
0});
//
// startAsyncButton
//
this.startAsyncButton.Location = new System.Drawing.Point(16, 72);
this.startAsyncButton.Name = "startAsyncButton";
this.startAsyncButton.Size = new System.Drawing.Size(120, 23);
this.startAsyncButton.TabIndex = 1;
this.startAsyncButton.Text = "Start Async";
this.startAsyncButton.Click += new System.EventHandler(this.startAsyncButton_Click);
//
// cancelAsyncButton
//
this.cancelAsyncButton.Enabled = false;
this.cancelAsyncButton.Location = new System.Drawing.Point(153, 72);
this.cancelAsyncButton.Name = "cancelAsyncButton";
this.cancelAsyncButton.Size = new System.Drawing.Size(119, 23);
this.cancelAsyncButton.TabIndex = 2;
this.cancelAsyncButton.Text = "Cancel Async";
this.cancelAsyncButton.Click += new System.EventHandler(this.cancelAsyncButton_Click);
//
// resultLabel
//
this.resultLabel.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
this.resultLabel.Location = new System.Drawing.Point(112, 16);
this.resultLabel.Name = "resultLabel";
this.resultLabel.Size = new System.Drawing.Size(160, 23);
this.resultLabel.TabIndex = 3;
this.resultLabel.Text = "(no result)";
this.resultLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// progressBar1
//
this.progressBar1.Location = new System.Drawing.Point(18, 48);
this.progressBar1.Name = "progressBar1";
this.progressBar1.Size = new System.Drawing.Size(256, 8);
this.progressBar1.Step = 2;
this.progressBar1.TabIndex = 4;
//
// backgroundWorker1
//
this.backgroundWorker1.WorkerReportsProgress = true;
this.backgroundWorker1.WorkerSupportsCancellation = true;
//
// FibonacciForm
//
this.ClientSize = new System.Drawing.Size(292, 118);
this.Controls.Add(this.progressBar1);
this.Controls.Add(this.resultLabel);
this.Controls.Add(this.cancelAsyncButton);
this.Controls.Add(this.startAsyncButton);
this.Controls.Add(this.numericUpDown1);
this.Name = "FibonacciForm";
this.Text = "Fibonacci Calculator";
((System.ComponentModel.ISupportInitialize)(
this.numericUpDown1)).EndInit();
this.ResumeLayout(false);

}
#endregion

[STAThread]
static void Main()
{
Application.Run(
new FibonacciForm());
}
}
}

    仔细学习之后终于解决了这个问题!把下载进程放入到backgroundWorker1_DoWork中……

 

 


 

posted on 2008-11-15 22:47  Rock.Liu  阅读(542)  评论(0编辑  收藏  举报

导航