横槊临江

New give up !

导航

实现 winform 异步跨线程访问UI控件

  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 对于第三种方法:我个人非常喜欢,代码在需要的时候动态使用,但是我也没有仔细分析该方法的性能问题。

 

 

posted on 2013-07-04 21:31  jian60521  阅读(1192)  评论(4编辑  收藏  举报