【问题标题】:C# winforms GUI will not accept data from other threadsC# winforms GUI 不会接受来自其他线程的数据
【发布时间】:2015-02-02 14:46:47
【问题描述】:

下面是我在运行 Winforms GUI 的线程中的 while(true) 循环中运行的函数。 我设置了一个按钮来将文本数据放入 inBuffer 对象中。这总是有效的,但是当我从另一个线程放入缓冲区对象时,会在 Console.out.WriteLine 语句中检测、提取和打印数据,但它永远不会出现在 Display (textBox) 对象中

public void put()
    {   
        string strDisplayMe = ModemKind.MainClass.inBuffer.MkRequest();
        if (strDisplayMe != "")
        {
            Console.Out.WriteLine("FOUND SOMETHING IN BUFFER: " + strDisplayMe);
            char[] DisplayMeArr = strDisplayMe.ToCharArray ();
            for (int i = 0; i <= DisplayMeArr.Length -1; ++i) 
            {
                this.display.Text += DisplayMeArr [i];
                Thread.Sleep (100);
            }
        this.display.Text += '\n';
        }
    }

编辑:这是一个独立于通过静态缓冲区对象提供数据的类

【问题讨论】:

  • Invoke(),即this.display.Invoke((MethodInvoker) delegate {this.display.Text += DisplayMeArr [i];});
  • 您是否有机会查看以下问题? link

标签: c# multithreading winforms


【解决方案1】:

只有主窗口线程可以访问/更改控件...如果您想从运行循环的线程更新 UI,您需要使用 Control.Invoke 方法将调用与主线程同步。

比如……

public void put()
{   
    string strDisplayMe = ModemKind.MainClass.inBuffer.MkRequest();
    if (strDisplayMe != string.Empty)
    {
        char[] DisplayMeArr = strDisplayMe.ToCharArray();
        for (int i = 0; i <= DisplayMeArr.Length -1; ++i) 
        {
            this.UpdateUI(() => { this.display.Text += DisplayMeArr[i]; });
            Thread.Sleep(100);
        }

        this.UpdateUI(() => { this.display.Text += '\n'; });
    }
}

private void UpdateUI(Action handler)
{
    this.Invoke(handler);
}

【讨论】:

    【解决方案2】:

    您可以使用 MethodInvoker 从其他线程访问 TextBox,然后是 GUI 线程。使用MethodInvoker 创建一个访问TextBox 的方法。您要多次分配文本考虑分配一次以提高性能,并使用StringBuilder 进行字符串连接。

    public void put()
    {   
        string strDisplayMe = ModemKind.MainClass.inBuffer.MkRequest();
        if (strDisplayMe != "")
        {
            Console.Out.WriteLine("FOUND SOMETHING IN BUFFER: " + strDisplayMe);
            char[] DisplayMeArr = strDisplayMe.ToCharArray ();
            for (int i = 0; i <= DisplayMeArr.Length -1; ++i) 
            {
                AssignToTextBox(this.display, this.display.Text + DisplayMeArr [i]);
                Thread.Sleep (100);
            }
        AssignToTextBox(this.display, this.display.Text +  '\n');
        }
    }
    
    void AssignToTextBox(TextBox txtBox, string value)
    {
      if(txtBox.InvokeRequired)
      {
          txtBox.Invoke(new MethodInvoker(delegate { txtBox.text = value;      }));
      }
    }
    

    编辑你可以使用BeginInvoke代替Invoke来异步调用它。在此question 中阅读有关InvokeBeginInvoke 的更多信息。

    void AssignToTextBox(TextBox txtBox, string value)
    {
          txtBox.BeginInvoke(new Action(()=>txtBox.Text = value ));
    }
    

    【讨论】:

    • 这看起来不错,但我不确定 txtFolderName 指的是什么。
    • 实际上,Thread.Sleep 似乎是“慢速调制解调器连接”效果的一部分:D
    猜你喜欢
    • 1970-01-01
    • 2020-12-20
    • 2020-10-11
    • 1970-01-01
    • 1970-01-01
    • 2019-02-20
    • 1970-01-01
    • 1970-01-01
    • 2012-05-19
    相关资源
    最近更新 更多