#region Fields
private IntPtr hdc;
#endregion
#region Instance management
/// <summary>/// Initializes a new instance of the <see cref="DeviceContext"/> class./// </summary>/// <param name="hdc">The device context handle to wrap.</param>protected DeviceContext(IntPtr hdc)
{
this.hdc = hdc;
}
/// <summary>/// Creates a <see cref="DeviceContext"/> wrapper around specified HDC./// </summary>/// <param name="hdc">The device context handler to wrap.</param>/// <returns></returns>public static DeviceContext Attach(IntPtr hdc)
{
return new DeviceContext(hdc);
}
/// <summary>/// Creates a <see cref="DeviceContext"/> from a <see cref="Graphics"/> object./// </summary>/// <param name="graphics">The <see cref="Graphics"/> object to wrap.</param>/// <returns>A new <see cref="DeviceContext"/> object.</returns>public static DeviceContext FromGraphics(Graphics graphics)
{
return new GraphicsDeviceContext(graphics);
}
/// <summary>/// Creates a <see cref="DeviceContext"/> to paint a window./// </summary>/// <param name="hwnd">The handle of the window.</param>/// <returns>A new <see cref="DeviceContext"/> object.</returns>public static DeviceContext FromHWnd(IntPtr hwnd)
{
return new WindowDeviceContext(hwnd, NativeGdi.GetWindowDC(hwnd));
}
/// <summary>/// Creates a <see cref="DeviceContext"/> to paint a window./// </summary>/// <param name="hwnd">The handle of the window.</param>/// <param name="region">The handle of a region.</param>/// <returns>A new <see cref="DeviceContext"/> object.</returns>public static DeviceContext FromHWnd(IntPtr hwnd, IntPtr region)
{
return new WindowDeviceContext(hwnd, NativeGdi.GetDCEx(hwnd, region, NativeGdi.DCX_WINDOW | NativeGdi.DCX_INTERSECTRGN));
}
/// <summary>/// Creates a new <see cref="DeviceContext"/> compatible width given device context./// </summary>/// <param name="hdc">The handle of the device context.</param>/// <returns>A new <see cref="DeviceContext"/> object.</returns>public static DeviceContext CreateCompatible(IntPtr hdc)
{
IntPtr compatibleHdc = NativeGdi.CreateCompatibleDC(hdc);
return new CompatibleDeviceContext(compatibleHdc);
}
/// <summary>/// Creates a new <see cref="DeviceContext"/> compatible width given device context./// </summary>/// <param name="dc">The original <see cref="DeviceContext"/> object.</param>/// <returns>A new <see cref="DeviceContext"/> object.</returns>public static DeviceContext CreateCompatible(DeviceContext dc)
{
IntPtr compatibleHdc = NativeGdi.CreateCompatibleDC(dc.Handle);
return new CompatibleDeviceContext(compatibleHdc);
}
/// <summary>/// Creates a screen device context./// </summary>/// <returns>A new <see cref="DeviceContext"/> object.</returns>public static DeviceContext FromScreen()
{
return FromHWnd(IntPtr.Zero);
}
/// <summary>/// Creates a <see cref="DeviceContext"/> compatible with screen./// </summary>/// <returns>A new <see cref="DeviceContext"/> object.</returns>public static DeviceContext CreateScreenCompatible()
{
IntPtr screen = NativeGdi.GetDC(IntPtr.Zero);
try{
return new CompatibleDeviceContext( NativeGdi.CreateCompatibleDC(screen) );
}
finally{
NativeGdi.ReleaseDC(IntPtr.Zero, screen);
}
}
#endregion
#region Dispose and finalization
/// <summary>/// Releases internal resources./// </summary>~DeviceContext()
{
Dispose(false);
}
/// <summary>/// Releases internal resources./// </summary>public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(
bool disposing)
{
hdc = IntPtr.Zero;
}
#endregion
#region Properties
/// <summary>/// Gets device context handle./// </summary>public IntPtr Handle
{
get { return hdc; }
}
#endregion
#region Methods
/// <summary>/// Creates a new clipping region that consists/// of the existing clipping region minus the specified rectangle/// </summary>/// <param name="rect">The rectangle used to modify the clipping region.</param>public void ExcludeClip(Rectangle rect)
{
NativeGdi.ExcludeClipRect(hdc, rect.Left, rect.Top, rect.Right, rect.Bottom);
GC.KeepAlive(this);
}
/// <summary>/// Creates a new clipping region from the intersection/// of the current clipping region and the specified rectangle./// </summary>/// <param name="rect">The rectangle used to modify the clipping region.</param>public void IntersectClip(Rectangle rect)
{
NativeGdi.IntersectClipRect(hdc, rect.Left, rect.Top, rect.Right, rect.Bottom);
GC.KeepAlive(this);
}
/// <summary>/// fills a rectangle by using the specified brush./// This function includes the left and top borders,/// but excludes the right and bottom borders of the rectangle./// </summary>/// <param name="brush">The brush used to fill the rectangle.</param>/// <param name="rect">The rectangle to be filled. </param>public void FillRectangle(GdiBrush brush, Rectangle rect)
{
NativeGdi.FillRect(hdc, rect, brush.Handle);
GC.KeepAlive(this);
}
/// <summary>/// Draws an image in the device context./// </summary>/// <param name="image">The image to draw.</param>/// <param name="point">The location where the image should be drawn.</param>public void DrawImageUnscaled(GdiBitmap image, Point point)
{
DrawImageUnscaled(image, point.X, point.Y, image.Width, image.Height);
GC.KeepAlive(this);
}
/// <summary>/// Draws an image in the device context./// </summary>/// <param name="image">The image to draw.</param>/// <param name="x">The x coordinate of the location/// where the image should be drawn.</param>/// <param name="y">The y coordinate of the location/// where the image should be drawn.</param>public void DrawImageUnscaled(GdiBitmap image,
int x,
int y)
{
DrawImageUnscaled(image, x, y, image.Width, image.Height);
GC.KeepAlive(this);
}
/// <summary>/// Draws an image in the device context./// </summary>/// <param name="image">The image to draw.</param>/// <param name="rectangle">The rectangle where/// the image should be drawn.</param>public void DrawImageUnscaled(GdiBitmap image, Rectangle rectangle)
{
DrawImageUnscaled(image, rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height);
GC.KeepAlive(this);
}
/// <summary>/// Draws an image in the device context./// </summary>/// <param name="image">The image to draw.</param>/// <param name="x">The x coordinate of the rectangle/// where the image should be drawn.</param>/// <param name="y">The y coordinate of the rectangle/// where the image should be drawn.</param>/// <param name="width">The width of the rectangle/// where the image should be drawn.</param>/// <param name="height">The height of the rectangle/// where the image should be drawn.</param>public void DrawImageUnscaled(GdiBitmap image,
int x,
int y,
int width,
int height)
{
using (DeviceContext sourceContext = CreateCompatibleDeviceContext())
{
using (GdiSelect select = sourceContext.SelectObject(image))
NativeGdi.BitBlt(hdc, x, y, width, height, sourceContext.Handle, 0, 0, NativeGdi.SRCCOPY);
}
}
/// <summary>/// Saves the state of the device context./// </summary>/// <returns>A <see cref="DeviceContextState"/> object containing device state.</returns>public DeviceContextState Save()
{
GC.KeepAlive(this);
return new DeviceContextState(NativeGdi.SaveDC(hdc));
}
/// <summary>/// Restores the state of the device context./// </summary>/// <param name="state">The <see cref="DeviceContextState"/>/// object containing the device state.</param>/// <remarks>The <see cref="DeviceContextState"/> is obtained/// by calling <see cref="Save"/>.</remarks>public void Restore(DeviceContextState state)
{
NativeGdi.RestoreDC(hdc, state.state);
GC.KeepAlive(this);
}
/// <summary>/// Applies a translate transformation to the device context./// </summary>/// <param name="x">The x coordinate of the offset.</param>/// <param name="y">The y coordinate of the offset.</param>public void TranslateTransform(
int x,
int y)
{
NativeGdi.OffsetWindowOrgEx(hdc, x, y, IntPtr.Zero);
GC.KeepAlive(this);
}
/// <summary>/// Applies a translate transformation to the device context./// </summary>/// <param name="point">The offset of the translation.</param>public void TranslateTransform(Point point)
{
TranslateTransform(point.X, point.Y);
}
/// <summary>/// Selects a <see cref="GdiObject"/> in the device context./// </summary>/// <param name="gdiObject">The <see cref="GdiObject"/> to select.</param>/// <returns>A <see cref="GdiSelect"/> disposable object/// used to deselect from device context.</returns>public GdiSelect SelectObject(GdiObject gdiObject)
{
GC.KeepAlive(this);
return new GdiSelect(NativeGdi.SelectObject( new HandleRef(this, hdc), new HandleRef(gdiObject, gdiObject.Handle)), hdc);
}
/// <summary>/// Creates a compatible device context./// </summary>/// <returns>The newly created device context.</returns>public DeviceContext CreateCompatibleDeviceContext()
{
return new CompatibleDeviceContext(NativeGdi.CreateCompatibleDC(hdc));
}
#endregion
#region Specialized inner classes
private class GraphicsDeviceContext : DeviceContext
{
private Graphics graphics;
internal GraphicsDeviceContext(Graphics graphics) :
base(graphics.GetHdc())
{
this.graphics = graphics;
}
protected override void Dispose(
bool disposing)
{
if (disposing)
{
if (Handle != IntPtr.Zero)
graphics.ReleaseHdc(Handle);
}
base.Dispose(disposing);
}
}
private class CompatibleDeviceContext : DeviceContext
{
internal CompatibleDeviceContext(IntPtr hdc) :
base(hdc)
{}
protected override void Dispose(
bool disposing)
{
if (Handle != IntPtr.Zero)
NativeGdi.DeleteDC(Handle);
base.Dispose(disposing);
}
}
private class WindowDeviceContext : DeviceContext
{
private IntPtr hwnd;
internal WindowDeviceContext(IntPtr hwnd, IntPtr hdc) :
base(hdc)
{
this.hwnd = hwnd;
}
protected override void Dispose(
bool disposing)
{
if (Handle != IntPtr.Zero)
NativeGdi.ReleaseDC(hwnd, Handle);
base.Dispose(disposing);
}
}
#endregion