WPF LifeCyle в надстройке

Я создал надстройку, которая вызывает через Reflection библиотеку классов WPF. Поскольку это библиотека классов, мне пришлось вручную создать экземпляр new System.Windows.Application().

Затем конструктор класса (тот, который вызывается через отражение) создает окно и Show() (с Dispatcher.Run(), чтобы избежать немедленного закрытия окна) или ShowDialog().

Поскольку мое приложение находится в надстройке, приложение все еще живо. Поэтому я могу создать экземпляр этого только один раз.

При первом запуске (когда создается экземпляр приложения) выполняется Application.Current.Dispatcher.

Но при втором запуске я понял, что Application.Current.Dispatcher был остановлен. Я никогда не вызываю InvokeShutdown(), поэтому не понимаю, когда Dispatcher останавливается.

Когда я запускаю это во второй раз, приложение уже создано (это нормально), но диспетчер остановился.

Есть идеи ? Спасибо !

Изменить. В своей надстройке я пробовал 2 способа:

Первый способ:

        foreach (Type type in ass2_l.GetTypes())
        {
            if (type.Name == "Loader")
            {
                object obj_l = Activator.CreateInstance(type);
                BindingFlags bf_l = BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
                object[] argList_l = new object[1];
                argList_l[0] = "ok";
                type.InvokeMember("Load", bf_l, null, obj_l, argList_l);
            }
        }

Когда я вызываю DLL напрямую из надстройки, Application.Current.Dispatcher находится в фоновом состоянии с именем «VSTA_Main». Когда я запускаю второй раз, Dispatcher все еще находится в фоновом режиме.

Второй способ:

        t_m = new Thread(loadDll);
        t_m.SetApartmentState(ApartmentState.STA);
        t_m.Start();

loadDll на самом деле содержат тот же код, что и код «первого пути». Когда я запускаю эту часть в первый раз, Диспетчер работает, и все совершенно нормально. При втором запуске Dispatcher останавливается.

EDIT 2: Проблема во втором случае. Когда loadDll завершается, а затем я снова нажимаю кнопку надстройки, t_m останавливается, и создание еще одного не решает проблему, поскольку Dispatcher ManagedThreadId имеет старый t_m ManagerThreadId:/

EDIT 3: Проблема определенно не вызвана надстройкой. Если вы просто создадите программу, которая запускает поток каждый раз, когда вы нажимаете кнопку. Поток пытается создать экземпляр библиотеки классов DLL WPF (посредством отражения), и если вы нажмете эту кнопку во второй раз (вызовите другой поток), поскольку Dispatcher все еще «связан» со старым потоком, Dispatcher «остановлен» (как в старой теме)


person metalcam    schedule 01.06.2011    source источник
comment
Является ли App.ShutdownMode явным или при закрытии последнего окна?   -  person Merlyn Morgan-Graham    schedule 01.06.2011
comment
Я пробовал оба. Но я думаю, что нашел, где именно проблема. В моей надстройке я запускаю поток STA, когда нажимаю кнопку (созданную моей надстройкой). Этот поток вызывает класс WPF с помощью Reflection. Я дважды пытался вызвать библиотеку в одном и том же потоке, и Dispatcher все еще работает. Это означает, что проблема заключается в завершении вызывающего потока, в результате чего Dispatcher останавливается... но почему? Я не знаю :/   -  person metalcam    schedule 01.06.2011
comment
Можете ли вы предоставить краткий пример кода, который воспроизводит проблему? Кроме того, не уверен, что это применимо, но Application не любит иметь несколько экземпляров на AppDomain...   -  person Merlyn Morgan-Graham    schedule 01.06.2011
comment
Я отредактировал свой код. Кстати, у меня нет нескольких экземпляров на AppDomain, так как каждый раз, когда я хочу создать новое приложение, я проверяю, имеет ли Application.Current значение null раньше.   -  person metalcam    schedule 01.06.2011


Ответы (2)


В обработчик события ThisAddin.Startup поместите этот код:

private void ThisAddInStartup(object sender, EventArgs e)
{
    if (System.Windows.Application.Current == null)
        new System.Windows.Application();
    System.Windows.Application.Current.ShutdownMode = ShutdownMode.OnExplicitShutdown
}

Это должно разобраться, у меня это хорошо работало в прошлом ..

person Jake Ginnivan    schedule 01.06.2011
comment
К сожалению, это не решает мою проблему, так как установка этого кода делает мой Диспетчер всегда фоновым. Но проблема не в надстройке. Действительно, если вы попробуете консольное приложение, запустив новый поток (как минимум 2 раза), и в этом потоке вызовите новую библиотеку классов wpf (которые создадут новое приложение), Диспетчер остановится во второй запущенный поток: / - person metalcam; 01.06.2011
comment
Мои знания о внутренностях класса Application немного нечеткие, но я предполагаю, что, поскольку он связан с WPF, у него есть собственный насос сообщений и другие вещи, связанные с потоком пользовательского интерфейса, в типичном приложении. VSTO работает в STA, и я предполагаю, что любой поток, который вы называете new Application(), запускает насос сообщений, когда этот поток завершается, и насос сообщений работает в этом потоке. Создание экземпляра в фоновом потоке не было бы хорошей идеей, и, как я уже сказал, это сработало для меня. Не могли бы вы опубликовать пример кода, мне было бы интересно покопаться в этом. - person Jake Ginnivan; 01.06.2011
comment
Кроме того, приведенный выше код создает приложение в методе VSTO Startup, который в основном представляет собой поток пользовательского интерфейса надстроек, работающий в Office STA (я думаю...). Затем вы должны создавать окна в этом потоке пользовательского интерфейса, независимо от того, используете ли вы для этого Dispatcher или SynchronisationContext, это не имеет значения. Но у вас должен быть ВЕСЬ код, связанный с WPF, выполняющийся в том же потоке пользовательского интерфейса, в котором был создан класс приложения. - person Jake Ginnivan; 01.06.2011

Наконец, я решил проблему, используя бесконечный цикл, чтобы поток оставался в рабочем состоянии, с AutoResetEvent/ManualResetEvent для запуска/остановки потока...

Поскольку поток никогда не завершается (и вызывает метод, который загружает dll пользовательского интерфейса WPF, когда он получает событие запуска), мы никогда не останавливаем поток (пока не остановим надстройку), и диспетчер тоже никогда не останавливается.

Кстати, спасибо за все ваши ответы :)

person metalcam    schedule 03.06.2011
comment
Можете ли вы добавить пример кода к своему ответу? Я сталкиваюсь с той же проблемой, однако на некоторых машинах диспетчер не выключается, а на некоторых - отключается. - person hustler; 22.05.2014