【问题标题】:Hooked events Outlook VSTO continuing job on main Thread挂钩事件 Outlook VSTO 在主线程上继续工作
【发布时间】: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
  • 请出示您的异步/等待代码。

标签: c# multithreading outlook vsto outlook-addin


【解决方案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
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-04-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-03
  • 1970-01-01
相关资源
最近更新 更多