2012-06-26 229 views
1

我有一個代碼,其是這樣的:如何避免GUI凍結?

private void testToolStripMenuItem_Click(object sender, EventArgs e) 
{ 
    toolStripStatusLabel1.Text = " Device Testing..."; 

    positive = false; 

    clearsensors_gui(); 
    datarec = false; 
    cmd = 04; 
    datarec = serialport_FT(0, 1); 

    if (datarec) 
    { 
     char ab = Convert.ToChar(rec_data[1]); 
     //MessageBox.Show("\n" + ab + "\n"); 
     int cab = Convert.ToInt16(ab); 
     int cabc1 = cab & 1; 
     int cabc2 = cab & 2; 
     int cabc3 = cab & 4; 
     int cabc4 = cab & 8; 
     int cabc5 = cab & 16; 
     int cabc6 = cab & 32; 

     if (cabc1 == 1) 
      ovalShape1.FillColor = Color.Green; 
     else 
      ovalShape1.FillColor = Color.Red; 

     if (cabc2 == 2) 
      ovalShape2.FillColor = Color.Green; 
     else 
      ovalShape2.FillColor = Color.Red; 

     if (cabc3 == 4) 
      ovalShape3.FillColor = Color.Green; 
     else 
      ovalShape3.FillColor = Color.Red; 

     if (cabc4 == 8) 
      ovalShape4.FillColor = Color.Green; 
     else 
      ovalShape4.FillColor = Color.Red; 

     if (cabc5 == 16) 
      ovalShape5.FillColor = Color.Green; 
     else 
      ovalShape5.FillColor = Color.Red; 

     if (cabc6 == 32) 
      ovalShape6.FillColor = Color.Green; 
     else 
      ovalShape6.FillColor = Color.Red; 

     toolStripStatusLabel1.Text = " Device Tested"; 
    } 
    else 
    { 
     toolStripStatusLabel1.Text = "Try Again or Communication With Device Failure...."; 
    } 
} 

上述代碼是讀取一個傳感器即datarec = serialport_FT(0,1);函數爲GUI端提供了一個傳感器輸出,後面會用紅色\綠色描述ovalShapeX(1-6)

問題:datarec = serialport_FT(0, 1);這個函數需要liltime,因此GUI會凍結,直到那個時候如何避免這種情況?

我試過使用後臺工作器,但沒有得到在哪裏把整個過程 也遇到了交叉線程操作錯誤,當它去到ovalShape並改變它的屬性。

我沒有收到在後臺使用什麼功能的一部分,何時何地回到第一線

請幫我使用的BackgroundWorker或使用調用,如果我必須使用線程

+0

在後臺線程中調用serialport_FT() - 請參閱http://stackoverflow.com/search?q=c%23+gui+background – Slugart

+0

使用backgroundworker,將'serialport_FT(0,1)'放入'DoWork()'並將'if(datarec){...}'放入'Completed()'事件中。 –

+0

爲了避免出現交叉線程異常,請執行以下操作:http:// stackoverflow。com/a/1136406/400303 – Mohammad

回答

5

你可以做這樣的事情:

toolStripStatusLabel1.Text = " Device Testing..."; 
positive = false; 
clearsensors_gui(); 
datarec = false; 
cmd = 04; 

BackgroundWorker worker = new BackgroundWorker(); 

worker.DoWork += delegate(object s, DoWorkEventArgs args) 
{ 
    // Will be run on background thread 
    args.Result = serialport_FT(0, 1); 
}; 

worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args) 
{ 
    bool result = (bool)args.Result; 

    if (result) 
    { 
     // Do your UI updates here 
    } 
}; 

worker.RunWorkerAsync(); 

一個改進可能是datarecrec_data結合在args.Result元組。

+0

謝謝......試過這個......我這次沒有得到任何錯誤,但UI消息得到了更新。我把這個塊:** if(datatarec){...} **放在** if(result){...} **之下。我究竟做錯了什麼? – pdthekd

+0

