[原译]C#制作进度窗体

来源:互联网 发布:黑莓priv淘宝靠谱么 编辑:程序博客网 时间:2024/06/08 05:23

介绍

这是我在CodeProject上的第一篇文章。我希望对你有用

当我开发软件的时候。我通常因为一个很耗时是任务需要完成。而请求让用户等待,并且通过也允许用户取消。不论我做何种操作(比如下载文件。保存大文件等等)。我都需要做下面几件事:

  • 通过一个模态对话框来让用户等待操作完成
  • 能让用户看到进度。
  • 能让用户随时取消。

我搜了好久也没找到拿来就能用的窗体控件,也许是我没找到。于是我自己写。。
图1

背景

BackgroundWorker 类包含了我需要完成任务的所有东西。我只需要给他提供一个对话框。

使用代码

ProgressForm 包含了一个BackgroundWorker ,你要做的仅仅就是提供了一个完成工作的方法。

ProgressForm form = new ProgressForm();form.DoWork += new ProgressForm.DoWorkEventHandler(form_DoWork);//如果想为后台任务提供参数的话form.Argument = something;

 

为了开始BackgroundWorker,只需要调用ShowDialog 方法。返回值则取决于任务是怎么完成的。

复制代码
DialogResult result = form.ShowDialog();if (result == DialogResult.Cancel){//用户点击了取消}else if (result == DialogResult.Abort){/未处理的异常抛出//你可以得到异常信息MessageBox.Show(form.Result.Error.Message);}else if (result == DialogResult.OK){//正常完成//结果存储在 form.Result里}
复制代码

 

 

最后。任务方法看起来是这样的。

复制代码
void form_DoWork(ProgressForm sender, DoWorkEventArgs e){//得到参数object myArgument = e.Argument;//做一些耗时的任务...for (int i = 0; i < 100; i++){//通知进度sender.SetProgress(i, "Step " + i.ToString() + " / 100...");//...//检查是否点击了取消if (sender.CancellationPending){e.Cancel = true;return;}}}
复制代码

 

如果你想要改改进度条,或者进度条显示的文本。SetProgress 有一些重载的方法

public void SetProgress(string status);public void SetProgress(int percent);public void SetProgress(int percent, string status);

 

最后一个可自定义的字符串是:有两个预定义的字符串CancellingText 和DefaultStatusText. CancellingText ,这两个字符串,当用户点击取消的时候显示

如何实现
ProgressForm 紧紧嵌入了一个BackgroundWorker ,并包装进了主函数。

首先。我设计了如图所示的一个窗体,然后。添加了BackgroundWorker。

复制代码
public partial class ProgressForm : Form{public ProgressForm(){InitializeComponent();worker = new BackgroundWorker();worker.WorkerReportsProgress = true;worker.WorkerSupportsCancellation = true;worker.DoWork += new System.ComponentModel.DoWorkEventHandler(worker_DoWork);worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);}void worker_DoWork(object sender, DoWorkEventArgs e){}void worker_ProgressChanged(object sender, ProgressChangedEventArgs e){}void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e){}BackgroundWorker worker;}
复制代码

我们必须把DoWork事件暴露给用户。我添加了一个委托。这样。我可以很容易的访问窗体成员

