TextBox 和 RichTextBox 在线程方面的区别

Difference between TextBox and RichTextBox in regards to threading

我遇到了一个问题,我认为这可能是由于我 类 相互传递对象的复杂性,所以我将其最小化,但问题仍然存在:

我在 VS2017 社区中创建了一个默认的 winform 项目

我在表单上添加了一个文本框、一个富文本框、一个后台程序和一个用于激活后台程序的按钮。

我已将以下代码放入表单中以填充文本框并 运行 工作人员单击按钮:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        textBox1.Text = "Hello";
        richTextBox1.Text = "World!";
    }

    private void button1_Click(object sender, EventArgs e)
    {
        if (backgroundWorker1.IsBusy != true)
        {
            backgroundWorker1.RunWorkerAsync();
        }
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        MessageBox.Show(textBox1.Text);
        MessageBox.Show(richTextBox1.Text);
    }
}

我运行这个程序,但我不明白接下来会发生什么。

textBox1.Text 可从表单访问,因此 MessageBox 显示正常。 richTextBox1.Text 无法访问并给我这个错误:

Cross-thread operation not valid: Control 'richTextBox1' accessed from a thread other than the thread it was created on.

为什么?

我假设 richTextBox 有更多的路由和包装,但是 .Text 属性 不完全一样吗?!这是怎么回事?

编辑: 我不认为这与标记的问题重复,因为他没有为 TextBox.Text 工作,而我的是。我问的是 TextBox 和 RichTextBox .Text 属性之间的差异。

你必须 Invoke UI 代码(你不能 运行 UI 在除 UI 以外的线程中):

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
   // What to do with UI
   Action action = () => {
      MessageBox.Show(textBox1.Text);
      MessageBox.Show(richTextBox1.Text);
   }

   if (InvokeRequired)  // We are in some background thread, Invoke required
     Invoke(action);
   else                 // We are in UI (main) thread, just call the action
     action(); 
}

它们的实施方式不同。

TextBox.Text 基本上 returns Control.Text 调用 WindowText 使用 GetWindowText。 在代码注释中明确提到跨线程调用GetWindowText是可以的。所以他们通过设置标志inCrossThreadSafeCall来故意关闭跨线程检查。

但是对于 ReachTextBox.Text 它不依赖于 Control.TextIt 发送 EM_STREAMOUT 并使用结果。所以没有标志被设置为除了这个来自跨线程异常。

注意: 你应该忽略这种情况,你永远不应该尝试从另一个线程访问 UI 元素。当您尝试从另一个线程与 UI 线程交互时,始终使用控件的 Invoke 方法。