0

我现在正在使用 namedpipe 和 C# 实现网络程序。在服务器程序的 main 方法中,我启动了一个名为“ReadingMessage”的线程,用于读取来自客户端程序的消息。在这个线程中,它需要根据客户端返回的消息来改变控件的属性(文本框的文本、标签的位置等)。因此,它在此过程中出现了跨线程错误(“ReadingMesssage between UI thread”)。我发现有两种方法可以解决这个问题

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

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

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

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

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

//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的文本)不受影响也不改变。在那里,我注意到调试器Control.InvokeRequired在第二次返回 false 。真的很抱歉所有长时间的问题,因为我是程序员的新手。

仍然期待您的建议...

更新 2:

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

4

2 回答 2

2

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

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

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

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

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

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

归根结底,对于大多数简单的应用程序,主线程是唯一创建窗口的线程,因此您应该只从主线程中接触窗体和控件。

于 2012-10-23T00:48:04.007 回答
0

请张贴代码。特别是您用来打开和关闭窗口的代码。

根据您的描述,我猜您正在Application.Run()表单上运行一个循环,同时运行后台线程。

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

这只是一个猜测,没有看到代码。

于 2012-10-23T01:00:19.967 回答