C# Invoke control from different thread

假装没事ソ 提交于 2021-01-27 23:24:18

问题


I'm working on a server program, which uses multithreading. The problem is, there are multiple classes and alot of threads, which all need access to a certain TextBox. (tbLog)

The method (Log) looks like like this:

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

Ofcourse I've tried other things, and this is not one of my better tries. The problem is, even if I call the method from another thread/class like this:

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

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

            return true;
        }
    }
}

-it will only work from the main thread. And I guess it has something to do with the namespace or because I'm using:

Menu menu = new Menu();

The answer is probably obvious, but I'm not seeing it. sigh

Help would be very much apreciated.


回答1:


Why are you creating a new form every time you log a message?

How the invoke normally works is:

  1. With e.g. application startup, you create a form which displays the log. This is on the main thread;

  2. Then, when you need to log, you get a reference to that form;

  3. Then, with Invoke, you send the log to that form.

If you do need to create the form on the fly, the Invoke should also be used to create the new form. You can do this by getting a reference to your main form and use Invoke on that form to also create the form.

The problem you are seeing is because you are creating the Menu form on a non-UI thread which does not have a message loop.




回答2:


The answer is simpler than you think (you're missing a return, so it always runs from the wrong thread). You can simplify your code slightly:

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


来源:https://stackoverflow.com/questions/4302089/c-sharp-invoke-control-from-different-thread

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!