【问题标题】:Can't access TextBox.Text in Background worker无法在后台工作人员中访问 TextBox.Text
【发布时间】:2016-01-06 16:51:26
【问题描述】:

我有一个 winforms 应用程序,最初设计为使用按钮手动触发不同的顺序功能(4 个按钮没有相应的后台工作人员,4 个按钮有相应的后台工作人员,总共 8 个按钮)。每个按钮都会同步进行一些快速设置,然后触发后台工作人员以异步方式完成工作。这可能是一项繁重的工作。

决定使用一个“快速”选项,它使用默认选项完成 4 个按钮的所有工作。不幸的是,我没有把它设计成我应该有的模块化。

我所做的是让 ExpressButton 调用第 5 个后台工作人员,该工作人员依次按顺序在每个按钮上调用 InvokeOnClick。幸运的是,首先调用了 4 个非异步按钮单击。在单击每个顺序按钮时,我正在使用 AutoResetEvent 阻止第 5 个后台工作人员。

这里是一些伪代码,按钮 1-4 不调用后台工作者,按钮 5-8 调用后台工作者和全局变量中的 _resetevent = new AutoResetEvent(false):

 private void backgroundWorker5_DoWork(object sender, DoWorkEventArgs e)    
 {
        ControlEventArgs automationcheck = new ControlEventArgs(expressButton);

        InvokeOnClick(button1, null);
        System.Threading.Thread.Sleep(500);
        InvokeOnClick(button2, null);
        System.Threading.Thread.Sleep(500);
        InvokeOnClick(button3, null);
        System.Threading.Thread.Sleep(500);
        InvokeOnClick(button4, null);
        System.Threading.Thread.Sleep(500);
        InvokeOnClick(button5, automationcheck);
        _resetevent.WaitOne();
        _resetevent.Reset();
        InvokeOnClick(button6, automationcheck);
        _resetevent.WaitOne();
        _resetevent.Reset();
        InvokeOnClick(button7, automationcheck);
        _resetevent.WaitOne();
        _resetevent.Reset();
        InvokeOnClick(button8, automationcheck);
        _resetevent.WaitOne();
        _statusBox.AppendText("Finished" + Environment.NewLine);
}

所以这是奇怪的事情。在 UI 中,我有 2 个文本框供用户输入信息。

在backgroundworker1(对应上面的button5)中,我可以访问第一个TextBox的.Text属性。 但是在 backgroundworker2(对应于 button6)中,我无法访问其他 TextBox 的 .Text 属性。 在调用 RunWorkerAsync() 之前,我可以一直在 button6 单击事件中访问它。 一旦我在 backgroundworker2 中尝试访问 TextBox.Text 就会冻结程序。也不例外,它只是停止。

这是我的理论: backgroundworker1 被调用/运行,没有来自 button5 点击事件的参数 使用来自 button6 点击事件的参数调用/运行 backgroundworker2 通过在 RunWorkAsync(params[]) 中传递对象列表,我是否会导致它不传递原始表单控件的某些上下文? 有趣的是,主窗体上还有另一个名为 statusBox 的文本框,我仍然可以在 backgroundworker2 中访问它,事实上,这就是我一直用于调试目的的文本框。

所以回顾一下。

Button 9    
  Backgroundworker 5
    Button 1
    Button 2
    Button 3
    Button 4
    Button 5
      Backgroundworker 1
        Can access TextBox.Text here
    Button 6
      Backgroundworker 2
        Can't access TextBox.Text here
    Button 7
      Backgroundworker 3
         unsure
    Button 8
      Backgroundworker 4
         unsure

最坏的情况:

由于 button6 仍然可以访问文本框,我可以获取文本并将其传递到参数列表中以供 runworkerasync 使用。但是我仍然想知道为什么 1 个后台工作人员可以在主窗体上看到一个文本框而另一个不能。

【问题讨论】:

  • 您应该使用委托并要求调用/调用...
  • 我可能应该做很多事情,但这个问题与为什么 1 个后台工作人员可以访问文本框而另一个不能访问直接相关。
  • 这个问题毫无意义。是否可以(有时)从另一个线程访问 UI 属性并不重要,因为根据定义,行为是 undefined
  • 您无法从工作人员更新 UI 元素,请尝试使用 dispatcher.run 更新 UI 元素

标签: c# .net winforms backgroundworker


【解决方案1】:

照奥斯汀说的做,Invoke() 所有的调用。

您只是随机遇到此异常(我不在乎它是否一致),从工作线程对 UI 的任何调用都可能导致异常,因为只有主线程必须访问 UI。

我敢打赌,当你第一次访问 .Text 属性时,控件本身不需要重绘,但第二次需要,所以你会以跨线程异常结束。

【讨论】:

  • 它最终成为了这个的变体。细节很有趣,2 个文本框是连接字符串,前 2 个按钮尝试自动检测,后 2 个按钮验证。当所有这些一步一步完成时,每个验证都需要检查另一个框是否已经验证。如果是,则什么也不做,但如果不是当前单击,则需要在另一个框上设置 ReadOnly=false。显然,当按顺序调用这些时,总是不会被验证,所以其中一次点击变成了 ReadOnly=false。我认为这导致需要重绘。
  • 要修复它,我意识到在验证后将连接字符串存储在全局变量中然后在每次需要连接字符串时引用 TextBox 的 .Text 属性更有意义。现在似乎很明显,但我对整个 UI 的东西还是新手,这是一个很大的错误,因为我对线程基础结构有更好的了解(至少在 winforms 中)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多