我在Excel工作表上有一个按钮,它启动一个新线程来进行一些处理。如果我想对Excel进行任何更改(例如使用Worksheet.Range("A1").Value = "info";
将数据写入单元格),我想我必须使用主UI线程。
如何做到这一点?
通常在Winforms中,我会在控件上调用Invoke
,但Excel.Application
或Worksheet
或Range
个对象没有Invoke
方法。
答案 0 :(得分:25)
这项工作不需要在UI线程上完成,.net会为你编组调用,但是如果你从后台线程重复调用,你可能会遇到性能问题。
但要具体回答你的问题,如果你有.net 3.5,请在你的加载项加载事件中添加:
_dispatcher = Dispatcher.CurrentDispatcher;
然后添加:
public Dispatcher Dispatcher { get {return _dispatcher;} }
然后你可以通过
发送到UI线程Globals.ThisAdd.Dispatcher.Invoke(()=>{/*stuff*/});
如果你没有.net 3.5,那么还有一些其他的线程同步技术,比如使用SynchronizationContext.Current而不是Dispatcher。
答案 1 :(得分:9)
这是我使用WindowsForms的VSTO AddIn的解决方案。 您不需要任何System.Windows.Forms.Control来使用它:
类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
答案 2 :(得分:2)
您是否尝试过按钮启动BackgroundWorker?这使得它很容易,因为ProgressChanged和RunWorkerCompleted事件将在主线程上触发。
我没有在Excel / VSTO环境中尝试这个,但我不明白为什么它不起作用。