BufferedGraphics
Provides a graphics buffer for double buffering.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Windows.Win32;
using Windows.Win32.Graphics.Gdi;
namespace System.Drawing
{
[NullableContext(1)]
[Nullable(0)]
public sealed class BufferedGraphics : IDisposable
{
[Nullable(2)]
private readonly Graphics _targetGraphics;
private readonly IntPtr _targetDC;
private Graphics _bufferedGraphicsSurface;
private BufferedGraphicsContext _context;
private readonly Point _targetLoc;
private readonly Size _virtualSize;
public Graphics Graphics => _bufferedGraphicsSurface;
internal bool DisposeContext { get; set; }
internal BufferedGraphics(Graphics bufferedGraphicsSurface, BufferedGraphicsContext context, [Nullable(2)] Graphics targetGraphics, IntPtr targetDC, Point targetLoc, Size virtualSize)
{
_context = context;
_bufferedGraphicsSurface = bufferedGraphicsSurface;
_targetDC = targetDC;
_targetGraphics = targetGraphics;
_targetLoc = targetLoc;
_virtualSize = virtualSize;
}
public void Dispose()
{
if (_context != null) {
_context.ReleaseBuffer();
if (DisposeContext) {
_context.Dispose();
_context = null;
}
}
if (_bufferedGraphicsSurface != null) {
_bufferedGraphicsSurface.Dispose();
_bufferedGraphicsSurface = null;
}
}
[NullableContext(2)]
public void Render(Graphics target)
{
if (target != null) {
IntPtr hdc = target.GetHdc();
try {
RenderInternal(new HandleRef(target, hdc));
} finally {
target.ReleaseHdcInternal(hdc);
}
}
}
private void RenderInternal(HandleRef refTargetDC)
{
IntPtr hdc = Graphics.GetHdc();
try {
PInvokeCore.BitBlt((HDC)refTargetDC.Handle, _targetLoc.X, _targetLoc.Y, _virtualSize.Width, _virtualSize.Height, (HDC)hdc, 0, 0, ROP_CODE.SRCCOPY);
GC.KeepAlive(refTargetDC.Wrapper);
} finally {
Graphics.ReleaseHdcInternal(hdc);
}
}
public void Render()
{
if (_targetGraphics != null)
Render(_targetGraphics);
else
RenderInternal(new HandleRef(Graphics, _targetDC));
}
public void Render(IntPtr targetDC)
{
RenderInternal(new HandleRef(null, targetDC));
}
}
}