我现在正在使用namedpipe和C#实现网络程序。在服务器程序的main方法中,我启动了一个名为“ReadingMessage”的线程,它从客户端程序中读取消息。在此线程中,它需要根据客户端返回的消息更改控件的属性(文本框的文本,标签的位置等)。因此,它在此过程中存在交叉线程错误(“UI线程之间的ReadingMesssage”)。我发现有两种方法可以解决这个问题
我测试了它们,但有一个问题。当表单首次启动时,控件的属性会更改而不会出现任何错误。当窗体关闭并再次作为第二次启动时,控件的属性不会更改,并且不会显示任何错误消息。我将断点捕获到指示控件属性发生更改的代码中。代码运行顺利,但问题仍然存在。
我不知道那是什么问题。因此,如果有人知道这个问题,请建议我......
更新:(在我的第一个问题中发布代码并纠正一些错误)
线程不在服务器程序的主方法中。我错了,因为我想简短地描述一下我的问题。现在,我将更详细地描述我的问题。服务器程序的主要形式中有一个按钮单击事件。
//Main Form
public partial class MainForm : Form
{
private void btnButton_Click(object sender, EventArgs e)
{
AnotherForm aform = new AnotherForm(); //This is the form where threading run
aform.show();
}
}
//AnotherForm
public partial class AnotherForm : Form
{
private void CargoLoading_Load(object sender, EventArgs e)
{
(new System.Threading.Thread(readingMessage)).Start(myPipe);
}
}
private void readingMessage(Object myPipeObject) //Read the messages send from the client machine
{
while (true)
{
//Code of serverstream
SetTextofTextBox1("AnyText"); //Code where the properties of control are instructed to change
}
}
private void SetTextofTextBox1(string text)
{
if (this.txtTextBox1.InvokeRequired) //the debugger return false at second time of this form is opened
{
SetTextCallback d = new SetTextCallback(SetTextofTextBox1);
this.Invoke(d, new object[] { text });
}
else
{
this.txtTextBox1.Text = text;
this.txtTextBox1.Update();
}
}
这就是出现问题的所有代码。当“AnotherForm”第一次打开时,没关系。但它第二次再次打开,控件的属性(TextBox1的文本)不受影响而且没有改变。在那里,我注意到调试器第二次返回false Control.InvokeRequired
。对于所有长期问题都非常抱歉,因为我是程序员的新手。
仍然期待你的建议......
更新2:
最后我尝试了所有的方法,但它并没有出来最好的解决方案。因此,我想建议所有人只要避免这种情况,并在遇到像我这样的情况时,在另一个概念中重写一些代码。
答案 0 :(得分:2)
在后台线程中,您应该使用Control.InvokeRequired
和Control.Invoke
以使UI线程执行更新UI的代码。
只允许UI线程“触摸”控件属性,因此后台线程无法更新它们。
更具体地说,如果您对更多细节感兴趣:在Windows中,每个表单和控件通常都有一个或多个与之关联的HWND。 HWND是表示Windows窗口的Windows操作系统对象的句柄。
每个HWND始终与特定线程(创建它的线程)相关联。发送到该HWND的任何Windows消息都将到达该线程的消息队列,并且必须由该线程的消息循环处理。
当您对Controls方法进行看似无辜的调用时,这些方法的实现有时可能会破坏并创建HWND(例如,为Menu控件创建子菜单或向工具栏控件添加按钮)。现在,如果你要从不同的线程进行这样的调用,你最终会得到属于不同线程的HWND,并且你的控件消息的处理将被破坏。
由于这个原因,除了创建控件的HWND的线程(例如,调用了`Control.CreateControl()的线程)之外的任何线程都禁止对控件方法的所有访问。
在底线中,对于大多数简单的应用程序,主线程是唯一创建窗口的线程,因此您应该仅从主线程触摸表单和控件。
答案 1 :(得分:0)
请发布代码。特别是用于打开和关闭窗口的代码。
从您的描述中我猜测您在运行后台线程时在表单上运行Application.Run()
循环。
然后,您可能正在关闭表单并打开一个新表单,而不运行消息循环。所以Control.Invoke
返回,但UI线程没有调用回调(不抽取消息)。
在没有看到代码的情况下,这只是猜测。