【问题标题】:Difference between TextBox and RichTextBox in regards to threadingTextBox 和 RichTextBox 在线程方面的区别
【发布时间】:2019-07-13 20:58:21
【问题描述】:

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

我在 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 无法访问并给我这个错误:

跨线程操作无效:控件“richTextBox1”从创建它的线程以外的线程访问。

为什么?

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

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

【问题讨论】:

  • 永远不要从后台线程访问 UI 线程元素。 TextBoxRichTextBox 都不是。 DoWork 处理程序中的代码肯定是错误的。你应该使用ReportProgress 并在那里做你的事情。
  • 是的,我知道,当我运行异步工作程序时,我实际上是通过参数传递的。这是我正在查看的旧代码,我仍然想回答我的问题!
  • 答案是UI控件不是线程安全的,至于它们如何反应,不可预测,没什么好说的了。
  • TextBox works 巧合,你是幸运当前实现没有抛出的。你不应该依赖这样的测试。所有 UI 元素都必须从创建它们的同一线程访问。

标签: c# .net winforms textbox richtextbox


【解决方案1】:

它们的实现方式不同。

TextBox.Text 基本上返回Control.Text,它调用WindowText,它使用GetWindowText。 在代码中 cmets 明确提到 可以跨线程调用 GetWindowText。 所以他们通过设置标志 inCrossThreadSafeCall 故意关闭了跨线程检查。

但对于ReachTextBox.Text,它不依赖于Control.TextIt 发送 EM_STREAMOUT 并使用结果。因此,除了跨线程异常之外,没有设置任何标志。

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

【讨论】:

  • 谢谢。我已经知道每个人都在告诉我关于不在线程中引用 UI 元素的内容。我要么将 UI 线程作为参数传递,要么在某些情况下使用了调用。我很高兴它确认.Text 属性不是来自同一个地方。
  • 通过检查checkForIllegalCrossThreadCalls && !inCrossThreadSafeCall && InvokeRequired是否为真,检查控制的Handle中是否发生了跨线程操作,然后抛出异常。对于WindowText 属性,它已通过将inCrossThreadSafeCall 设置为true 来关闭。
【解决方案2】:

你必须InvokeUI代码(你不能在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(); 
}

【讨论】:

  • 这不能回答我的问题。
猜你喜欢
  • 1970-01-01
  • 2012-05-02
  • 1970-01-01
  • 2011-07-14
  • 1970-01-01
  • 2011-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多