从控制台应用程序重新打开WPF窗口

12

我想要在控制台应用程序中打开一个WPF窗口。在参考这篇帖子后,它可以正常工作。

问题是:当用户手动关闭WPF窗口后,它不能从控制台再次打开,会抛出异常消息:"无法在同一AppDomain中创建多个System.Windows.Application实例。"

下面是代码:

class Program
    {
        static void Main(string[] args)
        {
            string input=null;
            while ((input = Console.ReadLine()) == "y")
            {
                //Works fine at the first iteration,
                //But failed at the second iteration.
                StartWpfThread();
            }
        }
        private static void OpenWindow()
        {
            //Exception(Cannot create more than one System.Windows.Application instance in the same AppDomain.)
            //is thrown at the second iteration.
            var app = new System.Windows.Application();
            var window = new System.Windows.Window();
            app.Run(window);
            //User  closes the opened window manually.
        }
        private static void StartWpfThread()
        {
            var thread = new Thread(() =>
            {
                OpenWindow();
            });
            thread.SetApartmentState(ApartmentState.STA);
            thread.IsBackground = false;
            thread.Start();
        }
    }

我如何重新打开WPF窗口?

3个回答

24

你不应该将应用程序与窗口一起创建,而应该单独创建一次,并通过设置相应的ShutdownMode确保在窗口关闭后它不会退出,例如:

class Program
{
    static Application app;
    static void Main(string[] args)
    {
        var appthread = new Thread(new ThreadStart(() =>
            {
                app = new Application();
                app.ShutdownMode = ShutdownMode.OnExplicitShutdown;
                app.Run();
            }));
        appthread.SetApartmentState(ApartmentState.STA);
        appthread.Start();

        while (true)
        {
            var key =Console.ReadKey().Key;
            // Press 1 to create a window
            if (key == ConsoleKey.D1)
            {
                // Use of dispatcher necessary as this is a cross-thread operation
                DispatchToApp(() => new Window().Show());
            }
            // Press 2 to exit
            if (key == ConsoleKey.D2)
            {
                DispatchToApp(() => app.Shutdown());
                break;
            }
        }
    }

    static void DispatchToApp(Action action)
    {
        app.Dispatcher.Invoke(action);
    }
}

如果您想要重新打开同一个窗口,请确保它从未完全关闭过。为此,您可以处理 Closing 事件并使用 e.Cancel = true; 取消该事件,然后只需在窗口上调用 Hide 来“关闭”它,以后再调用 Show 来“打开”它即可。


不在另一个线程中运行应用程序并且从未调用app.Run()会有什么负面影响吗?即只需创建一个新的Application对象,然后创建一个新的Window对象并调用myWindow.ShowDialog()。据我所知,调度程序会自动创建并附加到当前线程,并且仍然使用Application.Current来管理资源。 - Coder1095
@Matt:那不是你通常做的事情,所以我不知道,因为我从来没有这样做过。似乎你也可以没有任何应用程序的窗口... - H.B.

0
当你将窗口作为参数添加到app.Run中时,你将你的应用程序的生命周期与窗口链接在一起。不要这样做:
private static void OpenWindow()
        {
            //Exception(Cannot create more than one System.Windows.Application instance in the same AppDomain.)
            //is thrown at the second iteration.
            var app = new System.Windows.Application();
            var window = new System.Windows.Window();
            app.Run();
            window.Show();
            //User  closes the opened window manually.
        }

谢谢!但是当我将Window.Show()方法与app.Run()方法分开后,窗口就再也没有显示出来了。 - TomCaps
除了表单之外,您还可以传递一个ApplicationContext来运行。我不知道它是如何工作的,但也许在那个类中有解决您问题的方法。 - hcb

0

我自己还没有测试过这个,但是在阅读了您的错误信息后,我找到了一些相关资料。基本上,听起来像是您正在运行的AppDomain每个应用程序只能使用一次 - 所以也许您需要每次重新创建应用程序时创建一个新的AppDomain。请参见此处获取更多信息。

或者,您可以使用System.Diagnostics.Process.Start(...)来正确启动应用程序。请参考此处获取Process类的文档。

最后,如果您只想允许用户从命令行运行应用程序,那么编写一个命令脚本并从命令行执行可能会更简单。


谢谢!不幸的是,在我的应用程序中,WPF窗口将共享许多来自控制台应用程序的变量,因此它们必须在同一进程中运行。 - TomCaps

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接