WPF无法关闭应用程序实例以使其第二次运行

时间:2018-10-19 14:14:44

标签: c# wpf

我有一个以[STAThread]开头的控制台应用程序。

该应用程序应打开一个单独的Wpf UI来输入一些设置。

该功能:

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

第一次打开用户界面可以正常工作。 第二次打开UI时会发生此问题。

我得到一个System.InvalidOperationException,说我不能在同一个AppDomain中运行多个Application-Instance。

要保存ram,必须在两次操作之间将其关闭。

我还尝试在构造函数中创建System.Windows.Application。 但是,一旦我第二次运行该应用程序,就会得到一个非常类似的异常。 UI的InitializeComponents()方法抛出System.InvalidOperationException,表示该对象将要终止。

StackTraces显示在解析xaml时出现错误,因此我认为它无法打开它,因为它在第一次执行时仍被打开。

调用ui.Close()或调用application.Shutdown()都无法解决问题(Environment.Exit()关闭所有内容,包括我的控制台应用程序)。

ram profiler指示并非所有内容均已正确关闭,因为关闭窗口后显示的使用率要高于在点火区中打开窗口之前的使用率。

如何正确关闭Application实例,或者如何重用它多次运行Wpf Application?

5 个答案:

答案 0 :(得分:1)

看过source code for the Application class,由于类构造函数初始化了各种静态字段,因此您似乎无法解决该问题:

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内容,但这会复杂得多。


[*]除了使用反射功能外,但我们不要去那里!

答案 1 :(得分:1)

看看这个问题:Does a WPF Application Actually Need Application.Run?

基本上说,您可以使用window.ShowDialog()方法打开窗口而无需应用程序实例

认为,Application.Run除了运行Dispatcher循环外没有做任何重要的事情。 ShowDialog有其自己的Dispatcher。但是,您可以创建应用程序单例实例,因为它包含一些共享资源。

答案 2 :(得分:0)

您可以创建一个派生自class A { constructor() { this.a = 2; this.bb = 3; } methodA() { console.log('method of A'); } doesMethodBelongHere(method) { // it should return true if `method` argument is a method of A return this.constructor.prototype[method.name] === method; } } 的类:

MarshalByRefObject

...并在其自己的应用程序域中执行其public class AppDomainWrapper : MarshalByRefObject { public void openUI() { var application = new System.Windows.Application(); var ui = new Window(); application.Run(ui); application.Shutdown(); } } 方法:

openUI()

答案 3 :(得分:0)

史蒂芬·兰德(Steven Rands)展示了问题所在。 我在外部加载项中有同样的问题。但是我需要一个用于xaml资源的应用程序对象和一个有效的Application.Current。 在我看来这是一个错误。如果您调用Shutdown(),则该成员也应重置为false。

答案 4 :(得分:0)

Hack(在 application.Shutdown() 之后运行它)。我在测试中使用它:

var field = typeof(Application).GetField(
    "_appCreatedInThisAppDomain",
    BindingFlags.Static | BindingFlags.NonPublic) ??
    throw new InvalidOperationException(
        "Field is not found: _appCreatedInThisAppDomain.");
field.SetValue(null, false);