挂钩事件 Outlook VSTO 在主线程上继续工作
Posted
技术标签:
【中文标题】挂钩事件 Outlook VSTO 在主线程上继续工作【英文标题】:Hooked events Outlook VSTO continuing job on main Thread 【发布时间】:2015-12-03 23:31:14 【问题描述】:我开发了一个 Outlook VSTO 插件。有些任务应该在后台线程上完成。通常,检查本地数据库中的某些内容或调用 Web 请求。在阅读了几篇文章后,我放弃了在后台线程中调用 Outlook 对象模型 (OOM) 的想法。
我有一些 wpf 控件,并且成功地使用 .NET 40 TPL 来执行异步任务,并在完成后在主 VSTA 线程中“完成”工作(即访问 UI 或 OOM)。
为此,我使用以下形式的语法:
Task<SomeResult> task = Task.Factory.StartNew(()=>
//Do long tasks that have nothing to do with UI or OOM
return SomeResult();
);
//now I need to access the OOM
task.ContinueWith((Task<SomeResult> tsk) =>
//Do something clever using SomeResult that uses the OOM
,TaskScheduler.FromCurrentSynchronizationContext());
到目前为止一切顺利。但是现在我想在没有 Form/WPF 控件的 OOM 中挂钩事件时做类似的事情。准确地说,我的问题来自 TaskScheduler.FromCurrentSynchronizationContext() 抛出异常。
例如,
Items inboxItems = ...;
inboxItems.ItemAdd += AddNewInboxItems;
private void AddNewInboxItems(object item)
Task<SomeResult> task = Task.Factory.StartNew(()=>
//Do long tasks that have nothing to do with OOM
return SomeResult());
var scheduler = TaskScheduler.FromCurrentSynchronizationContext();
/* Ouch TaskScheduler.FromCurrentSynchronizationContext() throws an InvalidOperationException, 'The current SynchronizationContext may not be used as a TaskScheduler.' */
task.ContinueWith((Task<SomeResult> tsk) =>
//Do something clever using SomeResult that uses the OOM
),scheduler;
/* Ouch TaskScheduler.FromCurrentSynchronizationContext() 抛出 InvalidOperationException,“当前 SynchronizationContext 不能用作 TaskScheduler。” */
请注意,我尝试在插件初始化中创建一个 TaskScheduler,并按照建议 here 将其放入单例中。但它不起作用,继续任务不是在所需的 VSTA 主线程中执行,而是在另一个(用 VisualStudio 检查)中执行。
有什么想法吗?
【问题讨论】:
你试过异步/等待吗? 不,我没有,因为我的目标是 .NET40。升级到 .NET45 目前不是一个选项。但是,您是对的,我会尝试一下,这可能会为 40 年的修复带来一些见解。 @DmitryStreblechenko 不幸的是,在 await 关键字之后,执行其余任务的线程不是主 VSTA 线程。 @DmitryStreblechenko 查看我在代码中设置的断点123 请出示您的异步/等待代码。 【参考方案1】:有一个已知的错误,即 SynchronizationContext.Current 可能在几个不应该为空的地方(包括办公室加载项)为空。该错误已在 .NET 4.5 中修复。但由于您无法升级到 .NET 4.5,因此您必须找到解决方法。作为建议,请尝试这样做:
System.Threading.SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());
在初始化你的插件时。
【讨论】:
嗨,SynchronizationContext.Current 在 .NET 4.0 和 .NET 4.5 中都为空。但是,您使用 WindowsFormsSynchronizationContext 的解决方案有效。我会给你赏金。谢谢【参考方案2】:您可以使用SynchronizationContext 类,它提供了在各种同步模型中传播同步上下文的基本功能。 Post 方法将异步消息分派到同步上下文,即 Post 方法启动异步请求以发布消息。有关更多信息和示例代码,请参阅Using SynchronizationContext for sending events back to the UI for WinForms or WPF。
仅供参考Current 属性允许获取当前线程的同步上下文。此属性对于将同步上下文从一个线程传播到另一个线程很有用。
【讨论】:
thks,但我不明白你的建议。 SynchronizationContext.Current 在我的情况下为空。如果我尝试创建一个新的并使用它来创建一个 TaskScheduler 实例,如下所示: SynchronizationContext context = new SynchronizationContext(); SynchronizationContext.SetSynchronizationContext(context); TaskScheduler taskScheduler = TaskScheduler.FromCurrentSynchronizationContext();它也不起作用:作业不在主线程中执行。另外,我没有调度器,没有winform/WPF应用程序只有一些控件(在这种情况下没有)。 在辅助线程上调用时为空。尝试在主线程上获取它。 抱歉,不是。它在主线程上为空,请参阅screenshot以上是关于挂钩事件 Outlook VSTO 在主线程上继续工作的主要内容,如果未能解决你的问题,请参考以下文章
VSTO Outlook 插件:当用户拖放定期约会时,无法在 Item_Change 事件中获取 AppointmentItem