« IE 8 Beta 2 - Your last browsing session closed unexpectedly | Main | Unable to add reference to assemblies in GAC from VS »

How to write custom Main method for a WPF application?

If you have been working with WPF applications you know that the current default behavior for adding the entry point (Main) method is via codegen. You don't write it yourself. The method is generated when you compile your application. A typical WPF project contains App.xaml which is marked as ApplicationDefinition in the csproj file.

    <ApplicationDefinition Include="App.xaml">

      <Generator>MSBuild:Compile</Generator>

      <SubType>Designer</SubType>

    </ApplicationDefinition>

It is due to this tag, that MSBuild when compiling the project adds the Main method to App.g.cs that is created in the obj/debug (or obj/release) folder. The generated file looks something like below. See details here.

    public partial class App : System.Windows.Application {

 

        /// <summary>

        /// InitializeComponent

        /// </summary>

        [System.Diagnostics.DebuggerNonUserCodeAttribute()]

        public void InitializeComponent() {

 

            #line 4 "..\..\App.xaml"

            this.Exit += new System.Windows.ExitEventHandler(this.Application_Exit);

 

            #line default

            #line hidden

 

            #line 4 "..\..\App.xaml"

            this.StartupUri = new System.Uri("Window1.xaml", System.UriKind.Relative);

 

            #line default

            #line hidden

        }

 

        /// <summary>

        /// Application Entry Point.

        /// </summary>

        [System.STAThreadAttribute()]

        [System.Diagnostics.DebuggerNonUserCodeAttribute()]

        public static void Main() {

            DummyApp.App app = new DummyApp.App();

            app.InitializeComponent();

            app.Run();

        }

    }

 

Hence, If you try to directly add code for Main method in App.xaml.cs, you will end up compiler error stating that there is already a definition of Main method. To add your own implementation, there are various approaches and you can pick that works best for you

Approach 1
You can delete the existing App.xaml and App.xaml.cs and add a new class file and maybe call it App.cs. In this you can define the App class and write your own Main method as below.

    public class App : System.Windows.Application

    {       

        [STAThread]

        public static void Main()

        {

            App app = new App();

            app.StartupUri = new System.Uri("Window1.xaml", System.UriKind.Relative);

            app.Run();

        }

    }

 

Approach 2
You will run into issues with Approach 1 if you are adding resources and resource dictionaries to your App.xaml. Since the App.xaml is no longer present you will have to write code in your App.cs itself to manage the resources and the merged dictionaries. However this can be more easily handled by modifying the .csproj file and marking App.xaml as Page instead of ApplicationDefinition 

    <Page Include="App.xaml">

      <Generator>MSBuild:Compile</Generator>

      <SubType>Designer</SubType>
    </Page>

 

 

Due to this change, the default entry point is no longer generated and you can write your own which can be something like below. For detailed discussion on this check Dr. WPF's blog.

 

    public partial class App : System.Windows.Application

    {

        [STAThread()]

        static void Main()

        {

            App app = new App();

            app.InitializeComponent();

            app.Run();

        }

    }

 

Approach 3
If you have resources and hence want to have App.xaml, but don't like to tamper with .csproj file, then you can include another class in your project that defines the Main method as below.

 

    class Startup

    {

        [STAThread]

        static void Main()

        {

            App app = new App();

            app.MainWindow = new Window1();

            app.MainWindow.Show();

            app.Run();

        }

    }

 

However compilation will result in error stating that the EXE now has multiple entry points. You can then use the /main compiler option to identify the class whose main you want the application to use as entry point. This can be done via the project properties. In the Application tab, modify the Startup object properties from the drop down. See figure below.

 

startup.jpg

 

Each approach will result in the desired behavior of having a custom entry point defined instead of using the default code generated method. You can pick any approach that works for you.

Comments

You can also change the build action on App.xaml in the VS property window from ApplicationDefinition to Compile and follow approach 2/3.

Samuel, typically XAML files should be marked page if you want the BAML to be appropriately generated. See here (http://msdn.microsoft.com/en-us/library/aa970678.aspx) where is says that resource dictionary files should be marked as Page. Since App.xaml may also contains resources, it should be marked as Page in Build action and not compile. Incidentally, when I mark it as Compile, I can't even build my solution !

Option 3 works best. Both option 1 and option 2 has some shortcommings:

1. Normally there are some resources declared in app.xaml, therefore delete App.xaml is not a good option;

2. As mentioned by Gupta, option 2 should change the build action to Page, not Compile. Even though the VS designer will not work properly if you have styles defined in app.xaml, it will complain that the resource can not be found. Apparently VS designer needs the Application Definition to locate the App level resources.

Thank you so much for this. just saved my life. was so confused. :-)

Post a comment

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)

Please key in the two words you see in the box to validate your identity as an authentic user and reduce spam.

Subscribe to this blog's feed

Follow us on

Blogger Profiles

Infosys on Twitter