Add XNA Form controls
August 8, 2009 6:34 PMBelow is a game component which when added to a game will watch for new controls being added to the game’s underlying form. It will listen to the controls Paint event, and draw them to a Bitmap followed by converting that bitmap to a Texture2D (via MemoryStream). While mouse input works, keyboard input doesn’t, I might update this later after I figure out a way to reroute the input without disturbing XNA’s keyboard mechanics.
The component:
/// <summary> /// This game component will watch the Xna Game Form for System.Windows.Forms.Control being /// added to it and take the appropriate actions to get those controls onto the back-buffer /// as they would appear on a normal System.Windows.Forms.Form. /// </summary> public class ControlComponent : DrawableGameComponent{ private class ControlInstance : IDisposable{ private Control myControl; private Texture2D myTexture; private Rectangle myDestination; private bool isPaintRequired; public Control Control { get { return myControl; } } public ControlInstance(Control control){ myControl = control; myDestination = new Rectangle(); isPaintRequired = true; if (myControl != null && !myControl.IsDisposed)myControl.Paint += new PaintEventHandler(Control_Paint); } public void Update(){ Control currentControl = myControl; myDestination.Location = Point.Zero; while (currentControl != null){ myDestination.X += currentControl.Location.X; myDestination.Y += currentControl.Location.Y; currentControl = myControl.Parent; } currentControl = null; if (myDestination.Width != myControl.Width){ myDestination.Width = myControl.Width; isPaintRequired = true; } if (myDestination.Height != myControl.Height){ myDestination.Height = myControl.Height; isPaintRequired = true; } } public void Draw(SpriteBatch batch){ if (isPaintRequired){ using (System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(myDestination.Width, myDestination.Height)){ myControl.DrawToBitmap(bitmap, new System.Drawing.Rectangle(0, 0, myDestination.Width, myDestination.Height)); using (MemoryStream stream = new MemoryStream()){ bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Png); stream.Seek(0, SeekOrigin.Begin); myTexture = Texture2D.FromFile(batch.GraphicsDevice, stream); } } isPaintRequired = false; } if (myTexture != null && !myTexture.IsDisposed)batch.Draw(myTexture, myDestination, Color.White); } private void Control_Paint(object sender, PaintEventArgs e) { isPaintRequired = true; } #region IDisposable Memberspublic void Dispose(){ if (myControl != null){ if (myControl != null && !myControl.IsDisposed)myControl.Paint -= new PaintEventHandler(Control_Paint); myControl = null; } if (myTexture != null){ if (!myTexture.IsDisposed)myTexture.Dispose(); myTexture = null; } GC.SuppressFinalize(this); } #endregion } private class ControlInstanceCollection : KeyedCollection<Control, ControlInstance>{ protected override Control GetKeyForItem(ControlInstance item){ return item.Control; } } private Form myGameForm; private SpriteBatch myBatch; private ControlInstanceCollection myControls; /// <summary> /// Create a new ControlComponent. /// </summary> /// <param name="game">The game the ControlComponent should be asociated with.</param> public ControlComponent(Game game) : base(game){ myControls = new ControlInstanceCollection(); myGameForm = (Form)Control.FromHandle(game.Window.Handle); myGameForm.ControlAdded += new ControlEventHandler(GameForm_ControlAdded); myGameForm.ControlRemoved += new ControlEventHandler(GameForm_ControlRemoved); } protected override void LoadContent(){ base.LoadContent(); if (myBatch == null)myBatch = new SpriteBatch(GraphicsDevice); } protected override void Dispose(bool disposing){ for (int i = 0; i < myControls.Count; i++)myControls[i].Dispose(); if (myBatch != null)myBatch = null; base.Dispose(disposing); } /// <summary> /// Update the information stored about each control. /// </summary> public override void Update(GameTime gameTime){ base.Update(gameTime); for (int i = 0; i < myControls.Count; i++)myControls[i].Update(); } /// <summary> /// Draw all of the controls. /// </summary> public override void Draw(GameTime gameTime){ base.Draw(gameTime); myBatch.Begin(); for (int i = 0; i < myControls.Count; i++)myControls[i].Draw(myBatch); myBatch.End(); } private void GameForm_ControlAdded(object sender, ControlEventArgs e){ // Need to check for the form because it will pop up in control added if (sender == myGameForm) return; Control control = (Control)sender; if (control != null && !myControls.Contains(control)){ myControls.Add(new ControlInstance(control)); control.Disposed += new EventHandler(Control_Disposed); } } private void GameForm_ControlRemoved(object sender, ControlEventArgs e){ Control control = (Control)sender; if (control != null && myControls.Contains(control)){ myControls[control].Dispose(); myControls.Remove(control); control.Disposed -= new EventHandler(Control_Disposed); } } private void Control_Disposed(object sender, EventArgs e){ Control control = (Control)sender; if (myControls.Contains(control)){ myControls[control].Dispose(); myControls.Remove(control); } } }
http://ziggyware.com/forum/viewthread.php?forum_id=29&thread_id=13579
Example game using this component:
public class Game1 : Game { GraphicsDeviceManager myGraphics; ControlComponent myControls; public Game1() { myGraphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; myControls = new ControlComponent(this); Components.Add(myControls); Button btn = new Button(); btn.Text = "Button0"; TextBox tb = new TextBox(); tb.Location = new System.Drawing.Point(40, 40); tb.Multiline = true; tb.Size = new System.Drawing.Size(200, 100); Form gameForm = (Form)Control.FromHandle(Window.Handle); gameForm.Controls.Add(btn); gameForm.Controls.Add(tb); } protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); base.Draw(gameTime); } }
Categorised in: XNA