RenderSurface
The three modes
RenderSurface has three real usage modes. Two of them are managed modes, where the control owns an offscreen render target and asks you to draw into it. The first is a manual presentation mode, where you provide the finished surface yourself.
Mode 1
Manual surface mode
You provide an ImageSource or Texture2D. The control just presents it and participates in layout like any other surface presenter.
Mode 2
DrawSurface event mode
You subscribe to DrawSurface. The control creates an offscreen target, gives you a SpriteBatch and bounds rectangle, and you draw into it.
Mode 3
Subclass override mode
You derive from RenderSurface and override OnDrawSurface. This is the most reusable and encapsulated mode.
Mode 1: Manual surface mode
Use this when some other part of the app already produces a texture or image and your UI only needs to display it. This is the cleanest mode when the gameplay or simulation side already owns the rendering pipeline.
This is also the mode used by the CPU-backed demo in the repository. The demo renders into a texture, calls Present(_surfaceTexture), and later calls RefreshSurface() after uploading new pixel data.
public sealed class MiniMapHostView : UserControl
{
private readonly RenderSurface? _miniMapSurface;
private Texture2D? _miniMapTexture;
public MiniMapHostView()
{
InitializeComponent();
_miniMapSurface = this.FindName("MiniMapSurface") as RenderSurface;
}
private void PublishLatestMiniMap(Texture2D texture)
{
_miniMapTexture = texture;
_miniMapSurface?.Present(texture);
_miniMapSurface?.RefreshSurface();
}
}
Mode 2: DrawSurface event mode
Use this when you want the control to own the offscreen target, but you do not want to create a custom subclass. You attach an event handler and draw with MonoGame primitives directly into the surface.
This is the mode used by the GPU demo in the repository. The view subscribes to _gameSurface.DrawSurface += OnDrawGameSurface;, draws into the supplied SpriteBatch, and invalidates the control whenever a redraw is needed.
private void OnDrawMiniMap(SpriteBatch spriteBatch, Rectangle bounds)
{
// Draw your game visualization here.
}
Mode 3: Subclass override mode
Use this when RenderSurface is becoming a real reusable control in your UI layer. Instead of wiring event handlers from outside, you encapsulate the drawing behavior inside a type.
A subclass enters managed mode automatically if it overrides OnDrawSurface. This means no external event subscription is required.
public sealed class MiniMapSurface : RenderSurface
{
protected override bool IsFrameUpdateActive => true;
protected override void OnFrameUpdate(GameTime gameTime)
{
InvalidateVisual();
}
protected override void OnDrawSurface(SpriteBatch spriteBatch, Rectangle bounds)
{
// Draw the control's content here.
}
}