Search code examples
c#wpfmainwindow

How can I pass application control to another WPF window?


I'm setting up a simple WPF application, which looks at its command-line arguments to determine what kind of window should be shown next. When that's determined, I show the next window by calling new ApplicationWindow(), set the content, and call Show(). The problem is that the MainWindow instance seems to have "application control" - i.e. when it closes, so does everything else.

It goes like this:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        TopBar.Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FF1975DD"));
        this.ContentRendered += MainWindow_ContentRendered;
        this.OperationModeSet += MainWindow_OperationModeSet;
    }

    [STAThread]
    private void MainWindow_ContentRendered(object sender, EventArgs e)
    {
        Thread worker = new Thread(new ThreadStart(this.ParseCommandLineArgs));
        worker.SetApartmentState(ApartmentState.STA);
        worker.Start();
    }

    [STAThread]
    public void ParseCommandLineArgs()
    {
        Thread.Sleep(3000);

        string[] args = Environment.GetCommandLineArgs();

        if (args.Any(item => item == "--server" || item == "-s"))
        {
            SetOperationMode(OperationMode.Server);
            Dispatcher.BeginInvoke(new Action(delegate()
            {
                this.CloseWindow();
            }));
        }
        else
        {
            SetOperationMode(OperationMode.Client);
            Dispatcher.BeginInvoke(new Action(delegate()
            {
                this.CloseWindow();
            }));
        }
    }

    [STAThread]
    private void SetOperationMode(OperationMode mode)
    {
        OperatingMode = mode;
        if (OperationModeSet != null)
        {
            OperationModeSet(this, new OperationModeSetEventArgs(mode));
        }
    }

    [STAThread]
    private void MainWindow_OperationModeSet(object sender, OperationModeSetEventArgs e)
    {
        AppWindow window = new AppWindow();
        if (e.Mode == OperationMode.Client)
        {
            this.CloseWindow();
            window.Content = new ClientPage();
        }
        else if (e.Mode == OperationMode.Server)
        {
            this.CloseWindow();
            window.Content = new ServerPage();
        }
        window.Show();
    }
}

These methods get called in the order I've put them here, through various events. I've omitted a few fields and properties.

The problem is that when this MainWindow closes, so does window - the instantiated ApplicationWindow. I assume this is because the MainWindow created it.

However, I do want to be able to close the MainWindow and continue with another window as the "main" window - so how can I decouple the instantiated ApplicationWindow from its parent MainWindow so it continues on?

I've seen setting Application.MainWindow in App.xaml changes the main window - but I have no reference to the instantiated window that I can put into a static XAML file.


Solution

  • Why are you parsing the command line args in your MainWindow?

    You could just remove the StartupUri in the App.xaml and override the OnStartup method. Then you can use StartUpArgs to decide which operating mode you want.

    In App.xaml.cs

    protected override void OnStartup(StartupEventArgs e)
    {
        // Decide which window to show here
        // Add bounds checks etc. 
        if (e.Args[0] == "-s")
        {
            var window = new ServerPage();
            window.Show();
        }
        else
        {
            var window = new ClientPage();
            window.Show();
        }
    
        Current.ShutdownMode = ShutdownMode.OnExplicitShutdown;
        base.OnStartup(e);
    }