我在Excel工作表上有一個按鈕,它啓動一個新線程來做一些處理。如果我想對Excel進行任何更改(例如使用Worksheet.Range("A1").Value = "info";
將數據寫入單元格),我想我必須使用主UI線程。VSTO:在主Excel線程上調用
這怎麼辦?
通常在我的WinForms會叫Invoke
的控制,但Excel.Application
或Worksheet
或Range
對象不具有Invoke
方法。
我在Excel工作表上有一個按鈕,它啓動一個新線程來做一些處理。如果我想對Excel進行任何更改(例如使用Worksheet.Range("A1").Value = "info";
將數據寫入單元格),我想我必須使用主UI線程。VSTO:在主Excel線程上調用
這怎麼辦?
通常在我的WinForms會叫Invoke
的控制,但Excel.Application
或Worksheet
或Range
對象不具有Invoke
方法。
這項工作並不需要在UI線程上完成,.net會封送你的呼叫,但是如果你從後臺線程重複呼叫,你可能會遇到性能問題。
但具體回答你的問題,如果你有.NET 3.5,在您的外接負載事件補充一點:
,然後添加:
public Dispatcher Dispatcher { get {return _dispatcher;} }
然後,你可以派遣到UI線程去
Globals.ThisAdd.Dispatcher.Invoke(()=>{/*stuff*/});
如果你沒有.net 3.5,那麼還有一些其他的線程同步如使用SynchronizationContext.Current而不是Dispatcher。
您是否嘗試過從您的按鈕啓動BackgroundWorker?這使得它非常容易,因爲ProgressChanged和RunWorkerCompleted事件將在主線程上觸發。
我還沒有在Excel/VSTO環境中試過這個,但我不明白爲什麼它不起作用。
這是我使用WindowsForms的VSTO AddIn的解決方案。 你不需要任何System.Windows.Forms。控制使用它:在課堂上的ThisAddIn
初始化:
加入這一行 「ThisAddIn_Startup」 功能:
this.TheWindowsFormsSynchronizationContext = WindowsFormsSynchronizationContext.Current
?? new WindowsFormsSynchronizationContext();
添加這個新屬性:
public SynchronizationContext TheWindowsFormsSynchronizationContext { get; private set; }
然後在工作線程的用法是:
Globals.ThisAddIn.TheWindowsFormsSynchronizationContext.Send(d =>
{
MyMethodToInvoke();
}, null);
第二種解決方案(未測試):也許你可以同時使用:
var invokerControl = new Control();
invokerControl.CreateControl(); //Forces the control handle to be created
invokerControl.Invoke(new MethodInvoker(MyMethodToInvoke));
希望它有幫助,Jörg
非常感謝!搜索半小時後,這是VSTO唯一的工作解決方案! – Pali 2016-02-09 14:22:41
偉大的答案。我一直在牆上敲我的頭像類似的東西(xll加載項),並將其排序。雖然工作並不需要在UI線程上完成,但是如果您在另一個線程上完成工作,您可能會發現在關閉應用程序後,Excel.exe仍然處於任務管理器中。 – 2012-12-07 02:10:28
對於任何對Dispatcher感到困惑的人,你必須添加對WindowBase的引用才能訪問Dispatcher類。 – dotNET 2015-12-07 15:29:34
我從不同的線程調用時遇到的問題是Excel經常繁忙併拋出一個COMException異常。這解決了它。 – Laurent 2017-04-14 08:02:12