我在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