运行串口线程后填充列表视图

本文关键字:列表 视图 填充 串口 线程 运行 | 更新日期: 2023-09-27 18:11:45

我有一个应用程序,我通过一个按钮点击通过PC串行端口发送一个指令到一个微型。然后,微将数据流回,从而触发接收到的数据事件处理程序。这被捕获到一个字符串中。

在这一点上,我希望使用字符串的数据和填充我的列表视图框。我可以使用invoke, delegate来完成这个操作,因为我仍然在数据接收线程中。

是否有任何方法可以调用事件处理程序或简单的例程在线程退出后做到这一点,所以我不需要使用调用,委托?构建例程工作ok,如果它是由一个按钮触发,但我希望它被称为程序化完成任务。

希望这足够清楚,这是我的第一个帖子。

编辑:下面是一些示例代码——

private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    //use 28591 or("ISO-8859-1") to cover all hex bytes from 0 - 255
    serialPort1.Encoding = Encoding.GetEncoding(28591);
    //wait for download to complete by monitoring cts line
    if (HoldData == true)
    {
        while (serialPort1.CtsHolding == true) ;
        HoldData = false;
    }
    else
        Thread.Sleep(50);
    string text = serialPort1.ReadExisting();
    switch (text[0])
    {
        case '?': MemLabelUpdate(); break;
        case '>': WriteConfig(text); break;
        case '=': SealTest(text); break;
        case '<': CurrentNumber(text); break;
        default: DataDownload(text); break;
    }
}

字符串文本的第一个字节是输入内容的标识符。这反过来调用一个函数,该函数使用invoke委托方法在主表单上填充标签,因为它在数据接收线程中运行。对下载数据函数的默认调用传递文本并对其进行分类,因为这是大量事件。然后将结果传递到我的listview框的相关列中。我不想使用调用委托方法。要做到这一点,我需要退出port_datareceived线程,退出后,输入我的函数来更新列表,如下所示。我如何以编程方式触发这种事件。

private void btnDisplayData_Click(object sender, EventArgs e)
{
    int SectionStart = 10;
    int SectionEnd = 8;
    listView1.Items.Clear();
    listView1.View = View.Details;
    listView1.GridLines = true;
    //Add columns to listview
    listView1.Columns.Add("Event", 80, HorizontalAlignment.Center);
    listView1.Columns.Add("Time", 80, HorizontalAlignment.Center);
    listView1.Columns.Add("Date", 80, HorizontalAlignment.Center);
    //Print results to listview box
    ListViewItem ListItem;
    for (int i = 0; i < 10; i++)
    {
        ListItem = listView1.Items.Add(DownloadedData.Substring(SectionStart,     SectionEnd));
        SectionStart += 8;
        ListItem.SubItems.Add(DownloadedData.Substring(SectionStart, SectionEnd));
        SectionStart += 8;
        ListItem.SubItems.Add(DownloadedData.Substring(SectionStart, SectionEnd));
        SectionStart += 8;
    }
    foreach (ColumnHeader column in listView1.Columns)
    {
        column.Width = -2;
    }
}

运行串口线程后填充列表视图

看起来你真正感兴趣的事件是PinChange。所以处理它,检查CTS,然后使用BeginInvoke发送一个消息回你的UI线程,它可以清空串口缓冲区(不需要等待),解析数据,并更新控件。


进一步说明,DataReceived事件实际上在microsoft提供的System.IO.Ports.SerialPort类上是无用的。如果您有兴趣在数据到达后立即对其进行处理,请使用BeginRead和回调。

您仍然没有给出线程问题的任何细节。是在UI线程,工作线程或后台工作线程上创建的SerialPort ?SynchronizationContext很重要,如果SerialPort是在不同的线程上创建的,那么你必须使用某种机制来调用或将数据带回UI线程以显示。

最简单的解决方案可能只是调用DownloadData方法(假设该方法更新UI或调用另一个方法来更新UI):
        switch (text[0])
        {
            case '?': MemLabelUpdate(); break;
            case '>': WriteConfig(text); break;
            case '=': SealTest(text); break;
            case '<': CurrentNumber(text); break;
            default:
                if (InvokeRequired)
                    Invoke((MethodInvoker)delegate { DataDownload(text); });
                else
                    DataDownload(text);
                break;
        }

另一种技术是为接收到的数据定义自己的事件。您可以为一种或所有情况定义一个事件。您可能只需要为访问UI的代码定义一个事件,但是为所有情况添加事件可能是一个好主意,这样可以使协议更好地组件化,并将串行代码移动到单独的类中:

// Create an EventArgs based class for the data
public class DataDownloadEventArgs : EventArgs
{
    public string Data { get; set; }
    public DataDownloadEventArgs(string data)
    {
        Data = data;
    }
}
public partial class Form1 : Form
{
    // Event handler when data is downloaded
    public event EventHandler<DataDownloadEventArgs> DataDownloaded;
    // Virtual method to raise event to observers
    protected virtual void OnDataDownloaded(DataDownloadEventArgs e)
    {
        var handler = DataDownloaded;
        if (handler != null)
        {
            handler(this, e);
        }
    }
    // Form constructor
    public Form1()
    {
        InitializeComponent();
        // Add handler for the download event
        DataDownloaded += new EventHandler<DataDownloadEventArgs>(DisplayData);
    }
    // Serial port receive event
    private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        // snip...
        switch (text[0])
        {
            case '?': MemLabelUpdate(); break;
            case '>': WriteConfig(text); break;
            case '=': SealTest(text); break;
            case '<': CurrentNumber(text); break;
            default:
                DataDownload(text);
                OnDataDownloaded(new DataDownloadEventArgs(text));
                break;
        }
        // snip...
    }
    // Change btnDisplayData_Click to the following:
    private void DisplayData(object sender, DataDownloadEventArgs e)
    {
        // insert remaining code from btnDisplayData_Click
    }
}

如果你仍然对UI线程和事件有问题,你可以使用一个扩展来像这样向UI线程引发事件。这里有一篇文章可能会有所帮助,跨线程事件。