创建/添加新的 WPF 用户控件时"The calling thread must be STA, because many UI components require this"



我在VSTO加载项中有一个用户任务窗格。我在那里添加了winformshost和elementhost,以便能够在usertaskpane中使用wpf控件。

我设法添加了一个主 wpf 控件,但我无法向其添加子用户控件。

我有这样的方法来启动添加新的 wpf 控件:

private void MasterCheck()
{
this.pnlProgress.Visibility = System.Windows.Visibility.Visible;
//I'm using progress bar functionality in ReturnMasters method
Thread myNewThread = new Thread(() => Auditor.AuditMasterSlides(Globals.ThisAddIn.Application.ActivePresentation, this.pnlMaster, this, token));
token = new CancellationTokenSource();
myNewThread.Start();
this.pnlProgress.Visibility = System.Windows.Visibility.Collapsed;
}
public static void AuditMasterSlides(PPT.Presentation pres, Panel panel, MainProofingTaskPaneControl control, CancellationTokenSource cancToken)
{
IDictionary<string,MasterSlide> masterSlides = ReturnMasters(pres, cancToken, control);
control.ShowAndCollapse(panel);
control.RemovePanelChildren(panel);
if (masterSlides.Count>1)
{
//control.AddControlToPanel(panel, new MasterCheckControlOK());
}
else
{
control.AddControlToPanel(panel, new MasterCheckControlOK());
}
}
internal void RemovePanelChildren(Panel panel)
{
this.Dispatcher.Invoke(() =>
{
for (int i = panel.Children.Count - 1; i >= 0; i--)
{
panel.Children.RemoveAt(i);
}
});
}
internal void AddControlToPanel(Panel panel, Control control)
{
MasterCheckControlOK newControl = new MasterCheckControlOK();
this.Dispatcher.Invoke(() =>
{
panel.Children.Add(newControl);
});
}

我在这里收到错误:

public MasterCheckControlOK()
{
InitializeComponent();
}

我怎样才能解决它才能:

  • 使用进度条功能(当前有效(
  • 添加新的 WPF 控件(不起作用(
  • 修改/删除控件(当前有效(
  1. 只能在 STA(单线程单元(线程上创建 UI 控件:

调用线程必须是 STA,因为许多 UI 组件都需要此线程

  1. 您只能访问最初创建控件的线程上的控件。例如,不能在线程 B 上创建控件,然后尝试将其添加到在线程 A 上创建的控件的Children集合中。

因此,如果您打算从主线程以一种或另一种方式与后台线程交互,则在后台线程上创建控件是没有意义的。然后你会得到这个异常。

底线:应在同一线程上创建所有控件,并且在大多数情况下,此线程应为主 UI/调度程序线程。这将为您省去很多麻烦。

创建控件时,它必须在主 UI 线程中进行。当前,您正在另一个线程中创建控件,然后将其添加到另一个线程。这将导致异常。

您需要将控件的创建移动到调用内部,以便它在主 UI 线程上发生。

不能在单独的线程中创建 UI 控件。控件需要存在于 UI 线程上。

您可以尝试让线程函数使用其.Invoke()方法通过窗口的调度程序完成其工作。

您可能希望确保只有 UI控件的操作是使用调度程序完成的,否则您无论如何都可能会锁定 UI。

public static void AuditMasterSlides(PPT.Presentation pres, Panel panel, MainProofingTaskPaneControl control, CancellationTokenSource cancToken)
{
IDictionary<string,MasterSlide> masterSlides = ReturnMasters(pres, cancToken, control);
this.Dispatcher.Invoke((() => control.ShowAndCollapse(panel));
...
}

至于 STA 线程问题,您需要在启动之前指定您的线程是 STA 线程。

我通过在线程上调用.SetApartmentState()来做到这一点:

thread1.SetApartmentState(ApartmentState.STA);
thread1.Start();

相关内容

最新更新