使用SerialPort C#的来电显示

时间:2012-06-05 14:32:28

标签: c# winforms

当有人拨打固定电话时,我正在使用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)
    {

    }
  }
}

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

2 个答案:

答案 0 :(得分: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线程上更新。

答案 1 :(得分:2)

从其他线程更新UI时,您需要使用Invoke

替换...

lblCallerIDTitle.Text = ReadData

...与......

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

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

public delegate void SetCallerIdText();

虽然我更喜欢this question的答案。