主窗体接收到串口数据后触发函数

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);
    }

}

您可以制作一个使用自定义 addremove 访问器实现 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;
    }
}