C#从不同的线程调用控件

时间:2010-11-29 08:45:20

标签: c# winforms multithreading invoke

我正在研究一个使用多线程的服务器程序。问题是,有多个类和很多线程,都需要访问某个TextBox。 (tbLog)

方法(Log)如下所示:

using System;
using System.Windows.Forms;
using System.ComponentModel;

namespace Server
{
    public delegate void Logs(string message);

    public partial class Menu : Form
    {    
        public Menu()
        {
            InitializeComponent();
        }

        public void Log(string message)
        {
            if (this.tbLog.InvokeRequired)
                this.tbLog.BeginInvoke(new MethodInvoker(delegate() { tbLog.Invoke(new Logs(Log)); }
            )); 
            else
                this.tbLog.Text += DateTime.Now + ": " + message + Environment.NewLine;
        }
    }
}

当然我已尝试过其他事情,这不是我最好的尝试之一。问题是,即使我从另一个线程/类中调用该方法,如下所示:

namespace Server.Connections
{
    class packetSend
    {
        static bool sendPacket(string rawPacket)
        {
            Menu menu = new Menu();

            menu.Log("I'm a message");

            return true;
        }
    }
}

-it只能在主线程中使用。我想这与命名空间有关,或者因为我正在使用:

Menu menu = new Menu();

答案可能很明显,但我没有看到。 叹息

帮助会非常渺茫。

2 个答案:

答案 0 :(得分:3)

为什么每次记录消息时都要创建新表单?

调用通常如何工作:

  1. 例如应用程序启动时,您将创建一个显示日志的表单。这是主线程;

  2. 然后,当您需要登录时,您会获得对该表单的引用;

  3. 然后,使用Invoke,您将日志发送到该表单。

  4. 如果您确实需要动态创建表单,还应使用Invoke来创建新表单。您可以通过获取对主表单的引用并使用该表单上的Invoke来创建表单来完成此操作。

    您遇到的问题是因为您在没有消息循环的非UI线程上创建Menu表单。

答案 1 :(得分:0)

答案比你想象的要简单(你错过了一个返回,所以它总是从错误的线程运行)。您可以稍微简化一下代码:

namespace Server
{
    public delegate void Logs(string message);

    public partial class Menu : Form
    {
        public Menu()
        {
            InitializeComponent();
        }

        private void InitializeComponent()
        {
            throw new NotImplementedException();
        }

        public void Log(string message)
        {
            if (InvokeRequired)
            {
                Invoke(new Action<string>(Log), message);
                return;
            }
            else
            {
                this.tbLog.Text += DateTime.Now + ": " + message + Environment.NewLine;
            }
        }
}