ExcelDna:异步:调用线程必须是 STA
ExcelDna: Async: The calling thread must be STA
我正在使用 ExcelDna 和异步函数。如果 async:d 代码中存在异常,我想显示一个奇特的 WPF 错误 window。我的问题是出现错误 "The calling thread must be STA, because many UI components require this." 我该如何解决这个问题?
[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);
}
}
许多 Office 插件有一个问题,其中 SynchronizationContext.Current
是 null
,异步延续在线程池上执行。我会在第一个 await
.
之前检查 SynchronizationContext.Current
的值
我在创建 WinFormsSynchronizationContext
并将其安装在第一个 await
之前的线程上取得了一些成功。但是,安装 WPF 上下文会更复杂。
当您的 Excel 函数 运行s 没有安装 SynchronizationContext.Current
时,因此 async/await 机制将 运行s [=11 之后的代码=](包括您的捕获处理程序)在 ThreadPool 线程上。这不是您可以直接显示 WPF 表单的上下文。
在主线程(或其他线程)上安装与 Dispatcher 运行ning 相对应的 DispatcherSynchronizationContext 是可行的,但您必须为每个 UDF 调用执行此操作。通过 Excel 的本机代码路径以某种方式丢失了主线程上的 .NET 调用上下文,因此 SynchronizationContext 丢失了。
更好的做法可能是假设 catch 处理程序 运行 在线程池线程上运行,然后从 catch 处理程序进行 SynchronizationContext.Post
调用以将您带回主线程 运行设置您的 Dispatcher 和 WPF 表单。
您可以查看 Excel-DNA 如何实现 (WinForms) LogDisplay window。 (https://github.com/Excel-DNA/ExcelDna/blob/master/Source/ExcelDna.Integration/LogDisplay.cs)。您可以从任何线程调用 LogDisplay.WriteLine(...)
,它会在主线程上执行 _syncContext.Post
到 运行 和 'Show'。
C# async/await 机制与 Excel 的工作效果较差,因为 native/managed 转换,无论 Excel 在内部做什么,都会弄乱需要流动的线程上下文连续之间。即使在 .NET 方面,也不清楚如何在 AppDomain(不同的 Excel 加载项)之间管理线程上下文。因此,最好不要依赖 .NET 运行时间能够通过 managed/native 转换对任何类型的上下文进行线程处理。
我正在使用 ExcelDna 和异步函数。如果 async:d 代码中存在异常,我想显示一个奇特的 WPF 错误 window。我的问题是出现错误 "The calling thread must be STA, because many UI components require this." 我该如何解决这个问题?
[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);
}
}
许多 Office 插件有一个问题,其中 SynchronizationContext.Current
是 null
,异步延续在线程池上执行。我会在第一个 await
.
SynchronizationContext.Current
的值
我在创建 WinFormsSynchronizationContext
并将其安装在第一个 await
之前的线程上取得了一些成功。但是,安装 WPF 上下文会更复杂。
当您的 Excel 函数 运行s 没有安装 SynchronizationContext.Current
时,因此 async/await 机制将 运行s [=11 之后的代码=](包括您的捕获处理程序)在 ThreadPool 线程上。这不是您可以直接显示 WPF 表单的上下文。
在主线程(或其他线程)上安装与 Dispatcher 运行ning 相对应的 DispatcherSynchronizationContext 是可行的,但您必须为每个 UDF 调用执行此操作。通过 Excel 的本机代码路径以某种方式丢失了主线程上的 .NET 调用上下文,因此 SynchronizationContext 丢失了。
更好的做法可能是假设 catch 处理程序 运行 在线程池线程上运行,然后从 catch 处理程序进行 SynchronizationContext.Post
调用以将您带回主线程 运行设置您的 Dispatcher 和 WPF 表单。
您可以查看 Excel-DNA 如何实现 (WinForms) LogDisplay window。 (https://github.com/Excel-DNA/ExcelDna/blob/master/Source/ExcelDna.Integration/LogDisplay.cs)。您可以从任何线程调用 LogDisplay.WriteLine(...)
,它会在主线程上执行 _syncContext.Post
到 运行 和 'Show'。
C# async/await 机制与 Excel 的工作效果较差,因为 native/managed 转换,无论 Excel 在内部做什么,都会弄乱需要流动的线程上下文连续之间。即使在 .NET 方面,也不清楚如何在 AppDomain(不同的 Excel 加载项)之间管理线程上下文。因此,最好不要依赖 .NET 运行时间能够通过 managed/native 转换对任何类型的上下文进行线程处理。