VSTO: invoking on main Excel thread

前端 未结 3 816
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-12-13 20:26

I have a button on an Excel sheet which starts a new thread to do some processing. If I want to make any changes to Excel (e.g. write data to a cell using Worksheet.Ra

相关标签:
3条回答
  • 2020-12-13 20:28

    Have you tried starting a BackgroundWorker from your button? This makes it very easy as the ProgressChanged and RunWorkerCompleted events will fire on the main thread.

    I haven't tried this in an Excel/VSTO environment but I don't see why it wouldn't work.

    0 讨论(0)
  • 2020-12-13 20:45

    That work doesn't 'need' to be done on the UI thread, .net will marshal the call for you, but if you make repeated calls from a background thread you may hit performance issues.

    But to answer your question specifically, if you have .net 3.5, in your add-in load event add this:

    Dispatcher _dispatcher = Dispatcher.CurrentDispatcher;
    

    And then add:

    public Dispatcher Dispatcher { get {return _dispatcher;} }
    

    Then you can dispatch to the UI thread by going

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

    If you don't have .net 3.5, then there are a few other thread synchronisation techniques, like using SynchronizationContext.Current instead of the Dispatcher.

    0 讨论(0)
  • 2020-12-13 20:52

    This is my solution for a VSTO AddIn using WindowsForms. You don't need any System.Windows.Forms.Control to use it:


    Initialization in class ThisAddIn:

    Add this line to "ThisAddIn_Startup" function:

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

    Add this new property:

    public SynchronizationContext TheWindowsFormsSynchronizationContext { get; private set; }
    

    Then the usage in the worker thread is:

            Globals.ThisAddIn.TheWindowsFormsSynchronizationContext.Send(d =>
            {
                MyMethodToInvoke();
            }, null);   
    

    A second solution (Not tested): You could maybe also use:

            var invokerControl = new Control();
            invokerControl.CreateControl(); //Forces the control handle to be created
            invokerControl.Invoke(new MethodInvoker(MyMethodToInvoke));
    

    Hope it helps, Jörg

    0 讨论(0)
提交回复
热议问题