当主窗体最小化或移动时,从串行端口接收数据停止

时间:2011-01-12 09:46:20

标签: c#

爵士

如果已经在某个地方覆盖过,我道歉。我做了一个搜索,找到了我已经实现过的东西。

我正在开发一个应用程序,它从通过serialport连接的设备接收数据。我正在使用SerialPort datareceived事件来捕获数据。我将在主窗体的文本框中显示数据。经常收到数据。我用Timer向设备发送命令,在响应设备中发送一些数据。定时器间隔为100 ms。在每100毫秒间隔中,发送一些命令并相应地接收数据。我使用Invoke函数来更新像TExtbox,标签等GUI元素。一切都很好。所有元素都在精美地更新。但是在接收数据期间,如果我在主要表单中进行任何更改,例如移动表单,最小化,最大化或单击表单中的某个位置,则数据接收将停止。我找不到它发生的原因?我还将计时器间隔更改为200,300,400,500,但同样存在问题。

请告诉我为什么会这样?可能的解决方案......

先谢谢.... :)

4 个答案:

答案 0 :(得分: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(...)来执行此操作,因为它在单独的线程上运行。

答案 1 :(得分:0)

为什么不在不同的线程上执行操作并查看。

答案 2 :(得分:0)

我的猜测是你正在崩溃你的计时器线程,因为你无法在没有问题的情况下从另一个线程更新Form控件......你必须创建一个在主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线程调用的函数。

在此示例中,您调用的函数/委托与您所在的函数相同,但并非必须如此。但是你可以传递计时器tick事件处理程序,让它在主线程上执行。

答案 3 :(得分: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最小化时根本不会更新。您可能还希望对后台队列中的项目数量进行限制,如果它仅用于日志记录或类似的事件可以清除旧事件而不会造成损害(否则您可能最终耗尽内存)。