XNA 3.0 and Winforms, the easy way

There are many tutorials on XNA and Winforms, however none of them seem very easy, but after reading a post from ‘madman’ on Ziggyware.com and fiddleing around it seems very easy  to do, easier than the creators example.

In short we adjust the game1.cs to draw to a picturebox instead of drawing to the window that is created for it. The code is very easy to understand (as it’s only 10lines of code) and performs superb, without the use of ugly timers and all that stuff.

Firstoff create a new XNA3.0 Windows  project in  Visual Studio 2008 (Express) (this code will probably work just fine in XNA2.0/Visual Studio 2005 (Express))

Add a Form to it the usual way, and drag a picturebox to it. Call the picturebox pctSurface.

Then go into the code view of your  form and write the following code:


public IntPtr getDrawSurface()
{
    return pctSurface.Handle;
}

This code will give us the Handle to the picturebox which we will later use to draw our game to.

Now open up game1.cs add the variable ‘private IntPtr drawSurface;’ and change the constructor to look like this:


public Game1(IntPtr drawSurface)
{
              graphics = new GraphicsDeviceManager(this);
              Content.RootDirectory = "Content";
              this.drawSurface = drawSurface;
              graphics.PreparingDeviceSettings +=
              new EventHandler<preparingDeviceSettingsEventArgs>(graphics_PreparingDeviceSettings);
              System.Windows.Forms.Control.FromHandle((this.Window.Handle)).VisibleChanged +=
              new EventHandler(Game1_VisibleChanged);            
}

And add these 2 eventhandlers

        /// <summary>
        /// Event capturing the construction of a draw surface and makes sure this gets redirected to
        /// a predesignated drawsurface marked by pointer drawSurface
        /// </summary>
        ///
<param name="sender"></param>
        ///
<param name="e"></param>
        void graphics_PreparingDeviceSettings(object sender, PreparingDeviceSettingsEventArgs e)
        {
                e.GraphicsDeviceInformation.PresentationParameters.DeviceWindowHandle =
                drawSurface;
        }

        /// <summary>
        /// Occurs when the original gamewindows' visibility changes and makes sure it stays invisible
        /// </summary>
        ///
<param name="sender"></param>
        ///
<param name="e"></param>
        private void Game1_VisibleChanged(object sender, EventArgs e)
        {
                if (System.Windows.Forms.Control.FromHandle((this.Window.Handle)).Visible == true)
                    System.Windows.Forms.Control.FromHandle((this.Window.Handle)).Visible = false;
        }
 

Now we are almost done, change program.cs’ static void main to this:


static void Main(string[] args)
{
              formMain form = new formMain();
              form.Show();
              Game1 game = new Game1(form.getDrawSurface());
              game.Run();            
}

Now to make sure your application really exits when closing your form add the code

Application.Exit();

to your button and windowclosed eventhandler!

Thats it, run the code and you’ll see your wonderfull Form with a blue square where you’ve located your pictureBox! Now you can change your game1.cs as normal, use your contentmanager and content project as normal, and use windowsforms for an excellent  userinterface for your editor.

Note: this will not work on the Xbox360 since it doesn’t have WinForms
Note2: you might see a window for a few ms when starting your app. This is the old window that used to be drawn to, unfortunately I haven’t figured out how to get rid of it completely, but the eventhandler will hide it the first time it shows.

The sourcode can be downloaded here: sourcecode.
in the example I also created a spriteBatch and spriteFont to show you can really draw!

XNA3.0 In Winforms in action, notice the pictureBox borderstyle3d effect
(notice the picturebox’ borderstyle settings affecting the rendering, here it adds a nice 3D border)

Update: since I couldn’t believe the XNA devs being less smart than I am, I asked around at the creators forums and landed in a discussion between, Shawn Hargreaves, theZman and myself. According to Shawn this sollution might work properly but its not tested and he says that there might be border cases where this sollution will stop working (drawsurface may invalidate etc..) The creators example is guaranteed to work 100%, however in my eyes it still a bit bulky and hard to understand, that code may be necessairy to let everything work properly, even on strange hardware configurations etc. Also the input logic in the update loop might not work properly. I myself haven’t encountered any of these problems yet but it’s a thing to keep in mind.

My advice: creating an editor just for yourself, or anyway just for devs, you can safely use this sample. If your going to make code that has to ship to other users, you might want to reconsider.

