2010-10-26 38 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来设置新的值。进入主线程的新线程,您的用户界面运行并可以让您安全地更改控制。