UPDATE: Since originally asking this question, I have changed my approach slightly. Rather than drawing using System.Drawing.Graphics
, I am hosting a WPF user control with an InkCanvas. That does everything I need it to do. The problem still is that I cannot get the background of the ElementHost to be transparent. I see the same black square I was seeing before.
ORIGINAL QUESTION: I have a C# WinForms application that renders a 3D scene using Ogre3D to a panel in the form using that panel's handle. I am trying to add the ability to draw on top of that scene (imagine Madden drawing over the TV screen) using C#'s System.Drawing.Graphics
.
I'm using the BufferedGraphics
class to do this. As a test, I'm trying to simply draw a rectangle on top of the 3D scene. Below is a snippet of the code I'm using to set everything up.
namespace TestApp
{
public partial class TestForm
{
private BufferedGraphics graphicsBuffer;
private BufferedGraphicsContext bufferContext = BufferedGraphicsManager.Current;
public TestForm()
{
InitializeComponent();
UpdateGraphicsBuffer();
}
private void UpdateGraphicsBuffer()
{
bufferContext.MaximumBuffer = new Size(panelRender.Width + 1, panelRender.Height + 1);
graphicsBuffer = bufferContext.Allocate(Graphics.FromHwnd(panelRender.Handle), new Rectangle(49, 49, 100, 100));
graphicsBuffer.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
}
private void TestForm_Load(object sender, EventArgs e)
{
graphicsBuffer.Graphics.DrawRectangle(new Pen(Color.Red), 50, 50, 50, 50);
}
}
}
I've left out a lot of the proprietary code (there is a call to graphicsBuffer.Render();
in part of that proprietary code) and renamed some stuff but hopefully what I have provided will give you the gist. Also, the 3D scene is also using panelRender.Handle
to draw into that panel, and the panelRender.BackColor
is black.
In a nutshell, what I am seeing is a chunk of my 3D scene missing (specifically a 100x100 chunk) with the 50x50 red rectangle drawn inside it, as pictured here:
Obviously I don't want to lose the scene that I'm trying to draw on top of. Right now, I'm at a loss as to why this is happening. Is what I'm trying to do just not possible? If any additional information/code is needed, I will be happy to provide it, if possible.
EDIT: To try and simplify matters, I created a really simple WinForms app that has a single panel and used the code above to recreate the issue. The code-behind for that is here:
using System.Drawing;
using System.Windows.Forms;
namespace DoubleBufferTest
{
public partial class Form1 : Form
{
private BufferedGraphics graphicsBuffer = null;
private BufferedGraphicsContext bufferContext = BufferedGraphicsManager.Current;
public Form1()
{
this.SetStyle(ControlStyles.SupportsTransparentBackColor | ControlStyles.UserPaint, true);
this.UpdateStyles();
InitializeComponent();
UpdateGraphicsBuffer();
}
private void UpdateGraphicsBuffer()
{
bufferContext.MaximumBuffer = new Size(panel1.Width + 1, panel1.Height + 1);
graphicsBuffer = bufferContext.Allocate(Graphics.FromHwnd(panel1.Handle), new Rectangle(10, 10, 50, 50));
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
graphicsBuffer.Graphics.DrawRectangle(new Pen(Color.Red, 3.0f), 20, 20, 10, 10);
graphicsBuffer.Render();
}
}
}
The panel's backcolor is set to transparent. Here is the result:
That black square corresponds to the graphics buffer that is getting allocated by the context. Why it always shows up as black is basically what is confusing me now...
Thank you to @Ron Beyer for answering this for me in a different question I posted.
So I was on the right track with the ElementHost
control, but because of the transparency issues, Ron suggested that I try using a new WPF window that I could overlay on top of the application (link). The WPF window's background is set to transparent, so drawing on the InkCanvas results in the desired effect.