.net开发笔记(十八) winform中的等待框

winform中很多任务是需要在后台线程(或类似)中完成的,也就是说,经常容易涉及到UI界面与后台工作线程之间的交互。比如UI界面控制后台工作的执行(启动、暂停、停止等),后台工作进度在UI界面上的显示。前两天一个员工在UI线程中访问数据库,刚开始数据库在局域网中,没感觉到什么,后来将数据库移到了外网,发现问题来了,至于问题原因想必诸位都知晓,更详细的解释请参考本系列博客(四)。后将这方面的东西整理了一下,如下:

执行后台任务时,UI界面应该怎么做?大概分两种情况:(我自己随便给取的名字)

(1)一种是模式等待

也就说,后台工作没有完成之前,UI界面不允许操作,如下图:

.net开发笔记(十八) winform中的等待框

图1

如上图所示,红色箭头表示后台跟UI界面的交互。

(2)一种是非模式等待

后台工作没完成之前,UI界面可以操作,这个类似文件拷贝出现的信息框,如下图:

.net开发笔记(十八) winform中的等待框

图2

如上图所示,红色箭头表示后台与UI界面的交互。

以上是两种情况,以及对应的结构图,我做了一个Demo,包含两种等待窗体,一种即为“模式等待窗体”,另一种为“非模式等待窗体”。源码在文章结束后有下载地址。先来分别看一下两者的代码:

(1)模式等待窗体

 public partial class frmWait : Form
{
bool _run = true;
public frmWait()
{
InitializeComponent();
}
public object DoWait(object param)
{
List<string> list = new List<string>();
int count = (int)param;
progressBar1.Maximum = count; //---------------------以下代码片段可以使用线程代替
((Action)delegate()
{
System.Threading.Thread.Sleep(); for (int i = ; i < count; ++i) //耗时操作
{
if (_run)
{
string s = DateTime.Now.ToLongTimeString();
list.Add(s);
this.Invoke((Action)delegate()
{
if (!IsDisposed)
{
progressBar1.Value = i;
label1.Text = "正在载入字符串 \"" + s + "\"";
}
});
System.Threading.Thread.Sleep();
}
else
{
break;
}
} }).BeginInvoke(new AsyncCallback(OnAsync), null); //异步执行后台工作
//------------------------ ShowDialog(); //UI界面等待
return list; //后台工作执行完毕 可以使用结果
}
private void OnAsync(IAsyncResult ar)
{
if (_run) //后台工作正常结束
DialogResult = DialogResult.OK;
}
private void frmWait_Load(object sender, EventArgs e)
{ } private void button1_Click(object sender, EventArgs e)
{
_run = false; //UI界面控制后台结束
DialogResult = DialogResult.Cancel;
}
}

如上代码所示,后台任务很简单,就是返回指定数目(param)个字符串,存放在一个list中,使用frmWait也很简单:

  using (frmWait frmw = new frmWait())
{
List<string> list = frmw.DoWait() as List<string>; //弹出模式等待窗体 实时更新显示后台工作进度 后台工作结束后 等待窗体消失 UI线程继续执行...
MessageBox.Show("加载字符串 " + list.Count + "个");
}

(2)非模式等待窗体

  public partial class frmNoWait : Form
{
bool _run = true;
public frmNoWait()
{
InitializeComponent();
}
private void OnAsync(IAsyncResult ar)
{
// ar.AsyncState as List<string> 后台工作执行完毕的结果 if (_run) //后台工作正常结束
this.Invoke((Action)delegate()
{
Close();
});
}
public void DoNoWait(int param)
{
List<string> list = new List<string>();
int count = (int)param;
progressBar1.Maximum = count; //-----------------------以下代码片段 可以使用线程代替
((Action)delegate()
{
try
{
System.Threading.Thread.Sleep();
for (int i = ; i < count; ++i) //耗时操作
{
if (_run)
{
string s = DateTime.Now.ToLongTimeString();
list.Add(s);
this.Invoke((Action)delegate()
{
if (!IsDisposed)
{
progressBar1.Value = i;
label1.Text = "正在载入字符串 \"" + s + "\"";
}
});
System.Threading.Thread.Sleep();
}
else
{
break;
}
}
}
catch
{ }
}).BeginInvoke(new AsyncCallback(OnAsync), list); //异步执行后台工作
//---------------------------- Show();//UI界面不用等待
}
private void frmNoWait_Load(object sender, EventArgs e)
{
Text += (" " + Form1.index++ + "号");
} private void button1_Click(object sender, EventArgs e)
{
Close();
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
base.OnFormClosing(e);
_run = false; //UI界面控制后台结束
}
}

如上代码所示,后台工作开始后,弹出一个非模式对话框,UI界面可以继续操作,也就是说,你可以出现多个frmNoWait窗体,使用很简单,如下:

 frmNoWait frmnw = new frmNoWait();
frmnw.DoNoWait(); //弹出窗体
//UI界面继续...

至于怎么通知UI界面,后台工作结束了,你可以在OnAsync中完成这个功能。

最后上几张截图:

.net开发笔记(十八) winform中的等待框

图3

.net开发笔记(十八) winform中的等待框

图4

源码下载地址:http://files.cnblogs.com/xiaozhi_5638/ProgressForm.rar

希望有帮助!

上一篇:WebApi接口访问异常问题。尝试创建“testController”类型的控制器时出错。请确保控制器具有无参数公共构造函数


下一篇:编程利用利用curses库编程开始