Click here to Skip to main content
15,867,141 members
Articles / Desktop Programming / Windows Forms
Article

Hosting XNA in a Window

Rate me:
Please Sign up or sign in to vote.
4.64/5 (6 votes)
28 Jul 20074 min read 68.2K   47   11
My journey to unravel and discover a solution for hosting XNA in a WinForm UserControl

Introduction

After writing my first article on XNA, my next interest in XNA moved me to figuring out how to host an XNA Window inside a WinForm, so that I can provide additional controls and other UI elements as part of this concept I'm trying to develop. This has proven to be a considerably arduous task.

And while I've made a blog post about my research, I felt that it would be of benefit to the Code Project community to actually have a brief article on the topic, even though I did not come up with the actual solution. Instead, this article:

  • briefly describes the problem
  • takes a quick look at two other solutions I tried
  • presents a list of useful references that I discovered along the way

In the end, I found this website, which provides the C# source code for hosting an XNA Window as a user control. I'm not providing the download here as I didn't write it, so please visit Nuclex's website for the download.

So, the point of making this a Code Project article is to condense into a single article all the blogs and websites I visited to undestand the problem and find the solution. I certainly didn't come across the solution googling for "XNA WinForm". Hopefully, in a few days, other people will find this Code Project article using those keywords!

The First Problem: The Game Class Constructor

