Add XNA Form controls

August 8, 2009 6:34 PM Published by

Below 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:


Tag Cloud