我是这么处理的:有一个utils类,实现接受/发送的代码,需要更新UI的时候,触发一个事件(先定义好delegate)。UI的类中类似于这样的代码:myutils.BeginReceiving += new ReceivingHandler(OnBeginReceiving); ...不要直接操作界面。如果你的UI有多个,那么在一个统一的点上(如mainform上),对这些UI中的对于utils的事件响应,统一在这里登记处理。
比如说你的主界面form叫做mainform,上面有两个自己的UI控件,假设叫:MasterUI和DetailUI。 你的数据处理类,叫做DBUtils。DBUtils的处理方法可能是这样:public class DBUtils{ public void MyMethod(){ // 开始处理 if(null != BeginReceiving)BeginReceiving(this,new EventArgs()); // 循环什么咚咚 for(int i=0;i<MAX;i++){ // 通知外面,处理到第i个数据了 if(null != Receiving)Receiving(this,new YourEventArgs(i)); } // 循环结束了 if(null != EndReceiving)EndReceiving(this,new EventArgs()); } }然后在你的两个UI中,可能都需要这个Utils的这个方法,那么,代码可能是这样:public class MasterUI : SomeControl{ public void MasterUI(DBUtils utils){ utils = new DBUtils(); utils.BeginReceiving += new EventHandler(OnBeginReceiving); utils.Receiving += new MyReceivingEventHandler(OnReceiving); utils.EndReceiving += new EventHandler(OnEndReceiving); } private void OnBeginReceiving(object sender, EventArgs e){ // 这段代码你即可以上浮到mainform上,形如下面这行,也可以在这里直接处理。 // if(null != BeginReceiving)BeginReceiving(this,new EventArgs()); messageToDrawing = "Begin receiving..."; Invalidate(); } // 其他代码类似 }我就是juqiang1975,那是我的马甲。
改为使用this.Invoke()应该没问题,我一直都是这样使用的。
thx a lot!那个通讯类首先开启一个线程,等待进行接收数据: // Start the receiver thread. this.rxThread = new Thread(new ThreadStart(ReceiveThread)); this.rxThread.Name = "COMReceiver"; this.rxThread.Priority = ThreadPriority.AboveNormal; this.rxThread.Start();// Wait for receive thread to start. this.recvrEvent.WaitOne(500, false);然后在这个ReceiveThread方法里面进行事件的触发: private void ReceiveThread() { // Create locals. uint firedEvent = 0; //...
// Create thread signal (initial state is non-signaled). AutoResetEvent signal = new AutoResetEvent(false); //... // Signal the main thread that // the receive thread is started. this.recvrEvent.Set(); try { while(true) { // Arm the event monitoring mask. if(this.events.Set(this.port.Handle, Win32Events.EV_DEFAULT)) { // 等待事件发生 this.events.Wait(this.port.Handle, signal); // Get mask of fired events. firedEvent = this.events.GetMask; //..... // Receive event 接收数据的事件--接收到一个字节就触发 if(((firedEvent & Win32Events.EV_RXCHAR) != 0) && (this.immediate)) { do { nBytes = 0; //从串口读取数据 if(this.port.Read(buf, 1, out nBytes, this.rxOvr.MemPtr)) { if(nBytes == 1) //调用执行处理接收到数据的方法 this.OnRxChar(buf);
在串口类里面:// Delegate class declarations. public delegate void VoidFunc(); public delegate void BoolFunc(bool b); public delegate void StrnFunc(string s); public delegate void ByteFunc(byte[] b);/// <summary> /// This structure contains one delegate method for each override event /// method in the serial port base class. Each delegate provides a hook /// that can be used by any application that wishes to connect to the /// asynchronous OnXXX methods. /// </summary> public struct WithEvents { public VoidFunc Break; public VoidFunc TxDone; public StrnFunc Error; public ByteFunc RxChar; public BoolFunc CtsSig; public BoolFunc DsrSig; public BoolFunc RlsdSig; public BoolFunc RingSig; }... public class SerialPort { private WithEvents ev; private ManualResetEvent recvrEvent;//接收数据线程启动的信号 private ManualResetEvent writeEvent; private Thread rxThread; //接收数据的线程 public SerialPort(WithEvents ev) { this.ev = ev; } //打开串口 protected bool Open(...) //就是我前面调用的this.Port.Open { ... this.recvrEvent = new ManualResetEvent(false); ... //启动线程 this.rxThread = new Thread(new ThreadStart(ReceiveThread)); this.rxThread.Priority = ThreadPriority.AboveNormal; this.rxThread.Start(); // Wait for receive thread to start. this.recvrEvent.WaitOne(500, false); //成功打开了串口
问题还是会出在这里的: internal void OnRecvI(byte[] b) { //我在这里处理接收到的字节:b //将收到的b显示到界面上 <-------------如何控制主线程的界面? }
或者你更换一种方式:这段代码更改为:放在一个线程里面。而对于SerialPort类,内部不开线程。即:线程放到调用者那里处理。this.Func = new WithEvents();
this.Func.Error = new StrnFunc(this.OnError); this.Func.RxChar = new ByteFunc(this.OnRecvI);//OnRxChar this.Func.CtsSig = new BoolFunc(this.OnCts); this.Func.DsrSig = new BoolFunc(this.OnDsr); this.Func.RlsdSig = new BoolFunc(this.OnRlsd); this.Func.RingSig = new BoolFunc(this.OnRing); this.Port = new SerialPort(this.Func); if(this.Port.IsOpen == false) this.Port.Open(this.PortIndex);//打开串口
问题依旧
...不要直接操作界面。如果你的UI有多个,那么在一个统一的点上(如mainform上),对这些UI中的对于utils的事件响应,统一在这里登记处理。
就如:
myutils.BeginReceiving += new ReceivingHandler(OnBeginReceiving);
我收到一条数据后,就立刻回发一条,以表明接收到数据了。
希望 juqiang1975 和 reformer能说得详细一些,迷惑中...
你的数据处理类,叫做DBUtils。DBUtils的处理方法可能是这样:public class DBUtils{
public void MyMethod(){
// 开始处理
if(null != BeginReceiving)BeginReceiving(this,new EventArgs()); // 循环什么咚咚
for(int i=0;i<MAX;i++){
// 通知外面,处理到第i个数据了
if(null != Receiving)Receiving(this,new YourEventArgs(i));
} // 循环结束了
if(null != EndReceiving)EndReceiving(this,new EventArgs());
}
}然后在你的两个UI中,可能都需要这个Utils的这个方法,那么,代码可能是这样:public class MasterUI : SomeControl{
public void MasterUI(DBUtils utils){
utils = new DBUtils();
utils.BeginReceiving += new EventHandler(OnBeginReceiving);
utils.Receiving += new MyReceivingEventHandler(OnReceiving);
utils.EndReceiving += new EventHandler(OnEndReceiving);
} private void OnBeginReceiving(object sender, EventArgs e){
// 这段代码你即可以上浮到mainform上,形如下面这行,也可以在这里直接处理。
// if(null != BeginReceiving)BeginReceiving(this,new EventArgs());
messageToDrawing = "Begin receiving...";
Invalidate();
} // 其他代码类似
}我就是juqiang1975,那是我的马甲。
// Start the receiver thread.
this.rxThread = new Thread(new ThreadStart(ReceiveThread));
this.rxThread.Name = "COMReceiver";
this.rxThread.Priority = ThreadPriority.AboveNormal;
this.rxThread.Start();// Wait for receive thread to start.
this.recvrEvent.WaitOne(500, false);然后在这个ReceiveThread方法里面进行事件的触发:
private void ReceiveThread()
{
// Create locals.
uint firedEvent = 0;
//...
// Create thread signal (initial state is non-signaled).
AutoResetEvent signal = new AutoResetEvent(false);
//... // Signal the main thread that
// the receive thread is started.
this.recvrEvent.Set(); try
{
while(true)
{
// Arm the event monitoring mask.
if(this.events.Set(this.port.Handle, Win32Events.EV_DEFAULT))
{
// 等待事件发生
this.events.Wait(this.port.Handle, signal); // Get mask of fired events.
firedEvent = this.events.GetMask;
//.....
// Receive event 接收数据的事件--接收到一个字节就触发
if(((firedEvent & Win32Events.EV_RXCHAR) != 0) && (this.immediate))
{
do
{
nBytes = 0;
//从串口读取数据
if(this.port.Read(buf, 1, out nBytes, this.rxOvr.MemPtr))
{
if(nBytes == 1)
//调用执行处理接收到数据的方法
this.OnRxChar(buf);
}
} while(nBytes > 0);
//...
}
}
}
}
catch(Exception e)
{
//....
}
}
我正是像你这样的方式写的。Control.Invalidate()是必须调用的么?
是啊,我也是如你说的那样的做法。
接收数据的线程就是触发事件的,在这个事件里面处理接收到的数据,并且显示到界面上的。能给我一些代码么?
UI:private WithEvents Func;//处理发生事件的结构体//初始化端口
private void InitSerial()
{
this.Func = new WithEvents();
this.Func.Error = new StrnFunc(this.OnError);
this.Func.RxChar = new ByteFunc(this.OnRecvI);//OnRxChar
this.Func.CtsSig = new BoolFunc(this.OnCts);
this.Func.DsrSig = new BoolFunc(this.OnDsr);
this.Func.RlsdSig = new BoolFunc(this.OnRlsd);
this.Func.RingSig = new BoolFunc(this.OnRing);
this.Port = new SerialPort(this.Func);
if(this.Port.IsOpen == false)
this.Port.Open(this.PortIndex);//打开串口
...
}
/// <summary>
/// 当接收到数据时所作的处理
/// </summary>
internal void OnRecvI(byte[] b)
{ //我在这里处理接收到的字节:b
//将收到的b显示到界面上
}
static void Main()
{
Application.Run(new Form1());
}
void thread_show()
{
while(true)
{
textBox1.AppendText(System.DateTime.Now.ToString());
textBox1.ScrollToCaret();
}
}
private void button1_Click(object sender, System.EventArgs e)
{
x = new Thread(new ThreadStart(thread_show));
x.Start();
}
private void button2_Click(object sender, System.EventArgs e)
{
x.Abort();
}
public delegate void VoidFunc();
public delegate void BoolFunc(bool b);
public delegate void StrnFunc(string s);
public delegate void ByteFunc(byte[] b);/// <summary>
/// This structure contains one delegate method for each override event
/// method in the serial port base class. Each delegate provides a hook
/// that can be used by any application that wishes to connect to the
/// asynchronous OnXXX methods.
/// </summary>
public struct WithEvents
{
public VoidFunc Break;
public VoidFunc TxDone;
public StrnFunc Error;
public ByteFunc RxChar;
public BoolFunc CtsSig;
public BoolFunc DsrSig;
public BoolFunc RlsdSig;
public BoolFunc RingSig;
}...
public class SerialPort
{
private WithEvents ev;
private ManualResetEvent recvrEvent;//接收数据线程启动的信号
private ManualResetEvent writeEvent;
private Thread rxThread; //接收数据的线程
public SerialPort(WithEvents ev)
{
this.ev = ev;
}
//打开串口
protected bool Open(...) //就是我前面调用的this.Port.Open
{
...
this.recvrEvent = new ManualResetEvent(false);
...
//启动线程
this.rxThread = new Thread(new ThreadStart(ReceiveThread));
this.rxThread.Priority = ThreadPriority.AboveNormal;
this.rxThread.Start();
// Wait for receive thread to start.
this.recvrEvent.WaitOne(500, false);
//成功打开了串口
}
private void ReceiveThread()
{
//接收数据
//触发事件
...
this.OnRxChar(buf);
}
}
internal void OnRecvI(byte[] b)
{ //我在这里处理接收到的字节:b
//将收到的b显示到界面上 <-------------如何控制主线程的界面?
}
this.Func.Error = new StrnFunc(this.OnError);
this.Func.RxChar = new ByteFunc(this.OnRecvI);//OnRxChar
this.Func.CtsSig = new BoolFunc(this.OnCts);
this.Func.DsrSig = new BoolFunc(this.OnDsr);
this.Func.RlsdSig = new BoolFunc(this.OnRlsd);
this.Func.RingSig = new BoolFunc(this.OnRing);
this.Port = new SerialPort(this.Func);
if(this.Port.IsOpen == false)
this.Port.Open(this.PortIndex);//打开串口