1 在开发winform时经常会用到多线程防止界面出现假死现象,比如当你单击某个按钮时,需要执行很多代码,但是在执行过程中想实时的将当前执行的情况报告给用户,类型进度条或文本什么的。
2
3 这个时候很显然,如果你把要实现的内容放在按钮方法里时,其实界面要等这个按钮执行完后才能输出来,这个时候就达不到我们的预期了;那么怎么才能解决问题呢。
4
5 我初略终结了一下有以下几种方法:
6
7 1.采用BackgroundWorker控件,这个控件将要实时输出的内容写在事件中;
8
9
10 1 private void button1_Click(object sender, EventArgs e)
11 2 {
12 3 //异步执行逻辑
13 4 backgroundWorker1.RunWorkerAsync();
14 5 }
15 6 private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
16 7 {
17 8 //实现业务逻辑
18 9 int i = 5;
19 10 i = Math.Abs(i);
20 11 //报告当前处理进度
21 12 backgroundWorker1.ReportProgress(50);
22 13 }
23 14
24 15 private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
25 16 {
26 17 //当前进度
27 18 int cuur = e.ProgressPercentage;
28 19 //实现跨线程控件的输出
29 20 this.label1.Text = cuur.ToString();
30 21 }
31 22
32 23 private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
33 24 {
34 25 //执行完毕可以报告信息
35 26 this.label1.Text = "ok";
36 27 }
37
38 2.采用委托的方式实现灵活引用Invoke;
39
40
41 1 private void button2_Click(object sender, EventArgs e)
42 2 {
43 3 //异步执行逻辑
44 4 Thread thread = new Thread(ThreadFunc);
45 5 thread.IsBackground = true;
46 6 thread.Start();
47 7 }
48 8 private void ThreadFunc()
49 9 {
50 10 //实现业务逻辑
51 11 int i = 5;
52 12 i = Math.Abs(i);
53 13 //报告当前处理进度
54 14 SetLabel(i.ToString());
55 15 }
56 16 //定义委托
57 17 delegate void SetLabelHandler(string text);
58 18 //实现方法
59 19 private void SetLabel(string text)
60 20 {
61 21 if (InvokeRequired)
62 22 {
63 23 Invoke(new SetLabelHandler(SetLabel), text);
64 24 }
65 25 else
66 26 {
67 27 this.label1.Text = text;
68 28 }
69 29 }
70
71 3.采用Lamada表达式动态实现委托调用。
72
73
74 1 private void button3_Click(object sender, EventArgs e)
75 2 {
76 3 //异步执行逻辑
77 4 Thread thread = new Thread(Func);
78 5 thread.IsBackground = true;
79 6 thread.Start();
80 7 }
81 8 private void Func()
82 9 {
83 10 //实现业务逻辑
84 11 int i = 5;
85 12 i = Math.Abs(i);
86 13 //报告当前处理进度
87 14 AsyncUI(() => { label1.Text = i.ToString(); });
88 15 }
89 16 public void AsyncUI(Action action)
90 17 {
91 18 if (InvokeRequired)
92 19 {
93 20 Invoke(action);
94 21 }
95 22 else
96 23 {
97 24 action();
98 25 }
99 26 }
100
101
102
103 以上是我总结的三种,至于有没有其他方法,欢迎大家来拍砖,在这里我想推荐的是第三种方法,这个方法最灵活。
104
105 下面来谈谈我对这三种的看法:
106
107 对应第一种方法:使用简单,拖控件就ok,但是对应需要显示更负责的数据时比较麻烦;
108
109 对应第二种方法:可以不用拖控件来自由定制,但是同第一种方法一样,如果需要显示更多控件数据,也要定义很多方法和委托,太冗余累赘;
110
111 对于第三种方法:我个人非常喜欢,代码在需要的时候动态使用,但是我也没有仔细分析该方法的性能问题。