2015-09-08 2 views
19

Я разработал Outlook VSTO addin. Некоторые задачи должны выполняться в фоновом потоке. Как правило, проверка чего-то в моем локальном db или вызов веб-запроса. После прочтения нескольких сообщений я отказался от идеи вызова объектной модели Outlook (OOM) в фоновом потоке.Подключенные события Outlook VSTO продолжение работы на главной теме

У меня есть некоторые элементы управления wpf, и я успешно смог использовать .NET 40 TPL для выполнения задачи async и по завершении «завершить» задание (т. Е. Получить доступ к пользовательскому интерфейсу или OOM) в главной теме VSTA.

Для этого я использую синтаксис вида:

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()); 

До сих пор так хорошо. Но теперь я хочу сделать что-то подобное при подключении события в OOM, где нет элемента управления Form/WPF. Именно моя проблема возникает из-за того, что 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}; 
} 

/* Ай TaskScheduler.FromCurrentSynchronizationContext() выбрасывает InvalidOperationException, 'Ток SynchronizationContext не может быть использован в качестве TaskScheduler. */

Обратите внимание, что я попытался создать TaskScheduler в инициализации addin и поместив его в одноэлементный режим, как предлагается here. Но он не работает, задача продолжения не выполняется в нужном главном потоке VSTA, а другая (проверяется с помощью VisualStudio).

Любая идея?

+1

Вы пытались использовать async/wait? –

+0

Нет У меня нет, потому что я нацелен на .NET40. Обновление до .NET45 сейчас не является вариантом. Тем не менее, вы правы, я попробую, это может принести некоторые сведения о исправлении в 40. –

+0

@DmitryStreblechenko, к сожалению, после ключевого слова * await * поток, выполняющий остальную часть задачи, не является основным потоком VSTA. –

ответ

11

Известно, что SynchronizationContext.Current может быть пустым в нескольких местах, где он не должен (включая надстройки офиса). Эта ошибка была исправлена ​​в .NET 4.5. Но так как вы не можете перейти на .NET 4.5, вам нужно найти обходной путь. В качестве предложения попробуйте сделать:

System.Threading.SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext()); 

при инициализации вашего аддона.

+3

Привет , SynchronizationContext.Current имеет значение null в .NET 4.0 и .NET 4.5. Однако ваше решение с использованием WindowsFormsSynchronizationContext работает. Я дам вам щедрость. спасибо –

3

Вы можете использовать класс SynchronizationContext, который предоставляет базовые функции для распространения контекста синхронизации в различных моделях синхронизации. Метод Post отправляет асинхронное сообщение в контекст синхронизации, то есть метод Post запускает асинхронный запрос для публикации сообщения. См. Using SynchronizationContext for sending events back to the UI for WinForms or WPF для получения дополнительной информации и кода примера.

FYI Свойство Current позволяет получить контекст синхронизации для текущего потока. Это свойство полезно для распространения контекста синхронизации из одного потока в другой.

+0

thks, но я не понимаю вашего предложения. SynchronizationContext.Current имеет значение null в моем случае. Если я попытаюсь создать новый и использовать его для создания экземпляра TaskScheduler следующим образом: SynchronizationContext context = new SynchronizationContext(); СинхронизацияContext.SetSynchronizationContext (контекст); TaskScheduler taskScheduler = TaskScheduler.FromCurrentSynchronizationContext(); Он не будет работать: задание не выполняется в основном потоке. Кроме того, у меня нет диспетчера, нет приложения winform/WPF только некоторые элементы управления (а не в этом случае). –

+0

Это нулевое значение, когда вы вызываете его на вторичные потоки. Попытайтесь получить его в основной теме. –

+0

Простите, это не так. Это нуль в главном потоке, см [скриншот] (https://keluro-my.sharepoint.com/personal/bpatra_keluro_com/_layouts/15/guestaccess.aspx?guestaccesstoken=CjzPoV%2fA3XWbJ1wdvcnqe98weA1z7vLtKT7eXxtgfUo%3d&docid=0398a764bb29d423692c4c133a3664e9d) –

Смежные вопросы