在開發winform時經常會用到多線程防止界面出現假死現象,比如當你單擊某個按鈕時,需要執行很多代碼,但是在執行過程中想實時的將當前執行的情況報告給用戶,類型進度條或文本什么的。
這個時候很顯然,如果你把要實現的內容放在按鈕方法里時,其實界面要等這個按鈕執行完后才能輸出來,這個時候就達不到我們的預期了;那么怎么才能解決問題呢。
我初略終結了一下有以下幾種方法:
1.采用BackgroundWorker控件,這個控件將要實時輸出的內容寫在事件中;
1 private void button1_Click(object sender, EventArgs e) 2 { 3 //異步執行邏輯 4 backgroundWorker1.RunWorkerAsync(); 5 } 6 private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 7 { 8 //實現業務邏輯 9 int i = 5; 10 i = Math.Abs(i); 11 //報告當前處理進度 12 backgroundWorker1.ReportProgress(50); 13 } 14 15 private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) 16 { 17 //當前進度 18 int cuur = e.ProgressPercentage; 19 //實現跨線程控件的輸出 20 this.label1.Text = cuur.ToString(); 21 } 22 23 private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 24 { 25 //執行完畢可以報告信息 26 this.label1.Text = "ok"; 27 }
2.采用委托的方式實現靈活引用Invoke;
1 private void button2_Click(object sender, EventArgs e) 2 { 3 //異步執行邏輯 4 Thread thread = new Thread(ThreadFunc); 5 thread.IsBackground = true; 6 thread.Start(); 7 } 8 private void ThreadFunc() 9 { 10 //實現業務邏輯 11 int i = 5; 12 i = Math.Abs(i); 13 //報告當前處理進度 14 SetLabel(i.ToString()); 15 } 16 //定義委托 17 delegate void SetLabelHandler(string text); 18 //實現方法 19 private void SetLabel(string text) 20 { 21 if (InvokeRequired) 22 { 23 Invoke(new SetLabelHandler(SetLabel), text); 24 } 25 else 26 { 27 this.label1.Text = text; 28 } 29 }
3.采用Lamada表達式動態實現委托調用。
1 private void button3_Click(object sender, EventArgs e) 2 { 3 //異步執行邏輯 4 Thread thread = new Thread(Func); 5 thread.IsBackground = true; 6 thread.Start(); 7 } 8 private void Func() 9 { 10 //實現業務邏輯 11 int i = 5; 12 i = Math.Abs(i); 13 //報告當前處理進度 14 AsyncUI(() => { label1.Text = i.ToString(); }); 15 } 16 public void AsyncUI(Action action) 17 { 18 if (InvokeRequired) 19 { 20 Invoke(action); 21 } 22 else 23 { 24 action(); 25 } 26 }
以上是我總結的三種,至於有沒有其他方法,歡迎大家來拍磚,在這里我想推薦的是第三種方法,這個方法最靈活。
下面來談談我對這三種的看法:
對應第一種方法:使用簡單,拖控件就ok,但是對應需要顯示更負責的數據時比較麻煩;
對應第二種方法:可以不用拖控件來自由定制,但是同第一種方法一樣,如果需要顯示更多控件數據,也要定義很多方法和委托,太冗余累贅;
對於第三種方法:我個人非常喜歡,代碼在需要的時候動態使用,但是我也沒有仔細分析該方法的性能問題。