WPF не может закрыть экземпляр приложения для его запуска во второй раз - PullRequest
0 голосов
/ 19 октября 2018

У меня консольное приложение, запущенное как [STAThread].

Это приложение должно открыть отдельный интерфейс Wpf для ввода некоторых настроек.

Функции для этого:

 private static void openUI()
    {
        var application = new System.Windows.Application();

        //referenced project in the same solution
        var ui = new ManagerUI.MainWindow();

        //blocks execution
        application.Run(ui);

        application.Shutdown();
    }

Открытие пользовательского интерфейса в первый раз работает, как и ожидалось.Проблема возникает при повторном открытии пользовательского интерфейса.

Я получаю System.InvalidOperationException, говоря, что не могу запустить более одного экземпляра приложения в одном и том же домене приложений.

Для сохранения оперативной памяти, он должен быть закрыт между операциями.

Я также попытался создать System.Windows.Application в конструкторе.Но как только я запускаю приложение во второй раз, я получаю очень похожее исключение.Метод InitializeComponents() интерфейса выдает System.InvalidOperationException, говоря, что объект будет завершен.

StackTraces показывает, что ошибка возникает при разборе xaml, поэтому я пришел к выводу, что он не может открыть его, так как он все еще открывается при первом выполнении.

Ни вызов ui.Close(), ни вызовapplication.Shutdown() решает проблему (Environment.Exit() закрывает все, включая мое консольное приложение).

Профилировщик оперативной памяти указывает, что не все было закрыто правильно, поскольку он показывает более высокое использование после закрытия окна, чем до негобыл открыт в первом месте.

Как правильно закрыть экземпляр приложения или как повторно использовать его для запуска приложения Wpf несколько раз?

Ответы [ 4 ]

0 голосов
/ 20 июля 2019

Стивен Рэндс показывает проблему.У меня такая же проблема во внешней надстройке.Но мне нужен объект приложения для ресурсов xaml и действительный Application.Current.На мой взгляд это ошибка.Если вы вызываете Shutdown (), этот участник также должен быть сброшен в false.

0 голосов
/ 19 октября 2018

Вы можете создать класс, производный от MarshalByRefObject:

public class AppDomainWrapper : MarshalByRefObject
{
    public void openUI()
    {
        var application = new System.Windows.Application();
        var ui = new Window();
        application.Run(ui);
        application.Shutdown();
    }
}

... и выполнить его метод openUI() в своем собственном домене приложения:

[STAThread]
static void Main(string[] args)
{
    const int n = 2;
    for (int i = 0; i < n; ++i)
    {
        AppDomain appDomain = AppDomain.CreateDomain("AppDomain");
        AppDomainWrapper application = appDomain.CreateInstanceAndUnwrap(typeof(AppDomainWrapper).Assembly.FullName, typeof(AppDomainWrapper).FullName) as AppDomainWrapper;
        application.openUI();
        AppDomain.Unload(appDomain);
    }
}
0 голосов
/ 19 октября 2018

Взгляните на этот вопрос: Действительно ли приложение WPF нуждается в приложении. Run?.

По сути, это говорит о том, что вы можете открывать окна, используя метод window.ShowDialog () безЭкземпляр приложения

Смысл в том, что Application.Run не делает ничего важного, но запускает цикл Dispatcher.ShowDialog имеет свой собственный диспетчер.Вы можете создать экземпляр приложения Singleton, так как он содержит некоторые общие ресурсы.

0 голосов
/ 19 октября 2018

Посмотрев исходный код для класса приложения , не похоже, что вы сможете обойти это, поскольку различные статические поля инициализируются конструктором класса:

public Application()
{
    ...

    lock(_globalLock)
    {
        if (_appCreatedInThisAppDomain == false)
        {
            ...
            _appInstance = this;
            ...
            _appCreatedInThisAppDomain = true;
        }
        else
        {
            throw new InvalidOperationException(...);
        }
    }
}

...

static private object                           _globalLock;
static private bool                             _appCreatedInThisAppDomain;
static private Application                      _appInstance;

...

В основном конструктор устанавливает _appCreatedInThisAppDomain в значение true, и, поскольку это поле является приватным, у вас нет возможности вернуть его обратно *.

Я думаю, что единственный способ достичь чего-то похожего на то, что вы хотитеэто написать отдельное приложение WPF, а затем использовать класс Process для его запуска из консольного приложения.В качестве альтернативы, вы можете теоретически создать отдельный AppDomain для размещения вашего WPF-содержимого, но это будет намного сложнее.


[*], кроме использования Reflection, но давайте не будем там!

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