2010-10-26 72 views
-1
using System; 
using System.Windows.Forms; 
using agsXMPP; 
using System.Text; 
namespace iTalk2 
{ 
    public partial class Main : Form 
    { 
     agsXMPP.XmppClientConnection objXmpp; 

     public Main() 
     { 
      InitializeComponent(); 
     } 


     private void Form1_Load(object sender, EventArgs e) 
     { 

      Console.WriteLine("Logging in. Please wait..."); 
      Console.ReadLine(); 
      objXmpp = new agsXMPP.XmppClientConnection(); 
      agsXMPP.Jid jid = null; 
      jid = new agsXMPP.Jid("username" + "@gmail.com"); 
      objXmpp.Password = "password"; 
      objXmpp.Username = jid.User; 
      objXmpp.Server = jid.Server; 
      objXmpp.AutoResolveConnectServer = true; 

      try 
      { 
       objXmpp.OnMessage += messageReceived; 
       objXmpp.OnAuthError += loginFailed; 
       objXmpp.OnLogin += loggedIn; 
       objXmpp.Open(); 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine(ex.Message); 
       Console.ReadLine(); 
      } 
     } 

     private void messageReceived(object sender, agsXMPP.protocol.client.Message msg) 
     { 
      string[] chatMessage = null; 
      chatMessage = msg.From.ToString().Split('/'); 
      agsXMPP.Jid jid = null; 
      jid = new agsXMPP.Jid(chatMessage[0]); 
      agsXMPP.protocol.client.Message autoReply = null; 
      autoReply = new agsXMPP.protocol.client.Message(jid, agsXMPP.protocol.client.MessageType.chat, "This is a test"); 
      objXmpp.Send(autoReply); 
     } 

     private void loginFailed(object o, agsXMPP.Xml.Dom.Element el) 
     { 
      Console.WriteLine("Login failed. Please check your details."); 
     } 

     private void loggedIn(object o) 
     { 
      Console.WriteLine("Logged in and Active."); 
      lblStatus.Text = "Online"; 
     } 

     private void txtUsername_TextChanged(object sender, EventArgs e) 
     { 

     } 

     private void label1_Click(object sender, EventArgs e) 
     { 

     } 

     private void label2_Click(object sender, EventArgs e) 
     { 

     } 

     private void txtPassword_TextChanged(object sender, EventArgs e) 
     { 

     } 

     private void btnlogin_Click(object sender, EventArgs e) 
     { 

     } 

    } 

} 

此代碼不能正常工作。函數'loggedIn(object o)'不起作用。它說lblStatus(這是一個標籤)在另一個線程上。錯誤窗口顯示「跨線程操作無效:從其創建線程以外的線程訪問控制'lblStatus'」。提前致謝。跨線程調用

+1

的可能重複的[交線程操作無效:從比它創建的線程以外的線程訪問控制](http://stackoverflow.com/questions/142003/cross-thread-operation-not-有效控制 - 從線程訪問 - 除此之外) – spender 2010-10-26 20:43:42

+0

你甚至做過搜索嗎? – spender 2010-10-26 20:43:58

+0

是的,我沒有搜查過,但我無法理解其他線程。我是編程新手。 – vishnu 2010-10-26 22:19:36

回答

2

您需要調用UI線程上的呼叫。如果您按如下的方法的loggedIn的頂部添加代碼,它應該工作: -

if(InvokeRequired) 
{ 
    Invoke(new Action<object>(loggedIn), o); 
    return; 
} 
+0

。你能解釋發生了什麼嗎? – vishnu 2010-10-26 22:24:46

+0

當然。在WinForm應用程序中,有一個專門處理所有UI的線程。所有操作都發生在該線程中,除非您啓動一個單獨的線程來執行其他操作。 loggedIn在另一個線程上被回調,所以它必須讓UI線程運行它才能更新標籤。 InvokeRequired是Forms的一個屬性,用於指示您是否在UI線程中(如果不是),則必須在原始線程上調用該調用。正如@Ani指出的那樣(即直到完成才完成),你可以使用BeginInvoke在後臺執行此操作。 – ljs 2010-10-27 13:22:37

+0

(繼續從上面...),但在這種情況下,只是更新標籤,似乎沒有必要,除非這個其他線程需要做其他工作。唷! – ljs 2010-10-27 13:26:13

1

WinForms的設計使控制必須只能在UI線程上操作,該線程是運行管理控件的消息循環的線程。

試試這個:

private void loggedIn(object o) 
{ 
    Console.WriteLine("Logged in and Active."); 
    Action act =() => lblStatus.Text = "Online"; 
    Invoke(act); 
} 

如果您的應用程序是這樣的,這個方法可以在UI線程或單獨的工作線程上調用,你會爲InvokeRequired(只是更好的測試:我是在控件的UI線程上?)並適當地處理結果。例如,

private void loggedIn(object o) 
{ 
    if(InvokeRequired) 
     Invoke(new Action<object>(loggedIn), o);   
    else 
    { 
     Console.WriteLine("Logged in and Active."); 
     lblStatus.Text = "Online";   
    } 
} 

注意Invoke直到UI更新完成。如果你想要更多的東西,請使用BeginInvoke

+0

PLS解釋這兩個線 動作ACT =()=> lblStatus.Text = 「在線」; Invoke(act); – vishnu 2010-10-26 22:25:42

+0

通過lambda表達式創建一個類型爲「Action」的委託,然後在UI線程上調用它。它運作了 – Ani 2010-10-26 22:28:02

0

當您啓動它從一個單獨的線程運行的應用程序。這是主線程,有時稱爲UI線程(因爲UI通常會在啓動時呈現,因此它將會在該主線程中)。

現在,當您聽取事件時,您的方法/委託將來自新的線程調用。這是基於事件的設計的結果。通常這不是一個問題,除非你想兩個線程之間共享數據。這是你的UI元素究竟發生了什麼。在這種情況下,你的UI元素都由你的第一個線程創建,但其他線程試圖更新它的值

鑑於你的設計,你應該檢查控件上的IsInvokeRequired,如果是的話,使用Invoke來設置新的值。進入主線程的新線程,您的用戶界面運行並可以讓您安全地更改控制。