2011-01-12 39 views
1

先生,當主窗體最小化或移動時從串口停止接收數據

如果已經覆蓋某處,我表示歉意。我進行了搜索並找到了一些我已經實施的內容。

我正在開發從經由連接的serialport一個設備接收數據的應用程序。我正在使用SerialPort datareceived事件來捕獲數據。我將在主窗體的文本框中顯示數據。數據被頻繁接收。我用定時器發送命令給設備,在響應設備中發送一些數據。定時器間隔爲100毫秒。在每隔100毫秒的時間間隔內發送一些命令並相應地接收數據。我使用Invoke函數來更新像TExtbox,標籤等GUI元素。一切都很好。所有元素都更新得很漂亮。但在接收數據時,如果我在主表單中進行任何類似移動窗體的更改,最小化,最大化或單擊表單中的某處,則會停止數據接收。我無法找到它發生的原因?我也改變了定時器的時間間隔爲200,300,400,500,但同樣的問題在那裏。

請告訴我爲什麼會發生?和可能的解決方案......

在此先感謝.... :)

回答

0

你爲什麼不這樣做在不同的線程操作和看到的。

+0

爲什麼不是,但serialport datareceived事件也在輔助線程中運行。 – Rahul 2011-01-12 09:53:32

+0

你需要創建異步線程post backs等到用戶界面。 http://dotnetperls.com/backgroundworker – abmv 2011-01-12 10:06:13

+0

這是唯一的出路! – abmv 2011-01-12 10:06:56

1

問題是最小化時Timer被禁用。您應該創建一個新的Thread,並在其中使用Thread.Sleep(100);使其睡眠。另外,當你關門時放棄它。考慮類似於:

Thread recieverThread = new Thread(delegate() 
    { 
    try 
    { 
     //try loading data 
     Thread.Sleep(100); 
    } 
    catch (ThreadAbortException) 
    { 
     //close port or something 
    } 
    }); 

//on form.close or something like that 
recieverThread.Abort(); 

這應該有所斬斷。此外,如果接收器更新界面,您必須使用Form.Invoke(...)來做到這一點,因爲它在單獨的線程上運行。

0

我的猜測是,你崩潰的計時器線程,因爲你不能沒有更新的問題從另一個線程的窗體控件...你必須創建主UI線程下運行的委託。你通過測試Form.InvokeRequired來做到這一點,如果它是真的,則調用Form.Invoke

發生的事情:你的計時器線程正在更新窗體上的文本框或其他控件。您調整大小或最小化,並且這些表單控件的句柄無效...您不能再使用它們了。除了你的計時器線程仍在運行並試圖使用它們。崩潰!

一個很好的例子多線程的形式是here。重要的部分是:

delegate void SetBoolDelegate(bool parameter); 

// This would be your timer tick event handler... 
void SetInputEnabled(bool enabled) { 

    if(!InvokeRequired) { 
     button1.Enabled=enabled; 
     comboBoxDigits.Enabled=enabled; 
     numericUpDownDigits.Enabled=enabled; 
    } 
    else { 
     Invoke(new SetBoolDelegate(SetInputEnabled),new object[] {enabled}); 
    } 

} 

在這個例子中,你測試了InvokeRequired。如果它是假的,那麼你在主UI線程上運行,並可以直接設置控件屬性。如果它是真的,你調用Invoke(),傳遞一個將從主UI線程調用的函數。

在這個例子中,函數/委託你打電話是你在相同的功能,但它並沒有要。但是您可以將它傳遞給計時器滴答事件處理程序,讓它在主線程上執行。

0

在窗口移動操作期間,您的UI線程在模態循環中被阻塞。因此,任何Form.Invoke()呼叫也塊。

最好的辦法是除了接收數據的後臺線程使用的隊列。 UI線程然後在計時器事件期間輪詢數據。

隊列訪問必須同步以避免競爭條件。當UI線程需要獲取要應用的一組更新時交換隊列實例,因爲UI可能需要執行多個耗時的操作。

隊列管理器這樣的事情就可以了(兩個線程本質自己的隊列,管理者開關周圍它們):

private Queue<T> dataQueue; 
private object syncLock = new Object(); 
private volatile bool dataAvailable; // Volatile to avoid locking on read. 

// Called by the background thread to add an event object (e.g. string) to the queue. 
void QueuePut(T data) 
{ 
    lock (this.syncLock) 
    { 
     if (this.dataQueue == null) 
     { 
      this.dataQueue = new Queue<T>(); 
     } 

     this.dataQueue.Add(data); 
     this.dataAvailable = true; 
    } 
} 

// Called by the UI thread to get the pending updates. 
Queue<T> QueueGet(Queue<T> oldQueue) 
{ 
    if (oldQueue != null) 
    { 
     oldQueue.Clear(); 
    } 

    Queue<T> result; 
    lock (this.syncLock) 
    { 
     result = this.dataQueue; 
     this.dataQueue = oldQueue; 
     this.dataAvailable = false; 
    } 

    return result; 
} 

// Called by UI thread to avoid retrieving an empty queue 
// (and subsequent reallocation). 
public bool IsDataAvailable() 
{ 
    get 
    { 
     return this.dataAvailable; 
    } 
} 

這樣的UI並最小化時沒有得到所有更新。如果後臺隊列只用於日誌記錄或類似的地方,可以在不損壞舊事件的情況下清除(否則可能會導致內存不足),您可能還想限制後臺隊列中的項目數量。

相關問題