WPF中出现的错误:"调用线程必须是STA,因为许多UI组件需要这样。"

3
我正在创建下面的XPS文档。
Assembly assembly = Assembly.GetExecutingAssembly();
//read embedded xpsDocument file
Stream helpStream = assembly.GetManifestResourceStream(resourceNameOfContext);
if (helpStream != null)
{
    Package package = Package.Open(helpStream);
    string inMemoryPackageName = "memorystream://" + topicName + ".xps";
    Uri packageUri = new Uri(inMemoryPackageName);
    //Add package to PackageStore
    PackageStore.AddPackage(packageUri, package);
    docXps = new XpsDocument(package, CompressionOption.Maximum, inMemoryPackageName);
}
return docXps;

当我尝试获取docXps.GetFixedDocumentSequence()时,出现了上述错误。有人可以帮忙吗?
谢谢。

你能把你的代码缩进四个空格,让它更易读吗? - oltman
2个回答

19

你的问题与创建或使用XPS文档的代码无关,而是与你运行的线程有关。

当在 MTA (多线程单元) 线程下尝试执行以下任何操作时,你将收到“调用线程必须为 STA,因为许多 UI 组件需要这样”的错误提示:

  • 构造任何派生自 FrameworkElement(包括 Controls 和 Panels)的对象
  • 构造任何派生自 BitmapEffect 的对象
  • 构造任何派生自 TextComposition 的对象
  • 构造任何派生自 HwndSource 的对象
  • 访问当前 InputManager
  • 访问主 KeyboardDevice、StylusDevice 或 TabletDevice
  • 尝试更改 FrameworkContentElement 上的焦点
  • 向接受文本输入的任何控件提供鼠标、键盘或 IME 输入
  • 使 WPF 内容可见或更新其布局
  • 以使重新评估渲染的方式操纵可视树
  • 其他一些更改,主要与显示和输入有关

例如,去年我尝试在 WCF 服务中反序列化包含 <Button> 和其他 WPF 对象的 XAML 时收到此错误。问题简单解决:我只需切换到 STA 线程进行处理。

显然,大多数处理 XPS 文档的工作将触发上述一项或多项条件。在你的情况下,我怀疑 GetFixedDocumentSequence 使用了 TextComposition 或其子类之一。

毫无疑问,切换到 STA 线程也适用于你,但首先你需要弄清楚与 XpsDocuments 相关的代码是如何从 MTA 线程中执行的。通常来自 GUI 的任何代码(例如按钮按下)都会自动在 STA 线程中运行。

你是否有可能在没有 GUI 的情况下执行操作 XPS 文档的代码?比如在用户创建的线程中、WCF 服务或 Web 服务中,还是 ASPX 页面中?找出它并可能就能找到解决方案。

如果那样做没有效果,请告诉我们通过哪个路径调用了GetFixedDocumentSequence,这样我们就可以诊断它。 直接周围的代码并不像调用堆栈和最初如何调用那样重要。 如果很难解释,您可能应该添加一个调用堆栈以防止误解并帮助我们进一步诊断问题,或者告诉您如何在特定情况下启动STA线程。

1

你的代码是否试图从后台线程访问xps文档?如果是这种情况,你需要使用dispatcher。关于此的信息在这里

如果这不起作用,你可以发布一下实际调用GetFixedDocumentSequence()的代码吗?


我正在将这个xps文档分配给我的自定义类的属性。当我想从自定义类访问这个xpsdocument属性时,我可以获取文档,但是在docXps.GetFixedDocumentSequence()上出现错误。 - Ershad
私有 void MergeHelpDocument(HelpTopic helpTopic, SerializerWriterCollator vxpsd) { try { if (helpTopic.Document != null) { FixedDocumentSequence seqOld = helpTopic.Document.GetFixedDocumentSequence(); // 在这里我需要获取文档引用 foreach (DocumentReference r in seqOld.References) { FixedDocument d = r.GetDocument(false); } } } - Ershad
1
@Ershad:你知道吗,你可以编辑你的问题并将代码添加到里面?大多数人都这样做,因为代码在评论中阅读起来要容易得多。 - Ray Burns

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接