No longer updated: new and updated blog (including old content) at http://roy-t.nl

Archive for http://roy-t.nl, please update your bookmarks

XNA 3.0 and Winforms, the easy way

Posted by Roy Triesscheijn on Thursday 9 October, 2008

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

About these ads

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

  1. McCoder said

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

  2. 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 said

    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. 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 said

    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.

    • 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?

  6. Pdub87 said

    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.

    • 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. :)

  7. meeeeself said

    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!!!!!

  8. Stephen said

    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.

  9. @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)

  10. Chris Paul said

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

  11. ojrac said

    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();
    }

  12. grapher said

    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();
    }
    }

  13. grapher said

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

    • 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.

  14. Tomahawk said

    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

    • 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 :).

      • Tomahawk said

        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).

  15. Tomahawk said

    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.

  16. bsofman said

    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.

  17. Toda said

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

  18. Toda said

    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.

    • Toda said

      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

  19. Tomahawk said

    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.

  20. Shuya said

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

    • 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 )

    • nstod said

      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.

  21. Woj said

    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

  22. Notahappybunny said

    Nah, much better on creators site – sorry!

  23. Christopher Harris said

    Roy,

    Thanks for the post. I like this method a lot better than the XNA site’s version. For anyone who knows how to program in C#, your tutorial was very helpful and informative :)

  24. Roy Triesscheijn, thank you so much for creating this brief example for using winforms (a picture box from it) as a canvas for Xna. It’s saved me from using deprecated MDX or GDI+ for my application that needs accelerated 2D image support. I have been uncomfortable with switching to WPL, so I still use winforms for all my applications. I stick with what works well since I have so many custom controls and tricks for it when I develop my open source applications. Thanks again for all of your help; you’re a life saver!

    • As for those stating that you can’t access the Xna class from your winforms class, here’s a quick fix to add a reference of the Xna class’ instance. Using the example’s name scheme…

      First, create a property and constructor in your winform class:

      private game;

      public Game1 Game
      {
      get
      {
      return game;
      }
      set
      {
      game = value;
      }
      }

      Then change your program.cs’ void static main to this (from the example):

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

      Simple. Then you can set properties, constructors, and methods in your Xna class (Game1) to public to access via your winforms class.

      Example: Game.doSomething();

      Most C# developers would have figured this out on their own, so this is for new C#/Xna programmers. I use this mostly to resize and move sprites, as I can access the Xna Content pipeline from my winforms class without talking to any instance of my Xna class. I hope that helps others Googling for this in the future. :)

      • Raj said

        Hi cipher_nemo,
        i am stuck in similar problem ..
        could you please elaborate or show me complete code of winform class ???

        actuaaly i m trying to send some values from radiobutton in form to the game

        thank you

  25. Cue said

    Hi, thanks for this wonderful post.

    Can someone give me codes on how to add more than 1 XNA picture boxes in the form? Please i need it.

  26. Pato said

    Hi Roy, I have question, if I want that a button pressed at the forms affects something into the xna game class. For example, if I want to load a model, when a button is pressed at the forms, how can I do this?

  27. haxpor said

    Hey thanks so much for this such great technique.

    I would love to know the drawback for this technique as well as compared to the original way doing in creators’ sample. But from my point of view, in that creators’ sample, we have to handle a time issue manually.

    Thx

  28. Migel Anjel said

    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. ^_^

  29. Sam said

    hello
    nice post…., i however, find a problem with this, it executes then a meassage is launched telling me, “no suitable graphic card was found” it also says something about Direct3D not being able to be found for support of XNA framework, knowing that i have another Visual studio project open and it executes just fine. very weird. mayne i am missing something. i am using the latest sutff, XNA framework 4.0, VS 2010. Could you tell me if possible what could be the issue

  30. That’s because it requires XNA 3.0, not 4.0… Anyway updated stuff is at http://roy-t.nl (seriously can’t make that header any bigger :P)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.

%d bloggers like this: