主窗体接收到串口数据后触发函数
Trigger function in main form after serial data is received
我正在制作一个程序来读取 NFC 卡上的值。
我有一个 class,它从连接到 NFC IC 的 EMBED 发送的串行通信中读取值。接收到数据后,程序(在主窗体中)必须更改 'page' 并处理数据。
我使用了不同的用户控件 'pages'.
我知道有多个线程,如果不使用某种 Invoke/Deleagate,我无法从不同的线程更改 GUI?但是,我不确定如何在我的代码中实现它。
这是我的代码(省略了不相关的代码):
串行数据Class
public class SerialData
{
public SerialPort ComPort;
public String savedText;
public SerialData()
{
ComPort = new SerialPort();
// set port data
ComPort.PortName = "COM5";
ComPort.BaudRate = 9600;
ComPort.DataBits = 8;
ComPort.RtsEnable = true;
ComPort.DtrEnable = true;
}
public void readCard()
{
try
{
savedText = "";
ComPort.Open();
ComPort.DataReceived += ComPort_DataReceived;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message + ex.StackTrace);
}
}
private void ComPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
var serialPort = (SerialPort)sender;
var data = serialPort.ReadExisting();
savedText += data;
}
}
Form1 代码
public partial class Form1 : Form
{
List<UserControl> Pages = new List<UserControl>();
public int CurrentPage = 0;
SerialData SerialDataDriver = new SerialData();
public Form1()
{
InitializeComponent();
Pages.Add(page1);
Pages.Add(page2);
Pages.Add(page3);
// change to first page
ChangeToPage(0);
}
private void Page1ButtonClick(object sender, EventArgs e)
{
ChangeToPage(1);
SerialDataDriver.readCard();
}
void ComPort_DataReceived(string data)
{
SerialDataDriver.ComPort.Close(); /// close ComPort
ChangeToPage(2);
}
}
您可以制作一个使用自定义 add
和 remove
访问器实现 SerialPort
事件的包装器:
using System;
using System.IO.Ports;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
private readonly SerialData _data;
public Form1()
{
InitializeComponent();
Closing += (sender, args) => { _data.Dispose(); };
_data = new SerialData(new SerialPort("COM5", 9600));
_data.DataReceived += Serial_DataReceived;
}
private void Serial_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// do something
}
}
public class SerialData : IDisposable
{
private readonly object _locker = new object();
private readonly SerialPort _port;
public SerialData(SerialPort port)
{
_port = port ?? throw new ArgumentNullException(nameof(port));
}
#region IDisposable Members
public void Dispose()
{
_port.Dispose();
}
#endregion
public event SerialDataReceivedEventHandler DataReceived
{
add
{
lock (_locker)
{
_port.DataReceived += value;
}
}
remove
{
lock (_locker)
{
_port.DataReceived -= value;
}
}
}
}
}
这是自定义事件的示例:
public class SerialData
{
public SerialPort ComPort;
public String savedText;
public delegate void Data(string message);
public event Data NewData;
private void ComPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
var serialPort = (SerialPort)sender;
var data = serialPort.ReadExisting();
savedText += data;
if (NewData != null)
{
NewData(savedText);
}
}
}
...以及如何以以下形式连接和接收它:
public Form1()
{
InitializeComponent();
Pages.Add(page1);
Pages.Add(page2);
Pages.Add(page3);
// change to first page
ChangeToPage(0);
SerialDataDriver.NewData += SerialDataDriver_NewData;
}
private void SerialDataDriver_NewData(string message)
{
if (this.InvokeRequired)
{
this.Invoke((MethodInvoker) delegate() {
SerialDataDriver_NewData(message);
});
}
else
{
// do something with "message"
this.label1.Text = message;
}
}
我正在制作一个程序来读取 NFC 卡上的值。 我有一个 class,它从连接到 NFC IC 的 EMBED 发送的串行通信中读取值。接收到数据后,程序(在主窗体中)必须更改 'page' 并处理数据。 我使用了不同的用户控件 'pages'.
我知道有多个线程,如果不使用某种 Invoke/Deleagate,我无法从不同的线程更改 GUI?但是,我不确定如何在我的代码中实现它。
这是我的代码(省略了不相关的代码):
串行数据Class
public class SerialData
{
public SerialPort ComPort;
public String savedText;
public SerialData()
{
ComPort = new SerialPort();
// set port data
ComPort.PortName = "COM5";
ComPort.BaudRate = 9600;
ComPort.DataBits = 8;
ComPort.RtsEnable = true;
ComPort.DtrEnable = true;
}
public void readCard()
{
try
{
savedText = "";
ComPort.Open();
ComPort.DataReceived += ComPort_DataReceived;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message + ex.StackTrace);
}
}
private void ComPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
var serialPort = (SerialPort)sender;
var data = serialPort.ReadExisting();
savedText += data;
}
}
Form1 代码
public partial class Form1 : Form
{
List<UserControl> Pages = new List<UserControl>();
public int CurrentPage = 0;
SerialData SerialDataDriver = new SerialData();
public Form1()
{
InitializeComponent();
Pages.Add(page1);
Pages.Add(page2);
Pages.Add(page3);
// change to first page
ChangeToPage(0);
}
private void Page1ButtonClick(object sender, EventArgs e)
{
ChangeToPage(1);
SerialDataDriver.readCard();
}
void ComPort_DataReceived(string data)
{
SerialDataDriver.ComPort.Close(); /// close ComPort
ChangeToPage(2);
}
}
您可以制作一个使用自定义 add
和 remove
访问器实现 SerialPort
事件的包装器:
using System;
using System.IO.Ports;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
private readonly SerialData _data;
public Form1()
{
InitializeComponent();
Closing += (sender, args) => { _data.Dispose(); };
_data = new SerialData(new SerialPort("COM5", 9600));
_data.DataReceived += Serial_DataReceived;
}
private void Serial_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// do something
}
}
public class SerialData : IDisposable
{
private readonly object _locker = new object();
private readonly SerialPort _port;
public SerialData(SerialPort port)
{
_port = port ?? throw new ArgumentNullException(nameof(port));
}
#region IDisposable Members
public void Dispose()
{
_port.Dispose();
}
#endregion
public event SerialDataReceivedEventHandler DataReceived
{
add
{
lock (_locker)
{
_port.DataReceived += value;
}
}
remove
{
lock (_locker)
{
_port.DataReceived -= value;
}
}
}
}
}
这是自定义事件的示例:
public class SerialData
{
public SerialPort ComPort;
public String savedText;
public delegate void Data(string message);
public event Data NewData;
private void ComPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
var serialPort = (SerialPort)sender;
var data = serialPort.ReadExisting();
savedText += data;
if (NewData != null)
{
NewData(savedText);
}
}
}
...以及如何以以下形式连接和接收它:
public Form1()
{
InitializeComponent();
Pages.Add(page1);
Pages.Add(page2);
Pages.Add(page3);
// change to first page
ChangeToPage(0);
SerialDataDriver.NewData += SerialDataDriver_NewData;
}
private void SerialDataDriver_NewData(string message)
{
if (this.InvokeRequired)
{
this.Invoke((MethodInvoker) delegate() {
SerialDataDriver_NewData(message);
});
}
else
{
// do something with "message"
this.label1.Text = message;
}
}