12

I want to open a WPF Window from a Console application. After referring to this post, it works fine.

The problem is: When the user closed the WPF Window (manually), it can no long be re-opened from the Console, throwing the exception message: "Cannot create more than one System.Windows.Application instance in the same AppDomain."

Here is the code:

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

How can I re-open the WPF Window?

Community
  • 1
  • 1
TomCaps
  • 2,497
  • 3
  • 22
  • 25

3 Answers3

24

You should not create the application together with the window but only once separately, also make sure that it does not exit after the window is closed by setting the ShutdownMode respectively, e.g.

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

Also if you want to re-open the very same window make sure it is never closed completely, to do that you can handle the Closing event and cancel it using e.Cancel = true;, then just call Hide on the window to "close" it and Show to "open" it again later.

H.B.
  • 166,899
  • 29
  • 327
  • 400
  • Are there any negative consequences to not running the app in another thread, and never calling app.Run()? I.e just create a new Application object, then a new Window object and just call myWindow.ShowDialog(). From what I can tell, a dispatcher is created and attached to the current thread automatically, and Application.Current is still used to manage resources. – Coder1095 Jun 21 '13 at 12:52
  • @Matt: That is not something you usually do, so i don't know as i never did that. You can also have windows without any Application it seems... – H.B. Jun 21 '13 at 13:04
0

When you add window as a parameter to app.Run you link the lifetime of your app to your window. Don't do that:

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.
        }
hcb
  • 8,147
  • 1
  • 18
  • 17
  • Thanks!But atfter i separating the Window.Show() from the app.Run() method, the window never get shown. – TomCaps Nov 08 '11 at 08:55
  • In addition to a form you can also pass an ApplicationContext to run. I don't know how it works but maybe in that class lies a solution to your problem. – hcb Nov 08 '11 at 08:59
0

I've not had chance to test this myself, but after reading up on your error, I found some information. Basically, it sounds like the AppDomain you are running in can only be used once per application - so perhaps you need to create a new AppDomain each time you want to re-create the application. See here for some more information on this.

Alternately, you could use System.Diagnostics.Process.Start(...) in order to fire off the application properly. Refer here for the documentation for the Process class.

Finally, if you are just wanting to allow the user to run the application from the command line, it might be simpler to write a command script and execute that from the command line.

Samuel Slade
  • 8,405
  • 6
  • 33
  • 55
  • Thanks! Unfortunately, in my application the WPF Window will share many variables from the Console Application, so they have to be running in the same process. – TomCaps Nov 08 '11 at 08:57