2016-04-07 70 views
1

我正在使用ExcelDna和異步函數。如果在async:d代碼中有一個異常,我想顯示一個奇特的WPF錯誤窗口。我的問題是,我得到錯誤「調用線程必須是STA,因爲許多UI組件需要這個。」我該如何解決這個問題?ExcelDna:Async:調用線程必須是STA

[ExcelFunction(Description = "", Category = "")] 
    public static async Task<object> /*string*/ Foo(CancellationToken ct) 
    { 
     try 
     { 
      return await Task.Run(async() => 
      { 
       await Task.Delay(1000, ct); 
       throw new Exception("BOO"); 
       return "HelloWorld"; 
      }, ct2.Token); 
     } 
     catch (Exception e) 
     { 
      return ShowWpfErrorWindowThatRequiresSTA(e); 
     } 
    } 
+0

的可能的複製[「調用線程必須爲STA,因爲許多UI組件都需要這種」創造線程WPF彈出窗口時,錯誤](http://stackoverflow.com/questions/2657212/the-calling -thread-must-sta-because-many-ui-components-require-this-error) – CSharpie

+0

你必須在UI線程上顯示一個窗口。使用Application.Current.Dispatcher.BeginInvoke()。 –

+0

的可能的複製[調用線程必須爲STA,因爲許多UI組件都需要這在WPF(http://stackoverflow.com/questions/4183622/the-calling-thread-must-be-sta-because-many- ui-components-require-this-in-wpf) –

回答

3

當您的Excel函數運行時,沒有安裝SynchronizationContext.Current,因此async/await機制將在ThreadPool線程上運行await(包括您的catch處理程序)之後的代碼。這不是您可以直接顯示您的WPF表單的上下文。

安裝與在主線程(或另一個線程)上運行的Dispatcher相對應的DispatcherSynchronizationContext可行,但您必須爲每個UDF調用執行此操作。不知何故,通過Excel的本機代碼路徑會丟失主線程上的.NET調用上下文,所以SynchronizationContext會丟失。

更好的可能是假設catch處理程序正在ThreadPool線程上運行,並且從catch處理程序調用SynchronizationContext.Post以使您回到運行Dispatcher和WPF表單的主線程。

您可以看看Excel-DNA如何實現(WinForms)LogDisplay窗口。 (https://github.com/Excel-DNA/ExcelDna/blob/master/Source/ExcelDna.Integration/LogDisplay.cs)。你可以從任何線程調用LogDisplay.WriteLine(...),它將執行_syncContext.Post在主線程上運行「顯示」。

C#的異步/等待機制效果欠佳了與Excel,因爲本地/管理的轉變,不管Excel的內部呢,弄亂了,需要延續之間流動線程上下文。即使在.NET方面,也不清楚在AppDomain(不同的Excel加載項)之間如何管理線程上下文。所以最好不要依賴.NET運行時能夠通過託管/本地轉換來處理任何類型的上下文。

+0

Works!我在AutoOpen中創建了一個靜態的WindowsFormsSynchronizationContext(似乎也適用於WPF),我在HandleError中內部使用它。 –

+0

如果你只是在AutoOpen中設置一次,你不能依靠它在周圍.... – Govert

+0

你是什麼意思,它不會堅持?你會怎麼做? –

2

許多辦公室的插件有一個問題,即SynchronizationContext.Currentnull和異步連續執行的線程池。我會在第一個await之前檢查SynchronizationContext.Current的值。

我已經在創建WinFormsSynchronizationContext並在第一個await之前在線程上安裝了一些成功。但是,安裝WPF上下文會更復雜。

相關問題