最近在写一个TCP通信程序,自定义了一个通信类TCPclient,用于客户端异步接收和发送网络消息。
TCPclient中定义了一个接收到新的网络消息事件:
1 //收到新消息事件 2 public delegate void receiveNewNetworkMsgHandler( string networkMSG); 3 public event receiveNewNetworkMsgHandler receiveNewNetworkMsg;
在外部的窗体中订阅了此事件:
void thisClient_receiveNewNetworkMsg( string networkMSG);
起初是直接在这个函数中读取网络消息,并解析命令,然后触发窗体的LoginSuccess事件,LoginSuccess事件的委托函数会New一个 main 窗体
但是问题是这个new的main窗体总是无响应。
经过很长时间的摸索,终于得出以下结论
在自定义类中定义并触发事件,那么UI中的事件处理代码也就工作在自定义类线程中,访问UI中控件需要invoke
在此之前,我一直认为事件处理函数在哪个类,自然运行的时候就在相应的线程中执行,至此才明白错在哪里。
根据这条结论,自然就不能直接在thisClient_receiveNewNetworkMsg函数中直接进行命令的解析以及触发LoginSuccess事件,
所以现在在thisClient_receiveNewNetworkMsg函数中进行如下更改:
1 public delegate void NetMsgDealHandler(string str); 2 void thisClient_receiveNewNetworkMsg( string networkMSG) 4 { 5 NetMsgDealHandler newMSG = new NetMsgDealHandler(NetMsgDeal); 6 BeginInvoke(newMSG, networkMSG); 7 }
1 void NetMsgDeal(string networkMSG) { 2 XmlDocument xmldoc = new XmlDocument(); 3 try { xmldoc.LoadXml(networkMSG); } 4 catch (Exception ex) { MessageBox.Show(string.Format("XML加载错误({1}):{0}", networkMSG, ex.Message)); return; } 5 XmlElement rootElement = xmldoc.ChildNodes[0] as XmlElement; 6 XmlElement SecElement = rootElement.ChildNodes[0] as XmlElement; 7 switch (SecElement.Name) { 8 case "login": { 10 if (SecElement.SelectSingleNode("cmd").InnerText == "2") { 11 if (SecElement.SelectSingleNode("isSuccess").InnerText == "True") { 12 //触发LoginSuccess事件 13 this.loginSuccess(this); 14 } 15 else { 16 //触发loginFailed事件 17 this.LoginFailed(this); 18 } 19 } 21 } break;22 //此处省略若干行 23 default: { MessageBox.Show(string.Format("得到无法处理的消息:{0}", networkMSG)); return; } 24 } 25 }
现在再次执行main窗体不在无响应,问题成功解决!