最近在寫一個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窗體不在無響應,問題成功解決!