0

当有人拨打我的固定电话时,我正在使用 SerialPort 获取来电显示。我已经使用 PuTTy 软件对其进行了测试,它运行良好。

然而,我的 C# 代码抛出了一个 InvalidOperation 异常,并指出:跨线程操作无效:控件lblCallerIDTitle从创建它的线程以外的线程访问。当我尝试这样做时会发生此错误:lblCallerIDTitle.Text = ReadData;

我怎样才能解决这个问题?下面是我的代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;

namespace CallerID
{
    public partial class CallerID : Form
    {
        public CallerID()
        {
            InitializeComponent();
            port.Open();
            WatchModem();
            SetModem();
        }

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        WatchModem();
    }

    private SerialPort port = new SerialPort("COM3");
    string CallName;
    string CallNumber;
    string ReadData;

    private void SetModem()
    {
        port.WriteLine("AT+VCID=1\n");
        port.RtsEnable = true;
    }

    private void WatchModem()
    {
        port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
    }

    private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        ReadData = port.ReadExisting();
        //Add code to split up/decode the incoming data
        lblCallerIDTitle.Text = ReadData;
        Console.WriteLine(ReadData);
    }

    private void CallerID_Load(object sender, EventArgs e)
    {

    }
  }
}

我想要一个标签来显示传入的数据。谢谢

4

2 回答 2

3

您的用户控件(例如标签)必须在 UI 线程上更新,并且串行数据正在进入另一个线程。

您的两个选项是使用 Invoke() 将控件更新推送到主 UI 线程,或者让串行线程更新变量,并使用计时器控件检查该变量以更新标签。

第一个(更好的)选项的代码应该如下所示:

private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    ReadData = port.ReadExisting();
    //Add code to split up/decode the incoming data
    if (lblCallerIDTitle.InvokeRequired)
        lblCallerIDTitle.Invoke(() => lblCallerIDTitle.Text = ReadData);
    else
        lblCallerIDTitle.Text = ReadData;
    Console.WriteLine(ReadData);
}

然后标签将始终在主 UI 线程上更新。

于 2012-06-05T14:41:00.870 回答
2

Invoke从另一个线程更新 UI 时需要使用。

代替...

lblCallerIDTitle.Text = ReadData

... 和 ...

lblCallerIDTitle.Invoke(new SetCallerIdText(() => lblCallerIDTitle.Text = ReadData));

......在你班上的某个地方宣布这个之后......

public delegate void SetCallerIdText();

虽然我更喜欢这个问题的答案。

于 2012-06-05T14:47:26.190 回答