你是否檢查serialport_FT是否返回true,結果是否正確? – ekholm

+0

是的結果是真的......所以在此之後,我調用另一個函數,其中有**如果(datarec){...} ** [問題發佈] ovalShapesX [1-6]沒有更新既不給我例外或錯誤 – pdthekd

2

在後臺工作者中,您使用DoWork事件。

worker.DoWork += new DoWorkEventHandler(yourEventHandler); 

void yourEventHandler(object sender, DoWorkEventArgs e) 
{ 
//your work here 
} 
0

將這個在後臺線程,你已經嘗試過(或更好,但一Task),但要小心,只能通過Control.Invoke(爲的WinForms)或Dispatcher.Invoke(對於WPF)來調用GUI相關的操作。

0

使用一個標籤,隨着任務的進展實時更新。你可以試試這個代碼[使用BackGroundWorker]。查看DoWork你放置業務邏輯的位置[請參閱代碼中的BusinessClass用法],然後查看ProgressChanged,後臺任務隨着任務進度實時向用戶界面發出信號,&終於看到RunWorkerCompleted任務完成後處理代碼的位置,錯誤或取消。

using System.ComponentModel; 
using System.Windows.Forms; 

namespace WindowsFormsApplication1 
{ 
    public partial class Form3 : Form 
    { 
     private BackgroundWorker _worker; 
     BusinessClass _biz = new BusinessClass(); 
     public Form3() 
     { 
      InitializeComponent(); 
      InitWorker(); 
     } 

     private void InitWorker() 
     { 
      if (_worker != null) 
      { 
       _worker.Dispose(); 
      } 

      _worker = new BackgroundWorker 
      { 
       WorkerReportsProgress = true, 
       WorkerSupportsCancellation = true 
      }; 
      _worker.DoWork += DoWork; 
      _worker.RunWorkerCompleted += RunWorkerCompleted; 
      _worker.ProgressChanged += ProgressChanged; 
      _worker.RunWorkerAsync(); 
     } 


     void DoWork(object sender, DoWorkEventArgs e) 
     { 
      int highestPercentageReached = 0; 
      if (_worker.CancellationPending) 
      { 
       e.Cancel = true; 
      } 
      else 
      { 
       double i = 0.0d; 
       int junk = 0; 
       for (i = 0; i <= 199990000; i++) 
       { 
        int result = _biz.MyFunction(junk); 
        junk++; 

        // Report progress as a percentage of the total task. 
        var percentComplete = (int)(i/199990000 * 100); 
        if (percentComplete > highestPercentageReached) 
        { 
         highestPercentageReached = percentComplete; 
         // note I can pass the business class result also and display the same in the LABEL 
         _worker.ReportProgress(percentComplete, result); 
         _worker.CancelAsync(); 
        } 
       } 

      } 
     } 

     void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
     { 
      if (e.Cancelled) 
      { 
       // Display some message to the user that task has been 
       // cancelled 
      } 
      else if (e.Error != null) 
      { 
       // Do something with the error 
      } 
     } 

     void ProgressChanged(object sender, ProgressChangedEventArgs e) 
     { 
      label1.Text = string.Format("Result {0}: Percent {1}",e.UserState, e.ProgressPercentage); 
     } 
    } 

    public class BusinessClass 
    { 
     public int MyFunction(int input) 
     { 
      return input+10; 
     } 
    } 
} 
+0

我不明白這一點......你可以多做一點闡述? – pdthekd

+0

你沒有得到什麼? –

1

當你正在使用的WinForms,這裏是一個偉大的MSDN文章,讓你開始在應用程序中使用多個線程:Give Your .NET-based Application a Fast and Responsive UI with Multiple Threads

這篇文章是「幾天老」,但原則仍然今天絕對有效。

如果您使用的是.NET 4.x版本,則還可以使用Task Parallel Library來更輕鬆地處理多個線程。

即將推出的.NET 4.5還提供了更加舒適的await和asyc關鍵字:Asynchronous Programming with Async and Await