复制代码
public delegate void DoWorkEventHandler(ProgressForm sender, DoWorkEventArgs e);public event DoWorkEventHandler DoWork;void worker_DoWork(object sender, DoWorkEventArgs e){//后台任务开始//调用用户的事件处理程序if (DoWork != null)DoWork(this, e);}
复制代码

 

好。我们已经有了任务和事件。先爱。我们希望当窗体显示的时候。后台任务尽可能开始。我们在Load事件中写代码

复制代码
void ProgressForm_Load(object sender, EventArgs e){worker.RunWorkerAsync();}现在写一个方法通知进度。添加代码到ProgressChanged 事件处理程序中public void SetProgress(int percent, string status){worker.ReportProgress(percent, status);}void worker_ProgressChanged(object sender, ProgressChangedEventArgs e){if (e.ProgressPercentage >= progressBar.Minimum &&e.ProgressPercentage <= progressBar.Maximum){progressBar.Value = e.ProgressPercentage;}if (e.UserState != null)labelStatus.Text = e.UserState.ToString();}
复制代码

 

我们快做好了。现在我们添加取消按钮

复制代码
void buttonCancel_Click(object sender, EventArgs e){//通过worker我们要取消worker.CancelAsync();//使取消按钮不可用,改变状态文本buttonCancel.Enabled = false;labelStatus.Text = "Cancelling..."}最后一件事是我们想要当worker完成的时候自动关闭窗体,因为我们的worker通过ShowDialog 方法启动。如果直接接收返回结果会很好void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e){//ShowDialog返回值会指示worker是不是正确完成了if (e.Error != null)DialogResult = DialogResult.Abort;else if (e.Cancelled)DialogResult = DialogResult.Cancel;elseDialogResult = DialogResult.OK;//关闭窗体Close();}
复制代码

 

主要的工作就完成了。我添加了一些预定义的字符串啊。如果正在取消。保护状态不会改变。还有传递参数啊。
完整的代码如下:

复制代码
/// <summary>/// 简单的进度窗体/// </summary>public partial class ProgressForm : Form{/// <summary>/// 获得进度条以对他自定义/// 在显示窗体之前./// 不要在后台任务中直接使用 !/// </summary>public ProgressBar ProgressBar { get { return progressBar; } }/// <summary>/// 传递给后台任务的参数./// </summary>public object Argument { get; set; }/// <summary>/// 后台任务的结果.///也可以检查ShowDialog返回值///来看看是不是正确完成了./// </summary>public RunWorkerCompletedEventArgs Result { get; private set; }/// <summary>/// 如果点击了取消按钮则为true///后台任务还在执行/// </summary>public bool CancellationPending{get { return worker.CancellationPending; }}/// <summary>/// 取消按钮被点击之后的显示文本/// </summary>public string CancellingText { get; set; }/// <summary>/// 缺省状态文本./// </summary>public string DefaultStatusText { get; set; }/// <summary>/// DoWork事件的委托./// </summary>/// <param name="sender">T事件源.</param>/// <param name="e">包含事件数据.</param>public delegate void DoWorkEventHandler(ProgressForm sender, DoWorkEventArgs e);/// <summary>/// 当后台任务开始的时候发生./// </summary>public event DoWorkEventHandler DoWork;/// <summary>/// 构造函数./// </summary>public ProgressForm(){InitializeComponent();DefaultStatusText = "Please wait...";CancellingText = "Cancelling operation...";worker = new BackgroundWorker();worker.WorkerReportsProgress = true;worker.WorkerSupportsCancellation = true;worker.DoWork += new System.ComponentModel.DoWorkEventHandler(worker_DoWork);worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);}/// <summary>/// 改变状态文本./// </summary>/// <param name="status">新状态文本.</param>public void SetProgress(string status){//如果没有改变//或者取消请求还在处理就不改变状态文本if (status != lastStatus && !worker.CancellationPending){lastStatus = status;worker.ReportProgress(progressBar.Minimum - 1, status);}}/// <summary>///改变进度条的值/// </summary>/// <param name="percent">新值.</param>public void SetProgress(int percent){//如果值没有改变就不要更新进度条if (percent != lastPercent){lastPercent = percent;worker.ReportProgress(percent);}}/// <summary>///改变进度条值和文本./// </summary>/// <param name="percent">N新值.</param>/// <param name="status">新文本.</param>public void SetProgress(int percent, string status){//如果至少一个改变就调用if (percent != lastPercent || (status != lastStatus && !worker.CancellationPending)){lastPercent = percent;lastStatus = status;worker.ReportProgress(percent, status);}}private void ProgressForm_Load(object sender, EventArgs e){//重用窗体,恢复缺省值Result = null;buttonCancel.Enabled = true;progressBar.Value = progressBar.Minimum;labelStatus.Text = DefaultStatusText;lastStatus = DefaultStatusText;lastPercent = progressBar.Minimum;//窗体已载入就开始后台任务worker.RunWorkerAsync(Argument);}private void buttonCancel_Click(object sender, EventArgs e){//通知后台任务,我们要取消worker.CancelAsync();//取消按钮不可用,改变文本buttonCancel.Enabled = false;labelStatus.Text = CancellingText;}void worker_DoWork(object sender, DoWorkEventArgs e){//后台任务开始//调用用户的处理程序if (DoWork != null)DoWork(this, e);}void worker_ProgressChanged(object sender, ProgressChangedEventArgs e){//确保新值可用并更新if (e.ProgressPercentage >= progressBar.Minimum &&e.ProgressPercentage <= progressBar.Maximum){progressBar.Value = e.ProgressPercentage;}//如果取消请求正在处理就不要更新if (e.UserState != null && !worker.CancellationPending)labelStatus.Text = e.UserState.ToString();}void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e){//后台任务完成//保持结果,关闭窗体Result = e;if (e.Error != null)DialogResult = DialogResult.Abort;else if (e.Cancelled)DialogResult = DialogResult.Cancel;elseDialogResult = DialogResult.OK;Close();}BackgroundWorker worker;int lastPercent;string lastStatus;}
复制代码

 

结论
窗体简单,我通常用。希望对你们也有用