将另一个线程中的控制属性更改为主 (UI) 线程之外



我现在正在使用namedpipe和C#实现网络程序。在服务器程序的主方法中,我启动了一个名为"ReadingMessage"的线程,该线程是从客户端程序读取消息。在此线程中,它需要根据从客户端返回的消息更改控件的属性(文本框的文本、标签的位置等)。因此,它在此过程中存在跨线程错误("UI 线程之间的阅读消息")。我发现有两种方法可以解决这个问题

  1. 使用委托调用控件
  2. Form.CheckForIllegalCrossThreadCalls = false;

我测试了它们,但有一个问题。当窗体首次启动时,控件的属性将更改,没有任何错误。当窗体关闭并第二次重新启动时,控件的属性不会更改,也不会显示任何错误消息。我捕获了指示控件属性更改的代码的断点。代码运行顺利,但问题仍然存在。

我不知道这是什么问题。因此,如果有人知道这个问题,请建议我...

更新:(发布代码并纠正我第一个问题中的一些错误)

线程不在服务器程序的主方法中。我错了,因为我想简短地描述我的问题。现在,我将更详细地描述我的问题。服务器程序的主形式中有一个按钮单击事件。

//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();
}
}

这就是出现问题的所有代码。当"另一个表单"第一次打开时,没关系。但它第二次再次打开,控件的属性(TextBox1 的文本)不会受到影响,也不会更改。在那里,我注意到调试器在第二次返回 falseControl.InvokeRequired。真的很抱歉大家的长问题,因为我是程序员的新手。

仍然期待您的建议...

更新 2:

最后,我尝试了所有方法,但没有给出最佳解决方案。因此,我想建议大家避免这种情况,当你遇到像我这样的情况时,用另一个概念重写你的一些代码。

在后台线程中,应使用Control.InvokeRequiredControl.Invoke以使 UI 线程执行更新 UI 的代码。

仅允许 UI 线程"触摸"控件属性,因此后台线程无法更新它们。

更具体地说,如果您对更多详细信息感兴趣:在 Windows 中,每个窗体和控件通常都有一个或多个与之关联的 HWND。HWND 是表示 Windows 窗口的 Windows 操作系统对象的句柄。

每个 HWND 始终与特定线程相关联,即创建它的线程。发送到该 HWND 的任何 Windows 消息都将到达该线程的消息队列,并且必须由该线程的消息循环处理。

当您对 Controls 方法进行看似无害的调用时,这些方法的实现有时可能会破坏并在后台创建 HWND(例如,为 Menu 控件创建子菜单或向工具栏控件添加按钮)。现在,如果要从不同的线程进行此类调用,则最终将得到属于不同线程的 HWND,并且控件消息的处理将被破坏。

出于这个原因,除了创建控件的 HWND 的线程(例如调用 'Control.CreateControl() 的线程)之外,禁止任何线程访问控件的方法。

最重要的是,对于大多数简单的应用程序,主线程是唯一创建窗口的线程,因此您应该仅从主线程接触窗体和控件。

请发布代码。特别是用于打开和关闭窗口的代码。

从您的描述中,我猜测您在运行后台线程时正在表单上运行Application.Run()循环。

然后,也许您正在关闭表单并打开一个新表单,而无需运行消息循环。所以Control.Invoke返回,但 UI 线程不会调用回调(这不是抽取消息)。

这只是没有看到代码的猜测。

最新更新