我正在研究与串口相关的应用程序。在使用DataReceived
SerialPort
事件时,我需要使用收到的字节更新文本框:
private void Connection_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
ledReceive.On = true;
var data = Connection.ReadExisting();
_readBuffer.Add(data);
Invoke(new EventHandler(AddReceivedPacketToTextBox));
}
所以我使用Invoke
来更新文本框。但是有一个大问题。当我尝试关闭连接时,我的UI被冻结了,我认为这是因为Invoke
正在做某些事情。
一位朋友说我应该使用RequiredInvoke
,但我不知道他真的是什么。如何在不搞乱调用和UI线程的情况下关闭连接?
这是我的近距离方法:
private void DisconnectFromSerialPort()
{
if (Connection != null && Connection.IsOpen)
{
Connection.Close();
_receivedPackets = 0; //reset received packet count
}
}
答案 0 :(得分:1)
我不完全确定,但我猜想在关闭连接时会删除正在更新UI的线程,这可以解释为什么它会冻结。但是如果不挖掘所有代码我就无法确定。
如果尝试访问您的元素的线程不是您的UI本机,则InvokeRequired返回true。或者如果您更喜欢MS解释:
// Summary:
// Gets a value indicating whether the caller must call an invoke method when
// making method calls to the control because the caller is on a different thread
// than the one the control was created on.
//
// Returns:
// true if the control's System.Windows.Forms.Control.Handle was created on
// a different thread than the calling thread (indicating that you must make
// calls to the control through an invoke method); otherwise, false.
基本实现:
public void ReceiveCall()
{
if (this.InvokeRequired)
{
this.Invoke(new CallDelegate(ReceiveCall), new object[] { });
return; // Important to not continue on this method.
}
// Whatever else this function is suppose to do when on the correct thread.
}
Invoke应该是你的函数做的第一件事,以防止该线程深入UI。现在,如果确定连接本身在UI的线程的bounderies内,它可能不会触发“InvokeRequired”。防止这种情况发生的一种方法是手动创建一个更新未绑定到您的连接的UI的线程。
我有一个类似的问题,时钟更新多个UI元素的渲染。时钟会工作正常,但会“挂起”,直到所有的UI都完成呈现,这在很多UI的情况下意味着它会跳过它的下一个滴答。
Thread updateUI = new Thread(updateUIDelegate);
updateUI.Start();
这样,我的时钟(或你的连接)将启动一个独立的线程,它自己完成它的东西。您可能还需要检查Monitor类或lock关键字以防止使用相同变量冲突线程或多个线程。
编辑:或者你可以阅读很棒的答案,这可能比我的更有意义:What causes my UI to freeze when closing a serial port?