2015-09-08 10 views
19

Ho sviluppato un add-in per Outlook VSTO. Alcune attività dovrebbero essere eseguite su un thread in background. In genere, controllare qualcosa nel mio db locale o richiamare una richiesta web. Dopo aver letto diversi post, ho abbandonato l'idea di chiamare Outlook Object Model (OOM) in un thread in background.Eventi collegati Eventi continui di VSTO su thread principale

Ho alcuni controlli wpf e sono riuscito a utilizzare .NET 40 TPL per eseguire l'attività asincrona e una volta completato per "terminare" il lavoro (ovvero accedere all'interfaccia utente o all'OOM) nel thread VSTA principale.

Per fare in modo da utilizzare una sintassi del tipo:

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

Fin qui tutto bene. Ma ora voglio fare qualcosa di simile quando si collega un evento nell'OOM dove non ci sono controlli Form/WPF. Precisamente, il mio problema deriva dal fatto che TaskScheduler.FromCurrentSynchronizationContext() genera un'eccezione.

Ad esempio,

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() genera InvalidOperationException, 'Lo SynchronizationContext corrente non può essere usato come TaskScheduler.' */

Si noti che ho cercato di creare un TaskScheduler in inizializzazione Addin e metterlo in un singleton come suggerito here. Ma non funziona, il task di continuazione non viene eseguito nel thread principale VSTA desiderato ma in un altro (ispezionato con VisualStudio).

Qualche idea?

+1

Hai provato async/attendi? –

+0

No, non l'ho perché ho il targeting per .NET40. L'aggiornamento a .NET45 non è un'opzione per ora. Tuttavia, hai ragione, ti darò una possibilità, questo potrebbe portare qualche intuizione per una correzione in 40. –

+0

@DmitryStreblechenko purtroppo dopo la parola chiave * await * il thread che sta eseguendo il resto dell'attività non è il thread VSTA principale. –

risposta

11

È noto un bug che SynchronizationContext.Current potrebbe essere nullo in diversi punti in cui non dovrebbe (inclusi i componenti aggiuntivi dell'ufficio). Quel bug è stato corretto in .NET 4.5. Ma dal momento che non è possibile eseguire l'aggiornamento a .NET 4.5, è necessario trovare una soluzione alternativa. Come suggerimento, prova a fare:

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

durante l'inizializzazione del tuo addon.

+3

Hi , SynchronizationContext.Current è null in entrambi .NET 4.0 e .NET 4.5. Tuttavia, la soluzione che utilizza WindowsFormsSynchronizationContext funziona. Ti concederò la taglia. Grazie –

3

È possibile utilizzare la classe SynchronizationContext che fornisce le funzionalità di base per la propagazione di un contesto di sincronizzazione in vari modelli di sincronizzazione. Il metodo Post invia un messaggio asincrono a un contesto di sincronizzazione, ovvero il metodo Post avvia una richiesta asincrona per pubblicare un messaggio. Vedere Using SynchronizationContext for sending events back to the UI for WinForms or WPF per ulteriori informazioni e codice di esempio.

FYI La proprietà Current consente di ottenere il contesto di sincronizzazione per il thread corrente. Questa proprietà è utile per propagare un contesto di sincronizzazione da un thread a un altro.

+0

thks, ma non capisco il tuo suggerimento. SynchronizationContext.Current è nullo nel mio caso. Se provo a crearne uno nuovo e lo utilizzo per creare un'istanza TaskScheduler come questa: Contesto SynchronizationContext = new SynchronizationContext(); SynchronizationContext.SetSynchronizationContext (contesto); TaskScheduler taskScheduler = TaskScheduler.FromCurrentSynchronizationContext(); Non funzionerà neanche: il lavoro non viene eseguito nel thread principale. Inoltre, non ho un dispatcher, non esiste alcuna applicazione winform/WPF solo alcuni controlli (e non in questo caso). –

+0

È nullo quando lo si chiama sui thread secondari. Prova a farlo sul thread principale. –

+0

Scusa, non lo è. È nullo sul thread principale, vedere la [screenshot] (https://keluro-my.sharepoint.com/personal/bpatra_keluro_com/_layouts/15/guestaccess.aspx?guestaccesstoken=CjzPoV%2fA3XWbJ1wdvcnqe98weA1z7vLtKT7eXxtgfUo%3d&docid=0398a764bb29d423692c4c133a3664e9d) –

Problemi correlati