当有人拨打固定电话时,我正在使用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)
{
}
}
}
我想要一个标签来显示传入的数据。感谢
答案 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的答案。