【问题标题】:InvalidOperationException: The calling thread must be STA, because many UI components require thisInvalidOperationException: 调用线程必须是 STA,因为很多 UI 组件都需要这个
【发布时间】:2015-08-19 18:34:00
【问题描述】:

您可以在 SO 上找到很多类似的问题,但没有人(如我所见)涵盖情况,当您的逻辑必须返回某些内容时。

在这个代码示例中,我有一个简单的 CustomMessageBox(它是一个窗口),它必须返回由用户输入的内容。

public class CustomMessageBox  
{
  private string Value 
  {
      get 
      {
          return txt_box.Text;
      } 
  }

  private CustomMessageBox ()
  {
      InitializeComponent();
  }

  public static string Show(string caption = "Enter data")
  {
      CustomMessageBox cmb = new CustomMessageBox ();
      cmb.txt_block.Text = caption;

      cmb.ShowDialog();

      return cmb.Value;
  }
}

因此,当BackgroundWorker 调用Show 方法时,当构造函数尝试执行时,在第一行抛出异常。异常消息是

An exception of type 'System.InvalidOperationException' occurred in 
PresentationCore.dll but was not handled in user code


Additional information: The calling thread must be STA,  
because many UI components require this.

没有什么新东西,但我找不到这个问题的解决方案,我不能让线程成为 STA。 Show 方法签名必须像这样清晰 - 接受字符串并返回字符串。

通常必须如何解决此类问题?

【问题讨论】:

  • 您可以使用dispatcher.Invoke 使线程成为STA
  • 请提供任何能够从执行中返回值的示例。
  • 我通常以相反的方式执行此操作(至少在 WinForms 中):我订阅了 Close-event 并在事件处理程序中获取我需要的值,而不是返回一些东西。
  • 但我不能。需要明确的退货。

标签: c# multithreading dispatcher ui-thread


【解决方案1】:
public static string Show(string caption = "Enter data")
{
    Application.Current.Dispatcher.Invoke(new Action(() =>
    {
        CustomMessageBox cmb = new CustomMessageBox();
        cmb.txt_block.Text = caption;
        cmb.ShowDialog();
    }));
    return cmb.Value;
}

【讨论】:

  • «WindowsBase.dll 中发生“System.InvalidOperationException”类型的异常,但未在用户代码中处理附加信息:调用线程无法访问此对象,因为不同的线程拥有它。»跨度>
  • 自定义窗口已创建,但我仍然无法返回值。
  • CustomMessageBox cmb = null; Application.Current.Dispatcher.Invoke(new Action(() => { cmb = new CustomMessageBox(); cmb.txt_block.Text = caption; cmb.ShowDialog(); }));返回 cmb.Value;
  • 我知道可以通过复杂的调度来引发这种行为。这不是解决糟糕设计问题的好方法。
  • 你有没有试过不使用BackgroundWorker可以返回值?
【解决方案2】:

您不能从后台工作人员调用 UI 组件。这是你的问题的直接原因。所有 UI 组件都必须从 UI 线程创建并与之交互。这就是为什么在某些情况下我们有一些疯狂的逻辑来调用 UI 组件上的操作 - 应用程序中只有一个 UI 线程运行。

需要从后台进程填充 UI 元素的程序需要重新设计,以便将操作分为两个或多个工作单元,从而消除从后台操作 UI 的要求。

WPF and background worker and the calling thread must be STA

【讨论】:

  • 这就解释了为什么会抛出异常。但是为什么我只在调试输出窗口中看到异常?为什么它会静默失败而不是显示错误消息?
  • 我不完全确定——通常你不会在生产模式下运行像这样配置错误的程序。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多