【问题标题】:VSTO: invoking on main Excel threadVSTO:在 Excel 主线程上调用
【发布时间】:2011-04-06 14:18:32
【问题描述】:

我在 Excel 工作表上有一个按钮,它启动一个新线程来进行一些处理。如果我想对 Excel 进行任何更改(例如,使用 Worksheet.Range("A1").Value = "info"; 将数据写入单元格),我想我必须使用主 UI 线程。

如何做到这一点?

通常在 Winforms 中,我会在控件上调用 Invoke,但 Excel.ApplicationWorksheetRange 对象没有 Invoke 方法。

【问题讨论】:

    标签: c# excel vsto


    【解决方案1】:

    这项工作“不需要”在 UI 线程上完成,.net 将为您编组调用,但如果您从后台线程重复调用,您可能会遇到性能问题。

    但要具体回答您的问题,如果您有 .net 3.5,请在加载项加载事件中添加以下内容:

    Dispatcher _dispatcher = Dispatcher.CurrentDispatcher;
    

    然后加上:

    public Dispatcher Dispatcher { get {return _dispatcher;} }
    

    然后你就可以通过 go dispatch 到 UI 线程了

    Globals.ThisAddIn.Dispatcher.Invoke(()=>{/*stuff*/});
    

    如果您没有 .net 3.5,那么还有一些其他线程同步技术,例如使用 SynchronizationContext.Current 代替 Dispatcher。

    【讨论】:

    • 很好的答案。我一直在为类似的东西(xll 插件)撞墙,这对其进行了排序。正如您所说,虽然不需要在 UI 线程上完成工作,但如果您在另一个线程上完成工作,您可能会发现 Excel.exe 在关闭应用程序后仍在任务管理器中徘徊。
    • 对于其他对Dispatcher 感到困惑的人,您必须添加对WindowBase 的引用才能访问Dispatcher 类。
    • 从不同线程调用时遇到的问题是 Excel 经常很忙并抛出 COMException。这解决了它。
    • @JakeGinnivan 我在VS2019 中的VSTO 项目中使用您的建议。您要求在加载项的加载事件中添加 _dispatcher 变量声明。您的意思是在班级级别上声明吗?否则,属性声明 public Dispatcher Dispatcher { get {return _dispatcher;} } 不会将 _dispatcher 识别为 VS2019 正在抱怨我的 VSTO 项目。如果我在这里遗漏了什么,请告诉我。
    【解决方案2】:

    这是我使用 WindowsForms 的 VSTO 插件的解决方案。 您不需要任何 System.Windows.Forms.Control 即可使用它:


    ThisAddIn 类中的初始化:

    将此行添加到“ThisAddIn_Startup”函数中:

    this.TheWindowsFormsSynchronizationContext = WindowsFormsSynchronizationContext.Current 
                                               ?? new WindowsFormsSynchronizationContext();
    

    添加这个新属性:

    public SynchronizationContext TheWindowsFormsSynchronizationContext { get; private set; }
    

    那么在worker线程中的用法是:

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

    希望对你有帮助,约尔格

    【讨论】:

    • 非常感谢!经过半小时的搜索,这是 VSTO 唯一可行的解​​决方案!
    • SynchronisationContext 似乎比 Dispatcher 更通用、更安全(可以从 UI 外部调用)。这是 VS 答案stackoverflow.com/questions/24671883/…
    • 也适用于基于 ExcelDna 的插件。使用 AutoOpen() 函数来初始化上下文而不是 ThisAddIn_Startup。
    【解决方案3】:

    您是否尝试过从按钮启动 BackgroundWorker?这很容易,因为 ProgressChanged 和 RunWorkerCompleted 事件将在主线程上触发。

    我没有在 Excel/VSTO 环境中尝试过,但我不明白为什么它不起作用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-08-02
      • 2015-12-03
      • 1970-01-01
      • 2017-05-20
      • 2018-08-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多