【问题标题】:WPF cannot close Application instance for running it a second timeWPF 无法关闭应用程序实例以再次运行它
【发布时间】:2021-01-19 14:46:10
【问题描述】:

我有一个以[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 按预期工作。 第二次打开UI时出现问题。

我收到System.InvalidOperationException,说我不能在同一个 AppDomain 中运行多个应用程序实例。

为了节省内存,必须在操作之间关闭它。

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

StackTraces显示解析xaml时出现错误,所以我断定它无法打开它,因为它仍然是第一次执行时打开的。

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

ram profiler 表明,并非所有东西都正确关闭,因为它显示在窗口关闭后的使用率高于在第一个位置打开之前。

如何正确关闭应用程序实例,或者如何重复使用它来多次运行 Wpf 应用程序?

【问题讨论】:

    标签: c# wpf


    【解决方案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 内容,但这会更加复杂。


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

    【讨论】:

      【解决方案2】:

      你可以创建一个派生自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);
          }
      }
      

      【讨论】:

      • 它可以工作,但创建 AppDomain 对我来说非常慢。只需使用 ui.ShowDialog() 就可以了。
      【解决方案3】:

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

      基本上它说,您可以在没有应用程序实例的情况下使用 window.ShowDialog() 方法打开窗口

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

      【讨论】:

      • 这几乎可以工作。如果我只是打电话给ui.ShowDialog(),我会得到与我的问题相同的异常。但是,当我从构造函数中删除 InitializeComponents() 并在 ShowDialog() 之前从我的控制台应用程序中调用它时,它工作正常。
      【解决方案4】:

      Steven Rands 说明了问题所在。 我在外部加载项中遇到了同样的问题。但我需要一个用于 xaml 资源的应用程序对象和一个有效的 Application.Current。 在我看来,这是一个错误。如果你调用 Shutdown() 这个成员也应该被重置为 false。

      【讨论】:

      • 这似乎更像是一个评论而不是一个答案。
      • 是的,但我不被允许发表评论。不知道为什么。需要50分什么的。
      【解决方案5】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-12-04
        • 1970-01-01
        • 1970-01-01
        • 2012-11-12
        • 1970-01-01
        • 2022-12-04
        • 1970-01-01
        相关资源
        最近更新 更多