问题
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:
With e.g. application startup, you create a form which displays the log. This is on the main thread;
Then, when you need to log, you get a reference to that form;
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