C# 串口通讯问题

我最近做了一个小软件,用C#做一个上位机通讯软件。用的是SerialPort控件。现在出现了一个问题,应为DataReceived时间在辅助线程上触发,在辅助线程上不能修复主线程上Form中控件的属性。我现在的问题是我想在DataReceived事件中启动主线程上的定时器Timer1,程序应该怎么写。(自己刚学C# 很多都不太明白)

这个线程安全检查是在.net 2.0新引入的。
两个解决办法:

1. 在程序开始运行时,设定:
System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;
这个方法是简单地禁止检查,然后就可以直接用form1.Title = "hello"这样的代码访问form1的属性。

但是这样可会引起线程安全问题。

ms在.net 2.0里推荐下面的方法:

2. 在主form中定义一个委托方法,在这个委托方法里处理主窗口的属性。
然后在其他线程里可以invoke这个委托。

如下代码:
class from1:Form
{
// 委托类型定义
public delegate void EnableTimerHandle();

// 委托成员。将在构造方法里初始化
public EnableTimerHandle dgEnableTimer;

public Form1()
{
InitializeComponent();

// 初试化成员
this.dgEnableTimer = new EnableTimerHandle(EnableTimer);
}

// 被委托的方法
private void EnableTimer()
{
this.Timer1.Enable = true;
// 如果有其他操作,请一次完成。
}

// 线程工作函数
private void ThreadWork(object oPara)
{
// ...
// ...

// 需要修改主窗口的属性了
this.Invoke(this.dlgtChangeVolume);

// ... ...

}
}
温馨提示:内容为网友见解,仅供参考
第1个回答  2010-05-11
在.NET中如需在非UI线程中改变UI控件属性时,CLR会抛出异常,提示无法在非UI线程中更新界面上的控件(Cross-thread operation not valid)。一般情况下有两种解决办法。第一种就是设置Control的静态属性CheckForIllegalCrossThreadCalls为False,如下:
public Form1()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
}

private void button1_Click(object sender, EventArgs e)
{
Thread thread = new Thread(() =>
{
for (int i = 0; i < 100000; i++)
{
label1.Text = i.ToString();
label1.Refresh();
}
});

thread.Start();
}
另一种办法,就是使用委托,根据控件的InvokeRequired属性判断当前控件的更新操作是否是在另一个线程中。如果是,
则使用委托进行方法调用并更新控件。但是这种方法有个缺点,就是需要针对每个控件的属性设置方式创建一些单独的委托和方法,这些委托和方法仅仅是在解决跨线程操作的时候使用。比如,你在另一个线程中需要修改某个label的text时,你就需要创建一个SetLabelText方法,假设你还需要更新TextBox的text,那么你还需要另外创建一个SetTextBoxText方法。
通过下面的委托和方法的定义,我们实现了“一次定义,多次使用”。请看:

private delegate void ParameterizedControlUpdate(params object[] args);
private delegate void ControlUpdateDelegate(Component c,
ParameterizedControlUpdate callback,
params object[] args);

private void DelegatedControlUpdate(Component c,
ParameterizedControlUpdate callback,
params object[] args)

{
Control target = (c is Control) ? (c as Control) : this;
if (target.InvokeRequired)
{
ControlUpdateDelegate d = DelegatedControlUpdate;
target.Invoke(d, new object[] { c, callback, args });
}
else
{
callback(args);
}
}
上面的例子可以改为:
private void button1_Click(object sender, EventArgs e)

{
Thread thread = new Thread(() =>
{
for (int i = 0; i < 100000; i++)
{
DelegatedControlUpdate(label1, args =>
{
label1.Text = (string)args[0];
label1.Refresh();
}, i.ToString());
}
});
thread.Start();
}
第2个回答  2010-05-11
在DataReceived的代码段加timer1.enabled=true;
第3个回答  2010-05-11
使用Invoke函数,从辅助线程中唤醒主线程中的函数即可,唤醒的函数中要求打开timer
第4个回答  2020-03-04
还是觉得用timer比较好
多线程
补充
我做过两个串口的程序
有时候数据非常快
我觉得5ms后仍未接收到下一个字节数据,此时开始处理缓冲区中的数据这种方法就不是很好
在线程很多的情况下
timer不好做
为什么不换换串口处理的方式呢
比如说while(bytetoread>**)时每次处理一定数量
或者判断包头包尾什么的
相似回答