如何将变量传递给 Lambda 表达式
How to pass a Variable to Lambda Expression
我上周才开始使用 C#,并尝试创建一个简单的串行监视器程序。我希望我的程序连续从串行端口读取数据,同时在表单应用程序中显示这些数据。
我使用这里的代码作为参考 https://github.com/ahelsayd/Serial-Lab
我使用相同的 BeginInvoke() 函数。但是我不能传递我想写的变量。
这是原代码
private void rx_data_event(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
if (mySerial.IsOpen)
{
try
{
//=====Only this part is different=======================
int dataLength = mySerial.BytesToRead;
byte[] dataReceived = new byte[dataLength];
int nbytes = mySerial.Read(dataReceived, 0, dataLength);
if (nbytes == 0) return;
//=====Only this part is different=======================
this.BeginInvoke((Action)(() =>
{
data = System.Text.Encoding.Default.GetString(dataReceived);
if (!backgroundWorker1.IsBusy)
{
backgroundWorker1.RunWorkerAsync();
}
}));
}
catch { alert("Can't read form " + mySerial.PortName + " port it might be opennd in another program"); }
}
}
//And then update the UI
private void update_rxtextarea_event(object sender, DoWorkEventArgs e)
{
this.BeginInvoke((Action)(() =>
{
if (rx_textarea.Lines.Count() > 5000)
rx_textarea.ResetText();
rx_textarea.AppendText("[RX]> " + data);
}));
}
这段代码可以同时读取串口和写入窗体。但是,它不会从串行端口接收所有数据。所以我修改了代码,先将数据写入缓冲区,直到接收到所有数据。
修改后的代码
private void rx_data_event(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
if (mySerial.IsOpen)
{
try
{
//=====Only this part is different=======================
string Data = mySerial.ReadExisting();
serialBuffer.Append(Data);
string bufferString = serialBuffer.ToString();
int index = -1;
do
{
index = bufferString.IndexOf(terminationSequence);
if (index > -1)
{
string message = bufferString.Substring(0, index);
bufferString = bufferString.Remove(0, index + terminationSequence.Length);
}
}
while (index > -1);
serialBuffer = new StringBuilder(bufferString);
byte[] bytes = new byte[30];
if (serialBuffer.Length == 15) {
Console.WriteLine("data:" + serialBuffer);
bytes = Encoding.ASCII.GetBytes(serialBuffer.ToString());
}
//=====Only this part is different=======================
this.BeginInvoke((Action)(() =>
{
data = Encoding.ASCII.GetString(bytes);
if (!backgroundWorker1.IsBusy)
{
backgroundWorker1.RunWorkerAsync();
}
}));
}
catch { alert("Can't read form " + mySerial.PortName + " port it might be opennd in another program"); }
}
}
问题出在表单应用程序中,字节的值始终为空,尽管当我通过将输出值写入控制台进行检查时 window 我可以看到字节的值已更新。
我很困惑为什么变量 dataReceived 值可以被 BeginInvoke 访问,而变量字节保持空值。是否有我遗漏的东西导致值未更新?
所以我昨天没能做到,但我向 OP 保证我会在与我的评论相关的答案中写一些东西。据我了解,he/she 正在尝试根据从串口接收到的数据更新表单中的内容。以下是我的做法:
首先你需要声明一个 delegate 和一个 event (这基本上是一个委托列表):
public delegate void Data_Received_EventHandler(object sender, Data_Received_EventArgs e);
public event Data_Received_EventHandler Data_Received;
这些用于从串口替换原来的"data received"事件和事件参数。
为了简单起见,我通常将 Data_Received_EventArgs
类型定义为基于字节数组的类型:
public class Data_Received_EventArgs : EventArgs
{
public byte[] data;
internal Data_Received_EventArgs(int length)
{
data = new byte[length];
}
}
那么在原来的数据接收事件中(假设你的串口叫serialPort1
):
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// check how many bytes you need to read:
int bytesToRead = serialPort1.BytesToRead;
// declare your arguments for the event based on that number of bytes (check the Data_Received_EventArgs constructor):
Data_Received_EventArgs args = new Data_Received_EventArgs(bytesToRead);
// copy the bytes from your serial port into the arguments:
for (int i = 0; i < bytesToRead; i++)
args.data[i] = (byte)serialPort1.ReadByte();
// verify if there are subscribers to the event (list not empty) and fire your event using BeginInvoke:
if (Data_Received != null)
BeginInvoke((MethodInvoker)delegate () { Data_Received(this, args); });
}
我们现在拥有的是保证在 UI 线程上执行其 处理程序 的事件。
要使用它,您可以像这样订阅事件:
Data_Received += My_Data_Received_Handler;
你的 handler 应该与我们在第一行代码中声明的 delegate 具有相同的签名(应该是 void
并指定了参数):
private void My_Data_Received_Handler(object sender, Data_Received_EventArgs e)
{
// read bytes from the arguments as you normally would from an array and do whatever e.g.:
some_Label.Text = e.data[0].ToString(); // without worrying about crossthreading
}
我知道这不是 OP 想要的答案,但我希望它有助于简化 he/she 最初尝试做的事情。
我上周才开始使用 C#,并尝试创建一个简单的串行监视器程序。我希望我的程序连续从串行端口读取数据,同时在表单应用程序中显示这些数据。 我使用这里的代码作为参考 https://github.com/ahelsayd/Serial-Lab
我使用相同的 BeginInvoke() 函数。但是我不能传递我想写的变量。
这是原代码
private void rx_data_event(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
if (mySerial.IsOpen)
{
try
{
//=====Only this part is different=======================
int dataLength = mySerial.BytesToRead;
byte[] dataReceived = new byte[dataLength];
int nbytes = mySerial.Read(dataReceived, 0, dataLength);
if (nbytes == 0) return;
//=====Only this part is different=======================
this.BeginInvoke((Action)(() =>
{
data = System.Text.Encoding.Default.GetString(dataReceived);
if (!backgroundWorker1.IsBusy)
{
backgroundWorker1.RunWorkerAsync();
}
}));
}
catch { alert("Can't read form " + mySerial.PortName + " port it might be opennd in another program"); }
}
}
//And then update the UI
private void update_rxtextarea_event(object sender, DoWorkEventArgs e)
{
this.BeginInvoke((Action)(() =>
{
if (rx_textarea.Lines.Count() > 5000)
rx_textarea.ResetText();
rx_textarea.AppendText("[RX]> " + data);
}));
}
这段代码可以同时读取串口和写入窗体。但是,它不会从串行端口接收所有数据。所以我修改了代码,先将数据写入缓冲区,直到接收到所有数据。
修改后的代码
private void rx_data_event(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
if (mySerial.IsOpen)
{
try
{
//=====Only this part is different=======================
string Data = mySerial.ReadExisting();
serialBuffer.Append(Data);
string bufferString = serialBuffer.ToString();
int index = -1;
do
{
index = bufferString.IndexOf(terminationSequence);
if (index > -1)
{
string message = bufferString.Substring(0, index);
bufferString = bufferString.Remove(0, index + terminationSequence.Length);
}
}
while (index > -1);
serialBuffer = new StringBuilder(bufferString);
byte[] bytes = new byte[30];
if (serialBuffer.Length == 15) {
Console.WriteLine("data:" + serialBuffer);
bytes = Encoding.ASCII.GetBytes(serialBuffer.ToString());
}
//=====Only this part is different=======================
this.BeginInvoke((Action)(() =>
{
data = Encoding.ASCII.GetString(bytes);
if (!backgroundWorker1.IsBusy)
{
backgroundWorker1.RunWorkerAsync();
}
}));
}
catch { alert("Can't read form " + mySerial.PortName + " port it might be opennd in another program"); }
}
}
问题出在表单应用程序中,字节的值始终为空,尽管当我通过将输出值写入控制台进行检查时 window 我可以看到字节的值已更新。
我很困惑为什么变量 dataReceived 值可以被 BeginInvoke 访问,而变量字节保持空值。是否有我遗漏的东西导致值未更新?
所以我昨天没能做到,但我向 OP 保证我会在与我的评论相关的答案中写一些东西。据我了解,he/she 正在尝试根据从串口接收到的数据更新表单中的内容。以下是我的做法:
首先你需要声明一个 delegate 和一个 event (这基本上是一个委托列表):
public delegate void Data_Received_EventHandler(object sender, Data_Received_EventArgs e);
public event Data_Received_EventHandler Data_Received;
这些用于从串口替换原来的"data received"事件和事件参数。
为了简单起见,我通常将 Data_Received_EventArgs
类型定义为基于字节数组的类型:
public class Data_Received_EventArgs : EventArgs
{
public byte[] data;
internal Data_Received_EventArgs(int length)
{
data = new byte[length];
}
}
那么在原来的数据接收事件中(假设你的串口叫serialPort1
):
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// check how many bytes you need to read:
int bytesToRead = serialPort1.BytesToRead;
// declare your arguments for the event based on that number of bytes (check the Data_Received_EventArgs constructor):
Data_Received_EventArgs args = new Data_Received_EventArgs(bytesToRead);
// copy the bytes from your serial port into the arguments:
for (int i = 0; i < bytesToRead; i++)
args.data[i] = (byte)serialPort1.ReadByte();
// verify if there are subscribers to the event (list not empty) and fire your event using BeginInvoke:
if (Data_Received != null)
BeginInvoke((MethodInvoker)delegate () { Data_Received(this, args); });
}
我们现在拥有的是保证在 UI 线程上执行其 处理程序 的事件。 要使用它,您可以像这样订阅事件:
Data_Received += My_Data_Received_Handler;
你的 handler 应该与我们在第一行代码中声明的 delegate 具有相同的签名(应该是 void
并指定了参数):
private void My_Data_Received_Handler(object sender, Data_Received_EventArgs e)
{
// read bytes from the arguments as you normally would from an array and do whatever e.g.:
some_Label.Text = e.data[0].ToString(); // without worrying about crossthreading
}
我知道这不是 OP 想要的答案,但我希望它有助于简化 he/she 最初尝试做的事情。