public class SimplifiedWinformControl : Control
{
private Game game;
public Texture2D Texture { get; set; }
private SpriteBatch spriteBatch;
public Game Game
{
get { return this.game; }
set
{
// hold onto the game reference
this.game = value;
if (this.game == null) return;
// create the sprite batch
this.spriteBatch = new SpriteBatch(this.game.GraphicsDevice);
}
}
/// <summary>
/// Ignores WinForms paint-background messages. The default implementation
/// would clear the control to the current background color, causing
/// flickering when our OnPaint implementation then immediately draws some
/// other color over the top using the XNA Framework GraphicsDevice.
/// </summary>
protected override void OnPaintBackground(PaintEventArgs pevent)
{
// do nothing here. If this is not overridden the control may have drawing issues O.o
}
protected override void OnPaint(PaintEventArgs e)
{
if (this.game == null)
{
// draw normal winform way
e.Graphics.FillRectangle(System.Drawing.SystemBrushes.Control, this.ClientRectangle);
e.Graphics.DrawString(this.GetType().FullName, this.Font,
System.Drawing.SystemBrushes.ControlText, 0, 0);
}
else
{
// draw xna way
var gr = this.game.GraphicsDevice;
var oldVP = gr.Viewport;
// set the graphics viewport to the size the the controls client area
var newVP = new Viewport() { Width = this.ClientSize.Width,
Height = this.ClientSize.Height,
MinDepth = 0,
MaxDepth = 1 };
gr.Viewport = newVP;
// clear then draw something onto the control
gr.Clear(Color.CornflowerBlue);
this.spriteBatch.Begin();
this.spriteBatch.Draw(this.Texture, Vector2.Zero, Color.White);
this.spriteBatch.End();
// display it onto the control
try
{
var rect = new Rectangle(0, 0, this.ClientSize.Width, this.ClientSize.Height);
gr.Present(rect, null, this.Handle);
}
catch (Exception)
{
// Present might throw if the device became lost while we were
// drawing so we just swallow the exception.
}
// restore previous viewport
gr.Viewport = oldVP;
}
}
protected override void OnCreateControl()
{
// check if we are not in design mode and if not hook into the application idle event
if (!this.DesignMode)
{
// just invalidate the control so that it will be redrawn
// you could also put in some logic to restrict how often the control get invalidated
Application.Idle += ((sender, e) => { this.Invalidate(); });
}
base.OnCreateControl();
}
// not really nessary in this simple example to have a dispose here but i put it in anyway
protected override void Dispose(bool disposing)
{
// perform some cleanup
if (this.spriteBatch != null) this.spriteBatch.Dispose();
this.spriteBatch = null;
// we dont need to dispose of the texture here but I did anyway it will be
// disposed by the content manager. :P But if you have texture(s) you created
// your self then this is where they would get disposed
if (this.Texture != null) this.Texture.Dispose();
this.Texture = null;
base.Dispose(disposing);
}
}