代码之家  ›  专栏  ›  技术社区  ›  Vishnu Pradeep

跨线程调用

  •  -1
  • Vishnu Pradeep  · 技术社区  · 15 年前
    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“,提前谢谢。

    3 回复  |  直到 12 年前
        1
  •  2
  •   ljs TheVillageIdiot    15 年前

    您需要在UI线程上调用。如果在loggedin方法的顶部添加如下代码,它应该可以工作:

    if(InvokeRequired)
    {
        Invoke(new Action<object>(loggedIn), o);
        return;
    }
    
        2
  •  1
  •   Ani    15 年前

    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 直到用户界面更新完成。如果你想要更多的火而忘记,用 BeginInvoke 相反。

        3
  •  0
  •   Erik Noren    15 年前

    当您启动一个应用程序时,它是从一个线程运行的。这是主线程,有时称为UI线程(因为UI通常在启动时呈现,因此它将位于该主线程上)。

    现在,当您侦听事件时,将从新线程调用方法/委托。这是基于事件设计的结果。通常,除非您尝试在两个线程之间共享数据,否则这不是问题。这正是您的UI元素所发生的事情。在这种情况下,您的UI元素是由第一个线程创建的,但其他线程正在尝试更新其值。

    根据您的设计,您应该检查控件上是否需要IsInvokerRequired,如果需要,请使用Invoke设置新值。这将把您的调用从新线程封送到您的UI正在运行的主线程中,并允许您安全地更改控件。