在 WinForm 的开发过程中, 难免会有大量的操作耗时比较严重, 这时界面会卡死, 无法拖动, 用户体验不佳。这种情况下, BackgroundWorker 是最佳选择, 它提供了异步操作, 而且可以提供进度报告, 还可以取消操作。
不说废话了, 步入正轨。咱们做一个累加的程序:
1. 创建一个 Windows 应用程序;
2. 如下图, 创建好窗体上的相关控件, 并拖入 backgroundworker 控件;
3. 在 backgroundworker1 上右键, 看其属性中的 3 个事件, 分别双击:
4. 下面就直接贴代码了, 注释非常清晰, 相信你能看懂。
先是窗体的 Form1.cs 代码:
using System;
using System.ComponentModel;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
namespace WindowsFormsApp3
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
//允许 backgroundWorker 报告进度
this.backgroundWorker1.WorkerReportsProgress = true;
//backgroundWorker 支持取消异步操作
this.backgroundWorker1.WorkerSupportsCancellation = true;
//是否捕获对错误线程的调用。在 DoWork 中出现对控件的使用时必须配合这一句。
Control.CheckForIllegalCrossThreadCalls = false;
}
//在另一个线程上运行的事件处理程序
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
//下面的语句(在注释 CheckForIllegalCrossThreadCalls = false 之后)会提示有异常:
//System.InvalidOperationException:“线程间操作无效: 从不是创建控件“txtResult”的线程访问它。”
this.txtResult.Width = 101;
int i = 1;
int total = 0;
for (; i <= this.nudLastNum.Value; i++)
{
//如果应用程序已请求取消后台操作
if (worker.CancellationPending == true)
{
//取消事件
e.Cancel = true;
break;
}
total += i;
Thread.Sleep(40);
worker.ReportProgress( Convert.ToInt32( (i*100)/this.nudLastNum.Value ) );
}
e.Result = total;
}
//进度发生变化时事件
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
//修改进度条的值为 backgroundWorker1 的异步任务进度百分比
this.progressBar1.Value = e.ProgressPercentage;
}
//当辅助线程完成时发生(无论取消、异常、完成)
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
string baseInfo = string.Empty;
if (e.Cancelled == true)
{
baseInfo = "用户已取消!";
}
else if (e.Error != null)
{
baseInfo = "Error: " + e.Error.Message;
}
else
{
baseInfo = "顺利完成!";
//只有顺利完成,才能用 e.Result 的结果。否则只能想其它办法
this.txtResult.Text = e.Result.ToString();
}
this.lblExecInfo.Text = baseInfo;
SetBtnEnabled(false);
}
//开始按钮
private void btnStart_Click(object sender, EventArgs e)
{
//如果 backgroundWorker1 没有运行异步操作
if (backgroundWorker1.IsBusy != true)
{
SetBtnEnabled(true);
this.txtResult.Text = "";
//开始执行后台操作
backgroundWorker1.RunWorkerAsync();
}
}
//取消按钮
private void btnCancel_Click(object sender, EventArgs e)
{
//如果支持异步取消操作
if (backgroundWorker1.WorkerSupportsCancellation == true)
{
backgroundWorker1.CancelAsync();
SetBtnEnabled(false);
}
}
//设置按钮的启用禁用状态
private void SetBtnEnabled(bool start)
{
this.btnCancel.Enabled = start;
this.btnStart.Enabled = !start;
}
}
}
设计器 Form1.Designer.cs 代码如下:
namespace WindowsFormsApp3
{
partial class Form1
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows 窗体设计器生成的代码
/// <summary>
/// 设计器支持所需的方法 - 不要修改
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
this.nudLastNum = new System.Windows.Forms.NumericUpDown();
this.label2 = new System.Windows.Forms.Label();
this.txtResult = new System.Windows.Forms.TextBox();
this.btnStart = new System.Windows.Forms.Button();
this.btnCancel = new System.Windows.Forms.Button();
this.progressBar1 = new System.Windows.Forms.ProgressBar();
this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
this.lblExecInfo = new System.Windows.Forms.Label();
((System.ComponentModel.ISupportInitialize)(this.nudLastNum)).BeginInit();
this.SuspendLayout();
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(13, 13);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(47, 12);
this.label1.TabIndex = 0;
this.label1.Text = "从1加到";
//
// nudLastNum
//
this.nudLastNum.Location = new System.Drawing.Point(66, 9);
this.nudLastNum.Name = "nudLastNum";
this.nudLastNum.Size = new System.Drawing.Size(120, 21);
this.nudLastNum.TabIndex = 1;
this.nudLastNum.Value = new decimal(new int[] {
100,
0,
0,
0});
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(193, 13);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(53, 12);
this.label2.TabIndex = 2;
this.label2.Text = "结果为:";
//
// txtResult
//
this.txtResult.Location = new System.Drawing.Point(253, 9);
this.txtResult.Name = "txtResult";
this.txtResult.Size = new System.Drawing.Size(100, 21);
this.txtResult.TabIndex = 3;
//
// btnStart
//
this.btnStart.Location = new System.Drawing.Point(15, 86);
this.btnStart.Name = "btnStart";
this.btnStart.Size = new System.Drawing.Size(165, 23);
this.btnStart.TabIndex = 4;
this.btnStart.Text = "开 始";
this.btnStart.UseVisualStyleBackColor = true;
this.btnStart.Click += new System.EventHandler(this.btnStart_Click);
//
// btnCancel
//
this.btnCancel.Location = new System.Drawing.Point(188, 86);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(165, 23);
this.btnCancel.TabIndex = 5;
this.btnCancel.Text = "取 消";
this.btnCancel.UseVisualStyleBackColor = true;
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
//
// progressBar1
//
this.progressBar1.Location = new System.Drawing.Point(15, 116);
this.progressBar1.Name = "progressBar1";
this.progressBar1.Size = new System.Drawing.Size(338, 23);
this.progressBar1.TabIndex = 6;
//
// backgroundWorker1
//
this.backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);
this.backgroundWorker1.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(this.backgroundWorker1_ProgressChanged);
this.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);
//
// lblExecInfo
//
this.lblExecInfo.AutoSize = true;
this.lblExecInfo.Location = new System.Drawing.Point(15, 39);
this.lblExecInfo.Name = "lblExecInfo";
this.lblExecInfo.Size = new System.Drawing.Size(53, 12);
this.lblExecInfo.TabIndex = 7;
this.lblExecInfo.Text = "执行信息";
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(369, 147);
this.Controls.Add(this.lblExecInfo);
this.Controls.Add(this.progressBar1);
this.Controls.Add(this.btnCancel);
this.Controls.Add(this.btnStart);
this.Controls.Add(this.txtResult);
this.Controls.Add(this.label2);
this.Controls.Add(this.nudLastNum);
this.Controls.Add(this.label1);
this.Name = "Form1";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "累加";
((System.ComponentModel.ISupportInitialize)(this.nudLastNum)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Label label1;
private System.Windows.Forms.NumericUpDown nudLastNum;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.TextBox txtResult;
private System.Windows.Forms.Button btnStart;
private System.Windows.Forms.Button btnCancel;
private System.Windows.Forms.ProgressBar progressBar1;
private System.ComponentModel.BackgroundWorker backgroundWorker1;
private System.Windows.Forms.Label lblExecInfo;
}
}
百余行的代码, 就可以完成这么优秀的功能, 是不是很神奇?