VSTO: вызов в главном потоке Excel - PullRequest
19 голосов
/ 06 апреля 2011

У меня есть кнопка на листе Excel, которая запускает новый поток для некоторой обработки. Если я хочу внести какие-либо изменения в Excel (например, записать данные в ячейку, используя Worksheet.Range("A1").Value = "info";), я думаю, что я должен использовать основной поток пользовательского интерфейса.

Как это можно сделать?

Обычно в Winforms я бы назвал Invoke для элемента управления, но объекты Excel.Application или Worksheet или Range не имеют Invoke метода.

Ответы [ 3 ]

25 голосов
/ 15 мая 2011

Эту работу «не нужно» выполнять в потоке пользовательского интерфейса, .net будет перенаправлять вызов за вас, но если вы делаете повторные вызовы из фонового потока, вы можете столкнуться с проблемами производительности.

Но чтобы конкретно ответить на ваш вопрос, если у вас есть .net 3.5, в событии загрузки надстройки добавьте:

_dispatcher = Dispatcher.CurrentDispatcher;

А затем добавьте:

public Dispatcher Dispatcher { get {return _dispatcher;} }

Затем вы можете отправитьв поток пользовательского интерфейса:

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

Если у вас нет .net 3.5, есть несколько других методов синхронизации потоков, например использование SynchronizationContext.Current вместо Dispatcher.

10 голосов
/ 31 июля 2014

Это мое решение для надстройки VSTO с использованием WindowsForms. Вам не нужен 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));

Надеюсь, это поможет, Йорг

2 голосов
/ 06 апреля 2011

Вы пытались запустить BackgroundWorker с вашей кнопки?Это делает это очень легко, поскольку события ProgressChanged и RunWorkerCompleted будут запускаться в главном потоке.

Я не пробовал этого в среде Excel / VSTO, но не понимаю, почему это не сработает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...