【问题标题】:C# Invoke control from different threadC# 从不同的线程调用控件
【发布时间】:2010-11-29 08:45:19
【问题描述】:

我正在开发一个使用多线程的服务器程序。问题是,有多个类和很多线程,都需要访问某个 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;
        }
    }
}

-它只能在主线程中工作。我猜它与命名空间有关,或者因为我正在使用:

Menu menu = new Menu();

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

非常感谢您的帮助。

【问题讨论】:

    标签: c# winforms multithreading invoke


    【解决方案1】:

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

    调用的正常工作方式是:

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

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

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

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

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

    【讨论】:

    • 好吧,所以不是每次都创建一个新表单,我只是做一个参考。但如果我这样做,我将不得不将 Log 方法设为静态。这意味着我必须(目前)在 Log 方法中创建一个名为 Menu 的对象。你知道怎么解决吗?
    • 最重要的是,你需要有一种与主线程通信的方式。你有两个选择。 1. 从主线程创建Menu 表单(可能是隐藏的),例如当您启动应用程序时。 2. 即时创建Menu 表单,但在不同的表单(可能是主表单)上使用Invoke。是的,您需要参考其中一种形式。您可以通过创建一个静态变量 public static Menu Instance { get; private set; } 来做到这一点,您在构造函数 Instance = this; 中设置该变量。
    • 非常感谢,成功了!我不知道我可以调用 Menu.Instance.Log("Message");
    【解决方案2】:

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

    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;
                }
            }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多