为什么 Invoke 在另一个 class 中不起作用
why Invoke doesn't work in another class
我会用我的电脑和 Arduino 监控串行端口上接收到的数据。
在 arduino 上,草图发送 thorugt USB 字符串 "aabb" evry 300ms。
我想用 pc 收听,并实时打印控件中的字符串 (Textbox
)。为此,我创建了一个新线程,它在一个循环中侦听到达串口的内容,当它发生时,它通过调用文本框中的字符串写入。如果我在表单的 class 中部署,则这些过程有效,但如果我使用外部 class,则不会。为了更好地解释此事,我粘贴了 class
的代码
class SerialPortManager
{
public SerialPort Serial = new SerialPort();
private Thread thr;
private string Log;
public TextBox textLog;
public string LastString;
public bool thrIsAlive;
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[EditorBrowsable(EditorBrowsableState.Advanced)]
[IODescriptionAttribute("ControlInvokeRequiredDescr")]
public bool InvokeRequired { get; private set; }
//DISPOSE
public void Dispose()
{
this.Dispose();
}
//SET Textobox LOG
public void SetLogTxtB (TextBox txt)
{
textLog = txt;
}
//PORTE DISPONIBILI
public string[] Available_Ports()
{
return SerialPort.GetPortNames();
}
//COSTRUTTORI
public SerialPortManager(string portname, int baudrate,bool InitializeConn)
{
Serial.BaudRate = baudrate;
Serial.PortName = portname;
if (InitializeConn == true) Serial.Open();
}
public SerialPortManager()
{
}
//SETTA I PARAMETRI E INIZIALIZZA LA CONNESSIONE
public void SetConnectionParam(string portname, int baudrate, bool initializeConn)
{
Serial.Close();
Serial.Dispose();
Serial = new SerialPort();
Serial.BaudRate = baudrate;
Serial.PortName = portname;
if (initializeConn == true) Serial.Open();
}
//ASYNC LISTENER
public void AsyncListener()
{
thrIsAlive = true;
thr = new Thread(ThreadReader);
thr.Start();
}
//PROCEDURA PER APPEND
public void AppendTextBox(string value)
{
if (InvokeRequired)
{
this.Invoke(new Action<string>(AppendTextBox), new object[] { value });
return;
}
textLog.Text += value;
}
private void Invoke(Action<string> action, params object[] v)
{
throw new NotImplementedException();
}
void ThreadReader()
{
while (thrIsAlive)
{
string temp = Serial.ReadLine();
LastString = temp;
Log += LastString + "\n";
AppendTextBox(LastString + "\n");
}
}
}
表格里我写了三行
SerialPortManager PortMan = new Driver_Arduin.SerialPortManager("COM3", 9600,true);
PortMan.SetLogTxtB(textBox1);
PortMan.AsyncListener();
如果我尝试 运行 对其编程 returns 错误“不允许跨线程操作”。现在,当我发布这个问题时,我决定做最后一次尝试并将方法 AppendTextBox 更改为:
public void AppendTextBox(string value)
{
if (textLog.InvokeRequired)
{
try
{
textLog.Invoke(new Action<string>(AppendTextBox), new object[] { value });
return;
}
catch (ObjectDisposedException)
{
thrIsAlive = false;
}
}
textLog.Text += value;
}
终于成功了。现在在发布之前确定了 Whosebug 解决问题的能力,我会知道我的代码为什么有效。谢谢
除此之外,SerialPortManager
中的 Invoke
方法应该抛出 NotImplementedException
问题是您定义了自己的 InvokeRequired
/Invoke
.
您需要使用 WinForms 控件提供的这些方法,以便它知道您的代码是否 运行 在创建该控件的线程(UI 线程)内以及它如何更改上下文到这个主题。
实际上,您似乎可以使用 SerialPortManager
,但可以像在 AppendTextBox
中一样使用 textLog
的 InvokeRequired
/Invoke
.
顺便说一句,if (initializeConn == true)
没什么用 - if (initializeConn)
就足够了。
在 SerialPortManager 中,您必须使用委托代替 windows 控制。
class SerialPortManager
{
public SerialPort Serial = new SerialPort();
private Thread thr;
private string Log;
//public TextBox textLog;
public Action<string> textLog;
.....
克里特岛在你形成简单的方法:
public void SetTextBoxText(string value)
{
if (textBox1.InvokeRequired)
{
try
{
textBox1.Invoke(new Action<string>(AppendTextBox), new object[] { value });
return;
}
catch (ObjectDisposedException)
{
thrIsAlive = false;
}
}
textBox1.Text += value;
}
将委托设置为 PortMan:
SerialPortManager PortMan = new Driver_Arduin.SerialPortManager("COM3", 9600,true);
PortMan.SetLogTxtB=new Action<string>(SetTextBoxText);
PortMan.AsyncListener();
如果需要将日志输出到 PortMan 的 TextBox 调用 textLog 委托。
void ThreadReader()
{
while (thrIsAlive)
{
string temp = Serial.ReadLine();
LastString = temp;
Log += LastString + "\n";
//AppendTextBox(LastString + "\n");
textLog(LastString + "\n");
}
}
我会用我的电脑和 Arduino 监控串行端口上接收到的数据。
在 arduino 上,草图发送 thorugt USB 字符串 "aabb" evry 300ms。
我想用 pc 收听,并实时打印控件中的字符串 (Textbox
)。为此,我创建了一个新线程,它在一个循环中侦听到达串口的内容,当它发生时,它通过调用文本框中的字符串写入。如果我在表单的 class 中部署,则这些过程有效,但如果我使用外部 class,则不会。为了更好地解释此事,我粘贴了 class
class SerialPortManager
{
public SerialPort Serial = new SerialPort();
private Thread thr;
private string Log;
public TextBox textLog;
public string LastString;
public bool thrIsAlive;
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[EditorBrowsable(EditorBrowsableState.Advanced)]
[IODescriptionAttribute("ControlInvokeRequiredDescr")]
public bool InvokeRequired { get; private set; }
//DISPOSE
public void Dispose()
{
this.Dispose();
}
//SET Textobox LOG
public void SetLogTxtB (TextBox txt)
{
textLog = txt;
}
//PORTE DISPONIBILI
public string[] Available_Ports()
{
return SerialPort.GetPortNames();
}
//COSTRUTTORI
public SerialPortManager(string portname, int baudrate,bool InitializeConn)
{
Serial.BaudRate = baudrate;
Serial.PortName = portname;
if (InitializeConn == true) Serial.Open();
}
public SerialPortManager()
{
}
//SETTA I PARAMETRI E INIZIALIZZA LA CONNESSIONE
public void SetConnectionParam(string portname, int baudrate, bool initializeConn)
{
Serial.Close();
Serial.Dispose();
Serial = new SerialPort();
Serial.BaudRate = baudrate;
Serial.PortName = portname;
if (initializeConn == true) Serial.Open();
}
//ASYNC LISTENER
public void AsyncListener()
{
thrIsAlive = true;
thr = new Thread(ThreadReader);
thr.Start();
}
//PROCEDURA PER APPEND
public void AppendTextBox(string value)
{
if (InvokeRequired)
{
this.Invoke(new Action<string>(AppendTextBox), new object[] { value });
return;
}
textLog.Text += value;
}
private void Invoke(Action<string> action, params object[] v)
{
throw new NotImplementedException();
}
void ThreadReader()
{
while (thrIsAlive)
{
string temp = Serial.ReadLine();
LastString = temp;
Log += LastString + "\n";
AppendTextBox(LastString + "\n");
}
}
}
表格里我写了三行
SerialPortManager PortMan = new Driver_Arduin.SerialPortManager("COM3", 9600,true);
PortMan.SetLogTxtB(textBox1);
PortMan.AsyncListener();
如果我尝试 运行 对其编程 returns 错误“不允许跨线程操作”。现在,当我发布这个问题时,我决定做最后一次尝试并将方法 AppendTextBox 更改为:
public void AppendTextBox(string value)
{
if (textLog.InvokeRequired)
{
try
{
textLog.Invoke(new Action<string>(AppendTextBox), new object[] { value });
return;
}
catch (ObjectDisposedException)
{
thrIsAlive = false;
}
}
textLog.Text += value;
}
终于成功了。现在在发布之前确定了 Whosebug 解决问题的能力,我会知道我的代码为什么有效。谢谢
除此之外,SerialPortManager
中的 Invoke
方法应该抛出 NotImplementedException
问题是您定义了自己的 InvokeRequired
/Invoke
.
您需要使用 WinForms 控件提供的这些方法,以便它知道您的代码是否 运行 在创建该控件的线程(UI 线程)内以及它如何更改上下文到这个主题。
实际上,您似乎可以使用 SerialPortManager
,但可以像在 AppendTextBox
中一样使用 textLog
的 InvokeRequired
/Invoke
.
顺便说一句,if (initializeConn == true)
没什么用 - if (initializeConn)
就足够了。
在 SerialPortManager 中,您必须使用委托代替 windows 控制。
class SerialPortManager
{
public SerialPort Serial = new SerialPort();
private Thread thr;
private string Log;
//public TextBox textLog;
public Action<string> textLog;
.....
克里特岛在你形成简单的方法:
public void SetTextBoxText(string value)
{
if (textBox1.InvokeRequired)
{
try
{
textBox1.Invoke(new Action<string>(AppendTextBox), new object[] { value });
return;
}
catch (ObjectDisposedException)
{
thrIsAlive = false;
}
}
textBox1.Text += value;
}
将委托设置为 PortMan:
SerialPortManager PortMan = new Driver_Arduin.SerialPortManager("COM3", 9600,true);
PortMan.SetLogTxtB=new Action<string>(SetTextBoxText);
PortMan.AsyncListener();
如果需要将日志输出到 PortMan 的 TextBox 调用 textLog 委托。
void ThreadReader()
{
while (thrIsAlive)
{
string temp = Serial.ReadLine();
LastString = temp;
Log += LastString + "\n";
//AppendTextBox(LastString + "\n");
textLog(LastString + "\n");
}
}