Embedding Your MonoGame Game in a WinForms Control

In my previous entry, one reader brought up a good question: once you have your MonoGame-based WinForms control working, how do you run your game in it? This is a problem I had to solve in XNA during early development of my editor when I wanted to run my live game in it. For reasons that will follow, my solution involves replacing MonoGame/XNA’s Game class entirely for the embedded version, and making sure my game is designed to not depend on having a Game object present.

The WinForms series project with an embedded game.

The Game Object

The Game object that you typically derive your project from is designed to create and manage its own native window and rendering environment, with all the guts hidden away so its usage appears to be platform-independent. This is no good for embedding in our new GraphicsDeviceControl, and we can’t get at the underlying OpenTK surface that we need to be able to properly render our game in the control either.

I have a theory that if you hacked through enough layers of MonoGame to expose access to the underlying OpenTKGameWindow or OpenTK.GameWindow object, then you could suppress the standalone window and grab the necessary Handle to instead show rendered contents in your control. Doing so would allow you to directly wrap your derived Game object. If you want to stick to stock MonoGame code, then it needs to be replaced. Hopefully you’ve architected your game to not depend on an explicit instance of the Game object being available everywhere. If you also haven’t signed on to XNA’s suggested model of IDrawables and IUpdateables, then you’re even better off and have less work to do.

If we’re going to replace Game, we need to look at its API and the services it provides:

Methods

Properties

BeginDraw()

Components

BeginRun()

Content

Dispose()

GraphicsDevice

Draw(GameTime)

InactiveSleepTime

EndDraw()

IsFixedTimeStep

EndRun()

IsMouseVisible

Exit()

LaunchParameters

Game()

Services

Initialize()

TargetElapsedTime

LoadContent()

Window

ResetElapsedTime()

Run()

Run(GameRunBehavior)

RunOneFrame()

SuppressDraw()

Tick()

UnloadContent()

Update(GameTime)

Roughly, this laundry list of an API provides the following services for us:

The amount that you depend on XNA infrastructure to model your game will determine the amount of this API that needs to be duplicated. I’ve boldfaced the minimum amount of API that is necessary to implement any game. Some other entries like IsFixedTimeStep should also be provided to influence the frame rate, but other services like the ContentManager can easily be provided directly within your engine.

Replacing Game with GameControl

The following implementation represents the minimum viable replacement for the Game API, and derives from GraphicsDeviceControl just like any other type of rendered control you would write.

GraphicsDeviceControl already gives us entry points for everything we need: a GraphicsDeviceService, Initialize, Update, and Draw. We only do minimum tracking of game time, and the frame rate this runs at is entirely determine by how quickly the underlying Windows message loop idles. Depending on your needs, this may be sufficient, but chances are you’ll need to implement something more sophisticated. It’s worth noting that by hooking the game loop to the Application.Idle event, the game is running asynchronously with the rest of your UI.

I have implemented several services in the engine that were previously provided by the Game object, such as the GameServiceContainer and the ContentManager. I’m not using IGameComponent infrastructure, so I don’t need to worry about the absence of automagically self-updating IUpdatables or self-drawing IDrawables. But it would still be okay to use them if you spent the effort to properly implement support for them in your GameControl.

The Stand-Alone Game

Now that the game is implemented in terms of GameControl, let’s see what a stand-alone implementation would look like.

The implementation is almost identical to the GameControl version, save for creating a GraphicsDeviceManager as my GraphicsDeviceService. The Engine class being used is identical to the one above.

By keeping your game logic out of your Game class, it’s easy to drive your game from another game manager if necessary, such as a GameControl used in your custom level editor. The amount of effort needed to implement a compatible GameControl will vary from project to project, and you may be willing to accept a reduced implementation for your embedded use case. On the other hand, if you’ve already invested a large amount of time developing your game with your core Game object tightly intertwined through your codebase, then this approach will not be viable to you.

Thanks for the tip! I’ll have to play with this a little more when I get a moment.

Slowing down the update loop when the window is out of focus is a great idea. Or at least having the option to do so. As for when it is in focus, that’s a little trickier to think about. This uses the prescribed method of driving a GLControl, which is hooking up to Application.Idle. That also causes it to run the update and draw loop as fast as possible and basically burn up a core. I’m curious what your Sleep(1) translates to in terms of an FPS drop. The granularity of Sleep is about 10ms, so I’d expect your corresponding FPS to be around 1-2.

Another thing I would like to ask you is how are you handling the properties in a propertygrid of a Vector2 and Color (using the MonoGame.Framework). They don’t seem to expand like they used to using XNA.

I’m not, basically. PropertyGrid is a very flexible control that will try to display whatever you give it, to the best of its ability.

Microsoft probably provided the necessary TypeConverters to deal with this, even though they did not give us a first-party XNA control. It would probably not be much work to implement them. More info on the topic can be found here.

Error 1 Invalid Resx file. Could not load file or assembly ‘System.Runtime.Serialization, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e’ or one of its dependencies. The system cannot find the file specified. Line 126, position 5. C:\Users\user\Downloads\mgtkWinFormsDemo2 (1)\WinFormsGraphicsDevice\MainForm.resx 126 5 WinFormsGraphicsDevice

Are you playing with Silverlight by any chance? The 2.0.5.0 is a bit suspect. Seems like a framework problem regardless. You could also try out the examples in this repository: https://github.com/jaquadro/MonoGame-WinFormsControls — see if you can run them as-is before trying to integrate into something else.

VC#2010 should be fine. I was actually able to reproduce your error by deleting Resources.resx in the Properties directory, which causes causes that error because it’s referenced by MainForm.resx. Make sure you’ve got Resources.resx in your project and it’s set to EmbeddedResource.

I apologize, I just tried opening the project in actual Visual C# 2010 Express, and it’s doing something to the project to make it unusable (the error you’re reporting). I’m not quite sure what it’s doing yet, but I’m looking into it.

You’re sure you’re running into the same problem with the MonoGame-WinFormsControls project I linked you to? That runs fine for me in VC#2010 Express and it’s better example code anyway. There’s a few different example projects in that solution you can try building and running.

It’s looking more like there’s something just broken with the project file that’s included with this post.

Does Window.Handle return something besides null? The OpenTKGameWindow implementation could just be off. OpenTK creates an awkward window abstraction that doesn’t give up direct access to a handle.

Whether or not that works, you still need to do some reoganization. MonoGame does not implement that overload of GraphicsDevice.Present. You need another way of channeling your game’s window handle to your GraphicsDeviceControl, assuming that it’s compatible.

I haven’t thought of your approach for old XNA games, so I think there’s some value in playing around with this a little more and seeing if we can use Game classes directly after all.

Right, I see what you’re doing now. You made an assumption in your code that XNA would create your Game’s backing window from the Form class. OpenTK never derives from System.Windows.Form. It creates its own ugly window class, and you’re getting a handle to that instead. You could try casting to an OpenTK.INativeWindow instead and setting the Visible property and hooking up to the VisibleChanged event. Well, that would also require a way to even get an INativeWindow from your handle, which I don’t know how to do.

That issue aside, without a way to direct your output to another form element, I don’t think you can drive your panel from within Game/MonoGame. On the other hand, trying to run a Game from another control results in two event loops fighting. Ugh. It’s messy and I haven’t had much luck creating anything workable.

I only rate-limit my update loop, but you could do something similar for the draw loop too. You can also hoist it up into your extension of the Game class rather than embedding it deeper in your engine.