views:

131

answers:

4

I want to make my MainWindow a singleton because I want to make accessing it from all other windows in my app easier. But I couldn't make it run. Here is what I did.

As usual, I made the MainWindow contractor private, and created a public static MainWindow Instance property to return a static instance. When I just run it without any other changes, I got "No Source Available" error. I googled the Internet and found one related topic at http://www.netframeworkdev.com/windows-presentation-foundation-wpf/xamlc-singleton-class-80578.shtml. However, I couldn't make it work as suggested there. Some suggest to make a change in MainWindow.xaml from

<Window x:Class="TestApp.MainWindow"

to

<Window x:Class="TestApp.MainWindow.Instance"

Which looks logical. However, when I did this, I got tons of compiling errors (first one says the namespace TestApp already contains a definition of 'MainWindow'.)

I found many articles on the Internet about how to make single instance app. I'm not looking for this. I just want to make my MainWindow a singleton. I have done it in WinForm apps many times.

+4  A: 

Not sure about making it singleton, but why would you want to? You can simple use Application.Current.MainWindow to get the Application.MainWindow property anytime from anywhere in your application.. See: http://msdn.microsoft.com/en-us/library/system.windows.application.mainwindow(v=VS.90).aspx.

Window mainWin = Application.Current.MainWindow;
mainWin.Title = "This will be set as the title of the Main Window";

Making it singleton still does not make sense to me - how does that make it more accessible? You can always save reference to your main window in a public static variable - this could be set in the constructor of your main Window:

public partial class MainWindow : Window
{
    public static MainWindow myMainWindow; // ASSUMPTION: only one MainWindow is ever constructed otherwise this will be overwritten by latest such instance

    public MainWindow()
    {
        InitializeComponent();            
        myMainWindow = this;
    }
}

But then given the above Application.Current.MainWindow why bother..

Mrk Mnl
What about other part of code doint this Winow1 = new Window1() , it will create another instance.
saurabh
@Mrk Mnl. Yes, I know I can do that, but I just want to make my life a little easier. So, I want to call MainWindow.Instance.DoSomething() instead of ((MainWindow)Application.Current.MainWindow).DoSomething().
miliu
Understood, in that case saving a static reference as above should make your life easier.
Mrk Mnl
A: 

Remove StartupUri="MainWindow.xaml" from your App.xaml file. WPF will not launch any window for you anymore.

<Application x:Class="WpfApplication1.App"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&gt;
</Application>

Add a handler to the Startup event of your App class in App.xaml.cs.
In this handler call the Show() method of your singleton instance.

using System;
using System.Windows;

namespace WpfApplication1
{
    public partial class App : Application
    {
        public App()
        {
            Startup += new StartupEventHandler(App_Startup);
        }

        void App_Startup(object sender, StartupEventArgs e)
        {
            WpfApplication1.MainWindow.Instance.Show();
        }
    }
}

Note: The App class has a property called MainWindow, hence in App_Startup() I prefixed the MainWindow class with the namespace!

Alex Janzik
A: 

To make the MainWindow a singleton, these are the steps you need to make: Add a MainWindow Instance to MainWindow class...

public static MainWindow Instance { get; private set; }

Note: set accessor is private so that nobody else can set it to anything else.

Add a static constructor in MainWindow and make the constructor of MainWindow private, like this...

static MainWindow()
{
    Instance = new MainWindow();
}

private MainWindow()
{
    InitializeComponent();
}

Now remove StartupUri="MainWindow.xaml" from your App.xaml file so that no default window is launched when you start the application. Catch the Startup event of your App class in App.xaml.cs like this:

public App()
{
    ...
    Startup += App_Startup;
    ...
}

void App_Startup(object sender, StartupEventArgs e)
{
    TestApp.MainWindow.Instance.Show();
}
Yogesh
You have to do this in a static constructor or lazily in the `Instance` getter. Also, for singleton you usually make constructors private. In your example, consumers can create multiple MainWindow instances and the last one will be assigned to `Instance`
Isak Savo
At least if you want to properly implement the singleton pattern. This code will obviously work in the sense that other classes can access the main window from the `Instance` property, but it's not "pure" singleton IMHO
Isak Savo
Yes, I agree. See the modified code.
Yogesh
A: 

Thank you all very much for the quick answsers. The key point is that I have to remove StartupUri="MainWindow.xaml" from App.xaml. Thanks also for the tip of static contructor. Another point I want to mention is that we can also override OnStartup to startup the main window (just to make a few lines shorter):

 public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
            TestApp.MainWindow.Instance.Show();
        }
    }
miliu