2012-06-03 82 views
1

我目前有一個問題,這似乎與關閉窗體有關,而通過串行連接連接的一個秤繼續發送數據(每個包約3個包)。 。COM DataReceived事件持續激發時終止窗體。 C#

我在DataReceived事件(處理本身可能是無趣的這個問題,因爲我只是匹配的數據)留意在COM_InUse變量和allowFireDataReceived檢查)處理新的數據:

private void COMScale_DataReceived(object sender, EventArgs e) 
    { 
     if (allowFireDataReceived) 
     { 
      //set atomar state 
      COM_InUse = true; 

      //new scale: 
      if (Properties.Settings.Default.ScaleId == 1) 
      { 
       strLine = COMScale.ReadTo(((char)0x2).ToString()); 
       //new scale: 
       Regex reg = new Regex(Constants.regexScale2); 
       Match m = reg.Match(strLine); 
       if (m.Success) 
       { 
        strGewicht = m.Groups[1].Value + m.Groups[2]; 
        double dblComWeight; 
        double.TryParse(strGewicht, out dblComWeight); 
        dblScaleActiveWeight = dblComWeight/10000; 
        //add comma separator and remove zeros 
        strGewicht = strGewicht.Substring(0, 1) + strGewicht.Substring(1, 2).TrimStart('0') + strGewicht.Substring(3); 
        strGewicht = strGewicht.Insert(strGewicht.Length - 4, ","); 

        //write to textbox 
        ThreadSafeSetActiveScaleText(strGewicht); 

        COMScale.DiscardInBuffer(); 
        //MessageBox.Show(dblScaleActiveWeight.ToString(), "dblScaleActiveWeight"); 
       } 

      } 
      //free atomar state 
      COM_InUse = false; 
     } 
    } 

COM_InUse變量是一個全局布爾值,並且「告訴」是否存在當前的數據處理過程。 allowFireDataReceived也是一個全局布爾值,如果設置爲false,將不會導致額外處理已發送的數據。現在

我的問題是這樣的:

看來Eventhandling是一個獨立的線程,這導致了僵局klicking自COM_InUse取消鍵式將永遠不會變成假的,即使事件已經被處理(請參閱COMScale_DataReceived的結尾,其中COM_InUse設置爲false)。 雖然設置allowFireDataReceived = false完美(無需處理),正如我所說:while循環不會終止。

private void bScaleCancel_Click(object sender, EventArgs e) 
    { 
     allowFireDataReceived = false; 
     while (COM_InUse) 
     { 
      ; 
     } 
     if (!COM_InUse) 
     { 
      ret = 1; 
      SaveClose(); 
     } 
    } 

當我註釋掉while-block時,我必須點擊按鈕兩次,但它沒有崩潰。由於這個用戶不友好,我正在尋找另一種安全關閉窗口的方法。

信息: 簡單地關閉(不檢查COM數據是否被處理)會導致致命的崩潰。

所以,也許有人可以向我解釋究竟是什麼原因導致了這個問題,或者可以提供解決方案。 (也許有人會再次觸發取消點擊事件,但這非常難看)

問候!

我指望你:)

//編輯: 這裏是

private void ThreadSafeSetActiveScaleText(string text) 
    { 
     // InvokeRequired required compares the thread ID of the 
     // calling thread to the thread ID of the creating thread. 
     // If these threads are different, it returns true. 
     if (this.lScaleActive.InvokeRequired) 
     { 
      SafeActiveScaleTextCallback d = new SafeActiveScaleTextCallback(ThreadSafeSetActiveScaleText); 
      this.Invoke(d, new object[] { text }); 
     } 
     else 
     { 
      this.lScaleActive.Text = text; 
     } 
    } 

回答

2
ThreadSafeSetActiveScaleText(strGewicht); 

是的,DataReceived事件檢索上一個線程池線程上運行當前的代碼。你已經知道,否則你不會稱它爲「ThreadSafe」。我們看不到的是這個方法裏面的東西。但考慮到結果,您很可能正在使用Control.Invoke()。

當您在UI線程上運行的代碼中的COM_InUse循環時,會導致死鎖。 Control.Invoke()方法只能在UI線程執行委託目標方法時完成。但UI線程只能在空閒時抽取消息循環並等待Windows消息。並調用請求。它在Click事件處理程序中循環時無法執行此操作。所以Invoke()無法完成。這使得COM_InUse變量永遠保持爲真。這使得Click事件處理程序永遠循環。僵局城市。

當您調用SerialPort.Close()方法時發生完全相同的問題,只有在處理完所有事件後才能關閉端口。

您需要通過使用Control.BeginInvoke()來解決此問題。確保代理目標開始執行時數據仍然有效。例如將其作爲參數傳遞,如果需要的話複製。

在規模無情地發送數據時關閉表單通常是一個問題。當您在已處理的表單上調用時,您會得到一個異常。爲了解決這個問題,你需要實現FormClosing事件處理程序並將e.Cancel設置爲true。並取消訂閱DataReceived事件並啓動計時器。將時間間隔設置爲幾秒鐘。當計時器滴答時,您可以再次關閉表單,現在確保所有數據都已排空,並且不會再發生任何調用。

另請注意,調用DiscardInBuffer()只能很好地隨機丟失數據。

+0

謝謝,我希望能夠通過DiscardInBuffer()處理一個數據包(正則表達式匹配和東西)的同時,清除一些已發送的數據。 聽起來好像我沒有真正簡單的方法來處理這個問題。 順便說一句:正如我所說的,當allowFireDataReceived設置爲false時關閉秤連接工作沒有問題。 – reijin

+0

聽起來像你只讀了答案中的最後一段。那麼你在使用Invoke嗎? –

+0

是的,我確實使用了Invoke(在第一篇文章中添加了代碼)。 不,我看過你的整篇文章。也許我弄錯你了。我會給StartInvoke()一個嘗試。 //編輯: 所以基本上我必須使用BeginInvoke()而不是Invoke()。我有什麼需要照顧的嗎?像EndInvoke()? – reijin

相關問題