为啥 Invoke 在另一个类中不起作用
Posted
技术标签:
【中文标题】为啥 Invoke 在另一个类中不起作用【英文标题】:why Invoke doesn't work in another class为什么 Invoke 在另一个类中不起作用 【发布时间】:2017-04-18 06:38:30 【问题描述】:我会用我的电脑和 Arduino 监控在串行端口上接收到的数据。
在 arduino 上,草图每 300 毫秒向 USB 发送字符串“aabb”。
使用 pc 我想听,并在控件中实时打印字符串 (Textbox
)。为此,我创建了一个新线程,它在循环中侦听到达串行端口的内容,当它发生时,它通过调用文本框中的字符串写入。如果我在表单的类中部署,则这些过程有效,但如果我使用外部类,则不会。为了更好地解释这个问题,我粘贴了类的代码
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();
如果我尝试运行程序,它会返回错误“不允许跨线程操作”。现在,当我发布这个问题时,我决定做最后一次尝试并将 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;
它终于奏效了。现在确定了在发布之前解决问题的 *** 的强大功能,我会知道为什么我的代码有效。谢谢你
【问题讨论】:
【参考方案1】:在 SerialPortManager 中,您必须使用委托而不是窗口控件。
class SerialPortManager
public SerialPort Serial = new SerialPort();
private Thread thr;
private string Log;
//public TextBox textLog;
public Action<string> textLog;
.....
Crete 在你形成简单的方法:
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");
【讨论】:
【参考方案2】:除了SerialPortManager
中的Invoke
方法应该抛出NotImplementedException
之外,问题是你定义了自己的InvokeRequired
/Invoke
。
您需要使用 WinForms 控件提供的这些方法,以便它知道您的代码是否在创建控件的线程(UI 线程)内运行,以及它如何将上下文更改为该线程。
实际上,您似乎可以使用您的SerialPortManager
,但要使用textLog
的InvokeRequired
/Invoke
,就像您已经在AppendTextBox
中所做的那样。
顺便说一句,if (initializeConn == true)
相当没用 - if (initializeConn)
就足够了。
【讨论】:
以上是关于为啥 Invoke 在另一个类中不起作用的主要内容,如果未能解决你的问题,请参考以下文章
为啥 setter 的 'this._obj['a']=2' 在 Dart 类中不起作用
为啥我的 javascript 箭头函数在 Edge/IE 中不起作用?
为啥 iframe 高度 100% 在 XHTML 页面中不起作用? [复制]