挂钩事件 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

VSTO ItemAdd事件未触发

VSTO学习——创建Outlook解决方案

Outlook VSTO插件在Outlook中不可见。

如何从 VSTO 插件中找出当前版本的 Outlook?

VSTO开发的Outlook插件怎么部署到客户端机器上