Convert Monogame to Monogame with XAML

Some time ago, I blogged about the importance of creating a “Monogame With XAML” project. Before I’d written this, I’d started a long running project, and realised that I needed XAML (for reasons already indicated). So, is it possible to convert? YES!

Is it easy? Actually, it’s not too bad; but to save anyone else (and my future self) the hastle of working out how, I’ve broken it down into 7 easy steps. (Below, MyGame refers to your game namespace).

1. Add app.xaml as a blank xaml page. Once it’s added, change the BuildAction to ApplicationDefinition:

Image

2. Clear the XAML from the page, and replace with the following:

<Application
    x: Class="MyGame.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns: x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns: local="using:MyGame">

    <Application.Resources >
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>

                <!--
                    Styles that define common aspects of the platform look and feel
                    Required by Visual Studio project and item templates
                 -->
                <ResourceDictionary Source ="Common/StandardStyles.xaml"/>
            </ResourceDictionary.MergedDictionaries>

        </ResourceDictionary>
    </Application.Resources >
</Application>

3. StandardStyles.xaml referenced above will not exist. Create a new XAML file in the appropriate directory (the one in this example is in a Common subdirectory. This should look something like the following (although given that these are styles, you may have different ideas):

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <!-- Non-brush values that vary across themes -->

    <ResourceDictionary.ThemeDictionaries>
        <ResourceDictionary x:Key="Default">
            <x:String x:Key="BackButtonGlyph">&#xE071;</x:String>
            <x:String x:Key="BackButtonSnappedGlyph">&#xE0BA;</x:String>
        </ResourceDictionary>

        <ResourceDictionary x:Key="HighContrast">
            <x:String x:Key="BackButtonGlyph">&#xE071;</x:String>
            <x:String x:Key="BackButtonSnappedGlyph">&#xE0C4;</x:String>
        </ResourceDictionary>
    </ResourceDictionary.ThemeDictionaries>

    <x:String x:Key="ChevronGlyph">&#xE26B;</x:String>
...
</ResourceDictionary>

If you’re unsure about what to put in here then just create a blank store app and lift this file.

4. Next, you need to edit the code behind for the new App.Xaml file. In App.Xaml.cs, you should have the following code:

using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.UI.Xaml;

// The Blank Application template is documented at http://go.microsoft.com/fwlink/?LinkId=234227

namespace MyGame
{
    /// <summary>
    /// Provides application-specific behavior to supplement the default Application class.
    /// </summary>
    sealed partial class App : Application
    {
        /// <summary>
        /// Initializes the singleton application object.  This is the first line of authored code
        /// executed, and as such is the logical equivalent of main() or WinMain().
        /// </summary>
        public App()
        {
            InitializeComponent();
            Suspending += OnSuspending;
        }

        /// <summary>
        /// Invoked when the application is launched normally by the end user.  Other entry points
        /// will be used when the application is launched to open a specific file, to display
        /// search results, and so forth.
        /// </summary>
        /// <param name="args">Details about the launch request and process.</param>
        protected override void OnLaunched(LaunchActivatedEventArgs args)
        {
            var gamePage = Window.Current.Content as GamePage;

            // Do not repeat app initialization when the Window already has content,
            // just ensure that the window is active
            if (gamePage == null)
            {
                // Create a main GamePage
                gamePage = new GamePage(args.Arguments);

                if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
                {
                    // TODO: Load state from previously suspended application
                }

                // Place the GamePage in the current Window
                Window.Current.Content = gamePage;
            }

            // Ensure the current window is active
            Window.Current.Activate();
        }

        /// <summary>
        /// Invoked when application execution is being suspended.  Application state is saved
        /// without knowing whether the application will be terminated or resumed with the contents
        /// of memory still intact.
        /// </summary>
        /// <param name="sender">The source of the suspend request.</param>
        /// <param name="e">Details about the suspend request.</param>
        private void OnSuspending(object sender, SuspendingEventArgs e)
        {
            var deferral = e.SuspendingOperation.GetDeferral();

            // TODO: Save application state and stop any background activity

            deferral.Complete();
        }
    }
}

5. GamePage referenced above doesn’t exist; create a new Page, called GamePage.xaml, and paste the following Xaml into it:

<SwapChainBackgroundPanel
    x:Class="MyGame.GamePage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MyGame"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid>
    </Grid>

</SwapChainBackgroundPanel>

6. Next, press F7 to get to the code-behind for GamePage.Xaml. In GamePage.Xaml.cs, paste the following code:

    public sealed partial class GamePage : SwapChainBackgroundPanel
    {
        readonly GameEngine _game;

        public GamePage(string launchArguments)
        {
            this.InitializeComponent();

            // Create the game.
            _game = XamlGame<GameEngine>.Create(launchArguments, Window.Current.CoreWindow, this);
        }
    }

This should link the whole thing back to your initial GameEngine that MonoGame uses.

7. Finally, locate Program.cs and either comment out the code, or just delete it.

DONE

You should now find that your game runs exactly as before, except you now have XAML capabilities.

Please feel free to add any comments for anything that I might have missed, or improvements you may have on this process. Also, feel free to leave comments such as: “Yes, this worked!”.

7 thoughts on “Convert Monogame to Monogame with XAML

  1. Dark Chamber (@dcegames)

    Thanks so much for this, it really solved exactly what I was trying to do! I was wondering though, if your toolbox items are showing? I can’t get any user controls to show up in my toolbox, and I’m wondering if it is because I started a non monogame/xaml project? I started a new monogame + xaml project and all of the tools are there in that one.

    Thanks!

    Reply
  2. pcmichaels

    No – toolbox appears fine for me, no matter how the project is created. I believe this is down to the file being edited, rather than the project type. Try Ctrl-Alt-X, and see if that brings the toolbox up.

    Reply
  3. Victor

    Great article, but I had quite a few problems, following it exactly as written. I suspect others who are as inexperienced as I am with Windows Store XAML apps may also encounter these problems:

    * app.xaml should probably be named App.xaml (capitalized) so that the resulting class is capitalized.
    * x: Class=”MyGame.App” should be x:Class=”MyGame.App” (no space after x:)
    * xmlns: x=”http://schemas.microsoft.com/winfx/2006/xaml” should be xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml” (no space after xmlns:) This is a problem in multiple spots.
    * “using:MyGame” should be changed to whatever your game’s namespace is
    * GamePage.xaml.cs needs a using statement: using MonoGame.Framework;
    * GameEngine (I’ve never heard this term before for the Game-inheriting class) needs to be the game class – which by default is Game1 in XNA apps.
    * This line confused me: “(the one in this example is in a Common subdirectory”. I didn’t realize that it actually meant a subfolder called “Common”, instead I thought that it meant that the two files share a “common” directory.
    * Make sure StandardStyles does not have any code in its codebehind (if one is generated for you). I had it generated as inheriting from Page.
    * App does not have an InitializeComponent, so this call causes an error. This was caused by ‘ x:Class=”MyGame.GamePage” ‘ – I needed to change the namespace to my game’s namespace.
    * GamePage does not have an InitializeComponent method, so this call causes an error. Just as above, this was caused by the x:Class definition not using my class name.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *