【问题标题】:Why do I get 'The calling thread must be STA' exception although invoking via Dispatcher?尽管通过 Dispatcher 调用,为什么我得到“调用线程必须是 STA”异常?
【发布时间】:2013-12-03 16:14:31
【问题描述】:

此方法调用位于派生自DispatcherObject 的类中:

Dispatcher.Invoke(DispatcherPriority.Input, new ThreadStart(() =>
            {
                var exported = formatProvider.Export(original.Workbook);
                Workbook = formatProvider.Import(exported);
            }));

该类上的方法由其DoWork 委托中的后台工作人员调用。

Workbook 是 Telerik 的 Workbook,由 RadSpreadsheetControl 使用。显然,工作簿只能由 UI 线程访问。

上面的代码抛出一个InvalidOperationException,说

调用线程必须是STA,因为很多UI组件需要 这个。

我不太明白,因为我认为当使用 Dispatcher 调用操作时,我会从 UI 线程(即 STA)调用它?

我在这里遗漏了什么,如何解决?或者这应该在一般情况下工作并且错误在其他地方?那可能是什么原因呢?

【问题讨论】:

    标签: wpf dispatcher sta


    【解决方案1】:

    TL;DR:您必须在 UI 线程中创建此 DispatcherObject,而不是在工作线程中。

    DispatcherObject.Dispatcher,您正在编组操作,在对象构造时设置为Dispatcher.CurrentDispatcher。如果对象不是在您现有的 UI 线程中创建的,那么 CurrentDispatcher 的记录行为是创建一个与线程关联的新调度程序对象。稍后,Invoke 尝试编组对该线程(不是 STA)的调用,从而导致错误。

    【讨论】:

    • 好的,明白了。在尚未由主 GUI 线程创建的对象中访问 GUI 线程的好习惯是什么?我可以 - 例如 - 公开一个应用程序范围的 DispatcherObject,它是在 GUI 线程中创建的带有锁的静态字段或类似的东西吗?感谢您的帮助!
    • @Marc: Application.Current.Dispatcher 就是这样一个静态助手,大部分时间它都能正常工作。
    • @Marc:这里有我的相关回答,看看:stackoverflow.com/q/10448987/50079
    【解决方案2】:

    使用派生自DispatcherObject 的类是不够的。您必须使用从 XAML 创建的现有 UIElement 中的 Dispatcher(或者至少确保从 GUI 线程内部创建您的类,它会在其中选择正确的 Dispatcher)。

    【讨论】:

    • UIElement is 一个DispatcherObject,所以第一句话真的没有意义。第二句也相当于“使用另一个对象的调度程序”,在这种情况下,为什么要让当前对象以DispatcherObject开头?
    • 好吧 - 我编辑了第一部分以更清楚我的意思。第二部分是可选的,因为当 OP 无法访问需要 Dispatcher.Invoke 的任何现有 UIElement 时。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多