[英]ExcelDna: Async: The calling thread must be STA
我正在使用ExcelDna和异步功能。 如果async:d代码中有异常,我想显示一个奇特的WPF错误窗口。 我的问题是,我收到错误消息“调用线程必须是STA,因为许多UI组件都需要STA。” 我该如何解决?
[ExcelFunction(Description = "", Category = "")]
public static async Task<object> /*string*/ Foo(CancellationToken ct)
{
try
{
return await Task.Run(async () =>
{
await Task.Delay(1000, ct);
throw new Exception("BOO");
return "HelloWorld";
}, ct2.Token);
}
catch (Exception e)
{
return ShowWpfErrorWindowThatRequiresSTA(e);
}
}
当您的Excel函数运行时,没有安装SynchronizationContext.Current
,因此async / await机制将在ThreadPool线程上的await
(包括您的catch处理程序)之后运行代码。 那不是您可以直接显示WPF表单的上下文。
安装与在主线程(或另一个线程)上运行的Dispatcher相对应的DispatcherSynchronizationContext是可行的,但是您必须为每个UDF调用执行此操作。 通过Excel的本机代码路径以某种方式丢失了主线程上的.NET调用上下文,因此SynchronizationContext丢失了。
最好假设捕获处理程序正在ThreadPool线程上运行,并从捕获处理程序进行SynchronizationContext.Post
调用,以使您回到运行Dispatcher和WPF表单的主线程。
您可以查看Excel-DNA如何实现(WinForms)LogDisplay窗口。 ( https://github.com/Excel-DNA/ExcelDna/blob/master/Source/ExcelDna.Integration/LogDisplay.cs )。 您可以从任何线程调用LogDisplay.WriteLine(...)
,它将执行_syncContext.Post
以在主线程上运行“ Show”。
C#异步/等待机制在Excel中的效果较差,因为本机/托管的转换以及Excel在内部所做的任何事情都弄乱了需要在延续之间流动的线程上下文。 即使在.NET方面,也不清楚如何在AppDomain(不同的Excel加载项)之间管理线程上下文。 因此,最好不要依赖.NET运行时能够通过托管/本机转换线程化任何类型的上下文。
许多Office插件都有一个问题,其中SynchronizationContext.Current
为null
,并且异步继续在线程池上执行。 我将在第一次await
之前检查SynchronizationContext.Current
的值。
我曾在创造一些成功WinFormsSynchronizationContext
和第一,然后再安装该线程上await
。 但是,安装WPF上下文会更加复杂。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.