【问题标题】:Populating listview after running serial port thread运行串口线程后填充listview
【发布时间】:2013-05-03 01:08:46
【问题描述】:

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

此时我希望使用字符串的数据并填充我的列表视图框。我可以使用调用、委托来执行此操作,因为我仍在接收数据的线程中。

有什么方法可以在线程退出后调用事件处理程序或简单例程来执行此操作,因此我不需要使用调用、委托?如果它由按钮触发,则构建例程可以正常工作,但我希望以编程方式调用它来完成任务。

希望够清楚,这是我的第一篇文章。

编辑:这是一些示例代码--

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;

    }
}

字符串文本的第一个字节是输入内容的标识符。这反过来又调用了一个函数,该函数使用调用委托方法填充主窗体上的标签,因为它在接收数据的线程中运行。对下载数据函数的默认调用传递文本并对其进行分类,因为这是大量事件。然后将结果传递到我的列表视图框到相关列中。我想摆脱使用调用委托方法。我需要退出 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;
    }

}

【问题讨论】:

  • 您需要澄清一个问题:您使用的是什么线程,您使用的是C# SerialPort 类,您在哪个线程上创建了SerialPort 对象。
  • 向我们展示相关代码并解释一下您希望它如何以不同的方式工作。在这里很难说出你真正想要的是什么。

标签: c# serial-port


【解决方案1】:

真正感兴趣的活动似乎是PinChange。所以处理它,检查 CTS,然后使用 BeginInvokeone 消息发送回您的 UI 线程,这可以清空串口缓冲区(无需等待)、解析数据并更新控件.


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

【讨论】:

    【解决方案2】:

    您仍然没有提供有关线程问题的任何详细信息。 SerialPort 是在 UI 线程、工作线程还是 BackgroundWorker 上创建的? 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;
            }
    

    另一种技术是为接收到的数据案例定义您自己的事件。 YouOne 可以为一个或所有案例定义一个事件。您可能只需要为将访问 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 线程,例如 this。这里有一篇文章可能也会有所帮助,Cross-Thread Events

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多