The primary problem is that the Game class initializes its own Form rather than letting you specify your Form/Control. This is a silly oversight by the designers. Let's use Reflector to understand the problem:

  1. The Game constructor has a call to EnsureHost
  2. EnsureHost is implemented as:

    C#
    if (this.host == null)
    {
      this.host = new WindowsGameHost(this);

  3. WindowsGameHost instantiates a WindowsGameWindow:

    C#
    public WindowsGameHost(Game game)
    {
      this.game = game;
      this.LockThreadToProcessor();
      this.gameWindow = new WindowsGameWindow();
  4. And WindowsGameWindow finally instantiates the WindowsGameForm, which is derived from Form:

    C#
    public WindowsGameWindow()
    {
      this.mainForm = new WindowsGameForm();

That's problem number one.

The Second Problem: The GraphicsDeviceManager CreateDevice Method

Problem number two is the GraphicsDeviceManager. In your game's derived Game class, you'll have in the constructor:

C#
graphics = new GraphicsDeviceManager(this);

The GraphicsDeviceManager class adds two services:

C#
game.Services.AddService(typeof(IGraphicsDeviceManager), this);
game.Services.AddService(typeof(IGraphicsDeviceService), this);

and then, in the CreateDevice method, the Form control created by the Game constructor is specified as the control host:

C#
GraphicsDevice device = new GraphicsDevice(
  newInfo.Adapter, 
  newInfo.DeviceType, 
  this.game.Window.Handle, // <=====
  newInfo.CreationOptions, 
  newInfo.PresentationParameters);

So the problem is twofold -- the Game class creates its own Form and then that Window is passed to the GraphicsDevice constructor.

Silly Solution #1: Adding Controls to the Game Window

The very first idea I came across cast the GameWindow to a Control and added controls to it. These actually rendered on the XNA Window and worked for things like buttons but did not work for edit controls, I suspect because there is some issue with message processing in the host form, though I never investigated it further.

A Better Solution, But Not Great

The second workaround I found was almost right, hooking the PreparingDeviceSettings and overriding the DeviceWindowHandle:

C#
public Game1(Form form)
{
  graphics = new GraphicsDeviceManager(this);
  content = new ContentManager(Services);
  this.form = form;
  graphics.PreparingDeviceSettings += 
      new EventHandler<PreparingDeviceSettingsEventArgs>
                    (OnPreparingDeviceSettings);
}

void OnPreparingDeviceSettings(object sender, 
                    PreparingDeviceSettingsEventArgs e)
{
  e.GraphicsDeviceInformation.PresentationParameters.DeviceWindowHandle = 
    form.Handle;
}

This (and other solutions I came across) worked fine except that the XNA Window would still appear, requiring a kludge to hide it in the Draw window:

C#
protected override void Draw(GameTime gameTime)
{
  if (firstTime)
  {
    System.Windows.Forms.Control xnaWindow = 
      System.Windows.Forms.Control.FromHandle((this.Window.Handle));
    xnaWindow.Visible = false;
    firstTime = false;
  }
  ...

As well as properly disposing of it:

C#
static class Program
{
  static Game1 game;
  /// <summary>
  /// The main entry point for the application.
  /// </summary>
  static void Main(string[] args)
  {
    Form form = new Form();
    form.Disposed += new EventHandler(OnDisposed);
    form.ClientSize = new System.Drawing.Size(800, 600);
    form.Show();

    using (game = new Game1(form))
    {
      game.Run();
    }
  }

  static void OnDisposed(object sender, EventArgs e)
  {
    game.Exit();
  }
}

Other implementations, which are actually very straight forward (see references) typically eliminate the Game class. This wasn't really my goal, as I wanted to preserve the features of the Game class if at all possible. This led me to the conclusion that I would probably have to use Reflector to recreate specific classes of the framework. At this point, I shelved the whole effort and went back to work that actually pays the bills.

The Nuclex Solution

After putting in some billable hours, I revisited this and I came across a link in a reply to one of the references below that I hadn't checked out, and to my amazement, it was exactly what I was looking for. And indeed, the author does use reflector to recreate certain classes so as to gain control over the dual problems mentioned above. The link is here, and the implementation is very nice -- it's a user control, from which you derive your own class and work with the overridable methods just as you would from the Game class. I ported my test application over in minutes using the Nuclex.GameControl class.

I must say though that I'm still not happy with having to rewrite major sections of the framework. Hopefully the XNA framework architects will fix this problem in the future, and second, I still have a nagging feeling that there must be an easier way.

References

Various references (I found a lot of good information reading the comments as well):

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Architect Interacx
United States United States
Blog: https://marcclifton.wordpress.com/
Home Page: http://www.marcclifton.com
Research: http://www.higherorderprogramming.com/
GitHub: https://github.com/cliftonm

All my life I have been passionate about architecture / software design, as this is the cornerstone to a maintainable and extensible application. As such, I have enjoyed exploring some crazy ideas and discovering that they are not so crazy after all. I also love writing about my ideas and seeing the community response. As a consultant, I've enjoyed working in a wide range of industries such as aerospace, boatyard management, remote sensing, emergency services / data management, and casino operations. I've done a variety of pro-bono work non-profit organizations related to nature conservancy, drug recovery and women's health.

Comments and Discussions

 
GeneralMicrosoft have posted an official example of how to do this now Pin
MarkB7777-Feb-08 9:05
MarkB7777-Feb-08 9:05 
Generalnot using the Game class is easier Pin
Frederic My6-Aug-07 11:39
Frederic My6-Aug-07 11:39 
GeneralRe: not using the Game class is easier Pin
Marc Clifton6-Aug-07 11:48
mvaMarc Clifton6-Aug-07 11:48 
GeneralRe: not using the Game class is easier Pin
Frederic My6-Aug-07 17:18
Frederic My6-Aug-07 17:18 
GeneralInteresting Idea Pin
merlin98131-Jul-07 4:00
professionalmerlin98131-Jul-07 4:00 
Question"XNA"? Pin
Uwe Keim29-Jul-07 5:02
sitebuilderUwe Keim29-Jul-07 5:02 
AnswerRe: "XNA"? Pin
Marc Clifton29-Jul-07 5:26
mvaMarc Clifton29-Jul-07 5:26 
GeneralRe: "XNA"? Pin
Uwe Keim29-Jul-07 6:03
sitebuilderUwe Keim29-Jul-07 6:03 
Ah, I see. I wasn't even aware that it's about game programming. I couldn't deduct the context of the article at all.

--
Zeta Producer Desktop CMS
Intuitive, completely easy-to-use CMS for Windows.

Zeta Helpdesk
Open Source ticket software for Windows and web.

Zeta Uploader
Easily send large files by e-mail. Windows and web client.

Desargues
Innovative, lean and neat calculator for Windows.

GeneralRe: "XNA"? Pin
Marc Clifton29-Jul-07 8:41
mvaMarc Clifton29-Jul-07 8:41 
GeneralRe: "XNA"? Pin
xcorporation14-Aug-10 9:08
xcorporation14-Aug-10 9:08 
GeneralCool :-) Pin
Lukasz Sw.29-Jul-07 4:03
Lukasz Sw.29-Jul-07 4:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.