You could also look at this topic: Shawn Hargreaves in the Creators forums

kick it on GameDevKicks.com

47 Responses to “XNA 3.0 and Winforms, the easy way”

  1. McCoder says:

    How would you load a model using the load file dialog in .NET?

  2. royalexander says:

    McCoder, there is an example on creators.xna.com on content loading with the load file dialog. It’s a bit complicated since you have to tell the contentManager to built the game at runtime (and this can only be done if you have XNA3 installed, and I dont mean the redist, I mean full XNA3+C#2008, so it cant be done on the xbox360).

  3. Lueyyou says:

    Hi there, sorry to ask what must seem like a really obvious question, I’m new to XNA development and would like to develop a character editor with Windows form controls.

    How do you actually get access to the XNA objects such as spriteBatch from the Windows controls?

  4. royalexander says:

    Hey Lueyyou, when you use this way to use winforms, you can use the spritebatch etc exactly the same as when using XNa normally.

    (e.g. just create a new SpriteBatch spritebatch = new SpriteBatch(Graphics.graphicsDevice) and start drawing in the draw method :) )

    Good luck!

  5. Pdub87 says:

    I really don’t know about this method… sure, you’ve got the game drawing onto a winform. The better question is, so how do you plan on accessing the game/whats being drawn from the winform? Pass a bunch of shit through the form’s constructor, or what? There’s no point in routing the graphics to a picturebox if you can’t access any of the game content from the form.

  6. royalexander says:

    Hey Pdub87, thx for reading this article.

    About your criticique, it’s actually super simple to get acces to Content, you dont have to pass anything at all to the form. As you might know buttons and well almost everything that is going on on a winform happens with Events. You can simple listen to an event in your Game1.cs class and act on it. Also, even when you are drawing on winforms, you can acces input via XNA’s normal way: Keyboard.GetState() and GamePad.GetState().

    You can also fire dialogue boxes and everything from your game class.

    Tbh I dont really understand your critique since communicating this way is exactly the same as, for example an database backend would communicate with a form. Or any other ‘big’-application that uses forms. Maybe you’ve only made Winforms programs yet where the logic fitted into your forms class?

  7. Pdub87 says:

    I asked simply because other posters have asked the same question and you didn’t answer. This is a tut on using XNA on a WinForm, but you don’t show how you would access any of the graphics from the winform.

    Lueyyou said: “How do you actually get access to the XNA objects such as spriteBatch from the Windows controls?”- you didn’t answer his question. Of course we all know what a spritebatch is, and how to instantiate one- that’s not what he was asking!!

    You don’t want to listen for events from the game class. The sole reason you would want to use Winforms with XNA is generally to create an editor so that you could do the opposite- use XNA for graphics while using the winform’s controls to manipulate the graphics.

    The Winforms example isn’t bulky (500 lines of code?), and it’s actually very easy to understand and implement- you don’t even have to understand how it works because you don’t have to change any of it!! There’s the GraphicsDeviceService, ServiceContainer, and the GraphicsDeviceControl. Derive your own control from GraphicsDeviceControl and do all your graphics from there. Your windows form then interacts with your custom graphics device control- everything you need, your variables, your graphics, they can all be manipulated from within your custom control. It’s very simple!

    My critique is simple to understand. You have shown a clever way to hook the XNA graphics to a windows form using a minimal amount of code. However, the tutorial doesn’t elaborate on the whole reason WHY you would want to use windows forms- use the form controls to manipulate the graphics. At a minimum you should show how you would change the text displayed from the windows form.

  8. royalexander says:

    I’m sorry if I was a bit unclear earlier. But communicating with a form was (to me) a bit outside the scope of this small sample. Thats all it is a small sample to get that code drawn in a form quickly.

    Ofcourse the WinForms example has its uses, frankly I use it myself for one of my apps (an UV-painter). And it’s very good sollid [b]supported[/b] code! I’ve added an update to the article stating just that a long time ago.

    However I do think that this code will have it uses aswell, especially because it’s not using the idle-hook to draw the code. (Some people frown upon it, others think it’s good practice, tbh it depends on the program you are trying to create). And ofcourse you dont even have to understand the sample as long as you know where the draw and update method are. Also I’ve marked the example as pritty bulky because almost the same thing can be acomplished with 3 lines of code vs 500 lines.

    You can get the same behaviour you want (control like behaviour so to speak) if you send your Game1.cs class via a method or contructor to the form (so only 1 object, not very much as you’ve said) THat way the form can manipulate the control using its public props and methods, instead of that the ‘Control’ drives the form.

    That way you can just change text like this in the button_clicked event:

    myGame.SetDrawText(SomeVector2, textbox1.text); 

    .

    But by all means, for apps you are going to distribute you should use the winforms example because it is supported code, and this code I ‘made’ is not. Also take a look at the 2nd sample where you invoke MSBuild to pack models into xnb files at runtime so you can really make a nice (3D) editor, you can even make viewports and such.

    This is just a simple hack to get it done fast for testing or inhouse tools, just that, and that is stated in the article a few times. :)

  9. meeeeself says:

    Dude,
    u r prezently my king of kings
    I luv it when m$ looks like a buncha foolz
    haha
    lol
    im sure you’re way will have edge cases that break
    but sh*t man, i’m prototyping and ain’t got time to f around with porting everything and my mother’s uncle from xna 3 to winforms
    thx a jillion, bra
    much luv!!!!!

  10. royalexander says:

    Eh, ok :) but MS are no fools, their way IS better in typical cases, but this is faster and indeed very suited for prototyping, glad you liked it!

  11. Stephen says:

    When I used your sample, there were all sorts of weird stretching problems when I would resize the picturebox. To fix this, I simply added:

    e.GraphicsDeviceInformation.PresentationParameters.BackBufferHeight = 1280; //width of picturebox
    e.GraphicsDeviceInformation.PresentationParameters.BackBufferWidth = 720; //height of picturebox

    Hopes this helps someone so they don’t waste lots of time wondering about it too.

  12. royalexander says:

    @Stephen, that’s a good tip, you can tie it into the controls resize event to dynamically resize the backbuffer. (It is usually best to only scale the backbuffer up if it becomes to small, but not scale it down)

  13. Chris Paul says:

    Hey! Thanks for the post man, this is extremely helpful! I got Winforms up and running in minutes!

  14. ojrac says:

    Excellent post. I was having some trouble with the process not exiting after I’d closed the form, so I made the Game reference static, and added the following event listeners before Game.Run():

    form.FormClosing += new FormClosingEventHandler(gameForm_FormClosing);
    game.Exiting += new EventHandler(game_Exiting);

    // …and, later down:
    static void game_Exiting(object sender, EventArgs e) {
    Application.Exit();
    }

    static void gameForm_FormClosing(object sender, FormClosingEventArgs e) {
    game.Exit();
    }

  15. grapher says:

    Nice post.

    I add constructor without arguments and DrawSurface property to set surface handle when it really need. Draw method draw nothing. What happends?

    public Game1()
    {
    Content.RootDirectory = “Content”;
    mString = “Hello World!\n”;
    System.Windows.Forms.Control.FromHandle((this.Window.Handle)).VisibleChanged += new EventHandler(Game1_VisibleChanged);
    }

    public IntPtr DrawSurface
    {
    get { return drawSurface; }
    set
    {
    this.drawSurface = value;
    graphics = new GraphicsDeviceManager(this);
    graphics.PreparingDeviceSettings += new EventHandler(graphics_PreparingDeviceSettings);
    graphics.ApplyChanges();
    Initialize();
    }
    }

  16. royalexander says:

    Hey grapher, I’m not sure what you did there, could you explain the problem a little bit more?

  17. grapher says:

    I want to create a draw surface and graphics subsystem after some user work and at the moment when user really want it.

  18. royalexander says:

    Ok but how doesn’t the code work for you? You could also try the new winforms tutorials at creators.xna.com they’ve updated that section long after I’ve written this and have written a completely bug proof sollution where all you need todo is to drag a usercontrol to your form.

  19. Tomahawk says:

    Thanks for helpful example !

    I’m creating a game, which is a hybrid of standard XNA Game and Winforms. I’d like to perform this task by having two game windows – main windows and statistics window, using Winforms. Generally I’ve tried an approach with setting DeviceWindowHandle either to “System.IntPtr.Zero” for “normal game display” or to “drawSurface” for second screen with Winforms. This DeviceWindowHandle is being set in EventHandler for GraphicsDeviceManager.PreparingDeviceSettings, which is called e.g. when GraphicDevice is reset. Thus I’ve called GraphicsDevice.Reset() but the debugger doesn’t hit graphics_PreparingDeviceSettings() second time, after this event is raised. Do you know the reason or maybe you know better way to switch between game window and form window ?

    Thanks

  20. royalexander says:

    Maybe you could spam the two XNA instances in seperate threads so that they both have their own resource pool and won’t interfer with each other. Not sure if XNA/DirectX is gonna like that though. You could also take a look at the samples at creators.xna.com which where updated after I wrote this tutorial, they show you how to make a “XnaUserControl” so you can drag and drop multiple instances to your form and probably accompish what you want :).

  21. Tomahawk says:

    I don’t persist in Winforms to take use of some controls, that enable me to display statistics or display game elements by using DropDown list. I’m not perfect with .NET knowledge and this Winforms are the only way, that I know to have these controls. Maybe do you know any alternative way in XNA itself to take use of such functionallity ? (I don’t belive, that to display any list or table or even dropdown list we need to engage Winforms).

  22. royalexander says:

    Yeah the simplest sollution I see atm is todo it the other way around by having a xna control as from creators.xna.com and place your other controls like lists over it.

    But you could also look at a few pretty good toolkits for XNA like: http://www.nuclex.org/news/2007/01/14/ceguisharp (see the last comment on where to download it). Or others (see http://forums.xna.com/forums/p/1891/9461.aspx for a few alternatives).

  23. Tomahawk says:

    Thanks Royalexander :)

    I’ve really started to affraid, that XNA is so simply, that any step aside as adding controls will kill the idea of simply Framework…

    I’ll try now, what these GUI solutions are worth of.

  24. royalexander says:

    Ah yeah it’s really just a very nice wrapper around DirectX, that’s all, all the bricks to create a great game are there but it’s just bricks no prefabs. :)

  25. bsofman says:

    Hi,

    Thank you for this post — it was exactly what I was looking for. I have one issue that I’m sure someone else has run into that could maybe help me:

    If I launch my game object on its own, everything looks great, I get high resolution models to show up, life is good. However, when I pipe the output of the game object into the forms picture box as suggested here, it basically gets downsampled to what seems like the original resolution of the form so when the window is increased in size it looks noticeably more pixelated and low-res.

    Is there any way to have this picture window in the form display the game output at full quality?

    Many thanks in advance.

  26. Toda says:

    How do I get the REAL mouse coordinates? With real I mean the one on the gamescreen(not on the whole monitor)?

  27. Toda says:

    How stupid am I … :D.

    Mouse.WindowHandle = drawSurface;

    in the Game1 constructor! drawSurface is a handler so … now I am ready to get my level editor running!

  28. Toda says:

    Can someone show an example of how to access a buttonpressed event from say a gamecomponent? It’s really the final puzzle I need to solve.

  29. royalexander says:

    Hey Toda, you should just make a method yourself that substracts the left of the gamescreencomponent from the x coordinate of the mouse (and the same for the top of the gsc and the y of the mouse).

  30. Toda says:

    Actually I do not have to. That method works great.

  31. Toda says:

    Im not good with delegates but I sourt of found one solution.
    Instead of passing the IntPtr to game I did:

    Form1 form = new Form1();
    form.Show();
    Game1 game = new Game1(form);

    In program.cs

    Then in the constructor of game1:

    {
    ...
    System.Windows.Forms.Button.FromHandle(form.getMyButton1Handle()).Click += new EventHandler(do_something_when buttonpressed);
    }

    do_something_when buttonpressed(object sender, EventArgs e)
    {
    //Do the code here like:
    mygameobject.setEnemySpawnType(1);
    }

    And in the form class(Form1.cs):

    public IntPtr getMyButton1Handle()
    {
    return mybutton.Handle;
    }

    I would rather catch the events in the specific gameobject but don’t know how. This way works as long as the gameclass has a reference to the class whos method needs to be called. I do NOT however know for instance if I have a textfield, how do I get the value there?

    My knowledge in handlers and delegates are close to 0, just by trial and error and googling I found this solution

  32. Tomahawk says:

    Guys,

    I’ve got really nice effect engaging xWinForms, the beta version. Although it needs to be adjusted to your needs, you’ve got many Controls available. The downside is missing documentation and you must recognize product on your own. Look at demo of 1.0 version on youtube.
    I’ve managed to get application with one window, which is basic XNA game window and second window containing WinForms. Really good software.

  33. Toda says:

    The nly problem is that it recognises mouse presses outside the picturearea, argh!

  34. Shuya says:

    It’s quite slow. =/ If you redirect the XNA window into a PictureBox you won’t get the same FPS.

  35. royalexander says:

    I haven’t seen any fps differences at all tbh, but maybe you do some heavy stuff in your winforms? Anyway try the creators example to see if that one gives you a better example. ( http://www.creators.xna.com )

  36. nstod says:

    Hey, just wanted to give you a heads up on this. I, too, thought this was extremely slow, until I figured out that it’s only really slow if your window is not active. If you de-activate the window and then re-activate it (by clicking on another window then clicking back), you should see a dramatic increase in FPS.

    An easy way to fix this is to set your Game.InactiveSleepTime parameter. If you set it to System.TimeSpan.Zero, your game will run full speed all the time. I personally have mine set to 10000 ticks so it doesn’t use a full CPU core when inactive, but doesn’t come to a halt. Give that a shot.

  37. Woj says:

    i have a treeview control on the form that has a list of objects that i can select to add to my scene. everything except xna keyboard input is working. I want to use W, A, S, D to move my camera around however whenever i hit any keyboard buttons it only selects the corresponding item in the tree view instead of using using KeyboardState.IsKeyDown(Keys.W) etc.

    I got the mouse working fine using Mouse.WindowHandle = drawSurce, however i dont see an option do to this for the keyboard. I assume it has something to do with the current focus, but i’m not sure how to approach the solution.

    Thanks

  38. Woj says:

    figured it out, my fault. just wasn’t updating camera movement… embarrassing…

  39. Shaun says:

    I seem to be having an issue here. Im not the greatest with C#, but Im trying to add scrollbars to my picturebox. I have set the visibility property of them to false. In the game1.cs, in the initialize, im trying to make it so that I can make the scroll bars visible if the picturebox is smaller than the map im working on. I cannot seem to access the forms controls though. How do I access the form from the game1.cs file? Thanks in advance for the help.

  40. You have to have a reference to either the game in the form, or the form in the game. This is easiest done via a static field in the game class, because this way you can always reference it from outside without knowing the instance (and you’re going to only have on instance from the game anyway).

  41. Shaun says:

    Could you show me an example? Right now im putting handles in the constructor for each of the objects on the form that I need to control in the game. I know thats probably not the best way to do it. By reference, do you mean something like
    public Game1
    private Form1 form = new Form1();

    ?
    I tried that, but to no avail. Thanks again for the help.

  42. Miguel Angel says:

    Hi dude.
    Hey, i’m currently using your code, and it works great.
    I was wondering, is there any way you could think of that could help me putting 2 independent XNA Game on the same WinForm?

    I tryed to duplicate the code you provided here, with new pictureBox and new game class (cleverly called Game2) but it’s not showing anything in the second pictureBox…

    Thanks dude, your idea is great and it has been reeeeaally useful to me. ^_^

  43. Hmm, good question, just creating 2 instances in the program.cs and giving them both a different handle doesnt work?

  44. Miguel Angel says:

    Noup…
    Clearly i’m doing something wrong, but i can’t see what it is…
    This is how my Program class looks now.

    using System;
    using System.Windows.Forms;

    namespace PrototipoPlanoBrujulaWinform
    {
    static class Program
    {
    ///
    /// The main entry point for the application.
    ///
    static FormMain form;
    static Game1 game;
    static Game2 game2;

    static void Main(string[] args)
    {
    form = new FormMain();
    form.Show();
    game = new Game1(form.getDrawSurface());
    game.Run();
    game2 = new Game2(form.getDrawSurface2());
    game2.Run();
    }

    static void CloseGame(object sender, FormClosingEventArgs e)
    {
    game.Exit();
    game2.Exit();
    Application.Exit();
    }
    }
    }

    Here, the method form.getDrawSurface2() work just like getDrawSurface(), but it returns my 2nd PictureBox

  45. Hazim says:

    Hi
    i didn’t find the source code
    can you provide it for GS4.0 and VS 2010 please

  46. Hey Hazim,

    I don’t have readiliy available source code for this, but the trick should still work in GS4. Though you’re probably better off with the Winforms example on http://create.msdn.com or the XAML example by Nick Gravelyn http://blogs.msdn.com/b/nicgrave/archive/2010/07/25/rendering-with-xna-framework-4-0-inside-of-a-wpf-application.aspx

Leave a Reply