我正在研究一个使用多线程的服务器程序。问题是,有多个类和很多线程,都需要访问某个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();
答案可能很明显,但我没有看到。 叹息
帮助会非常渺茫。
答案 0 :(得分:3)
为什么每次记录消息时都要创建新表单?
调用通常如何工作:
例如应用程序启动时,您将创建一个显示日志的表单。这是主线程;
然后,当您需要登录时,您会获得对该表单的引用;
然后,使用Invoke
,您将日志发送到该表单。
如果您确实需要动态创建表单,还应使用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;
}
}
}