|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Drawing;
namespace System.Windows.Forms;
/// <summary>
/// This event is fired by owner drawn <see cref="Control"/> objects, such as <see cref="ListBox"/> and
/// <see cref="ComboBox"/>. It contains all the information needed for the user to paint the given item,
/// including the item index, the <see cref="Rectangle"/> in which the drawing should be done, and the
/// <see cref="Graphics"/> object with which the drawing should be done.
/// </summary>
public class DrawItemEventArgs : EventArgs, IDisposable, IDeviceContext, IGraphicsHdcProvider, IHdcContext
{
private readonly DrawingEventArgs _event;
/// <summary>
/// The backColor to paint each menu item with.
/// </summary>
private readonly Color _backColor;
/// <summary>
/// The foreColor to paint each menu item with.
/// </summary>
private readonly Color _foreColor;
/// <summary>
/// Creates a new DrawItemEventArgs with the given parameters.
/// </summary>
public DrawItemEventArgs(Graphics graphics, Font? font, Rectangle rect, int index, DrawItemState state)
: this(graphics, font, rect, index, state, SystemColors.WindowText, SystemColors.Window)
{ }
/// <summary>
/// Creates a new DrawItemEventArgs with the given parameters, including the foreColor and backColor
/// of the control.
/// </summary>
public DrawItemEventArgs(
Graphics graphics,
Font? font,
Rectangle rect,
int index,
DrawItemState state,
Color foreColor,
Color backColor)
{
_event = new DrawingEventArgs(graphics, rect, DrawingEventFlags.GraphicsStateUnclean);
Font = font;
Index = index;
State = state;
_foreColor = foreColor;
_backColor = backColor;
}
internal DrawItemEventArgs(
HDC hdc,
Font? font,
Rectangle rect,
uint index,
ODS_FLAGS state)
: this(hdc, font, rect, index, state, SystemColors.WindowText, SystemColors.Window)
{ }
internal DrawItemEventArgs(
HDC hdc,
Font? font,
Rectangle rect,
uint index,
ODS_FLAGS state,
Color foreColor,
Color backColor)
{
_event = new DrawingEventArgs(hdc, rect, DrawingEventFlags.CheckState);
Font = font;
Index = (int)index;
State = (DrawItemState)state;
_foreColor = foreColor;
_backColor = backColor;
}
/// <summary>
/// Gets the <see cref="Drawing.Graphics"/> object used to paint.
/// </summary>
public Graphics Graphics => _event.Graphics;
/// <summary>
/// A suggested font, usually the parent control's Font property.
/// </summary>
public Font? Font { get; }
/// <summary>
/// The rectangle outlining the area in which the painting should be done.
/// </summary>
public Rectangle Bounds => _event.ClipRectangle;
/// <summary>
/// The index of the item that should be painted.
/// </summary>
public int Index { get; }
/// <summary>
/// Miscellaneous state information, such as whether the item is
/// "selected", "focused", or some other such information. ComboBoxes
/// have one special piece of information which indicates if the item
/// being painted is the editable portion of the ComboBox.
/// </summary>
public DrawItemState State { get; }
/// <summary>
/// A suggested color drawing: either SystemColors.WindowText or SystemColors.HighlightText,
/// depending on whether this item is selected.
/// </summary>
public Color ForeColor
=> (State & DrawItemState.Selected) == DrawItemState.Selected ? SystemColors.HighlightText : _foreColor;
public Color BackColor
=> (State & DrawItemState.Selected) == DrawItemState.Selected ? SystemColors.Highlight : _backColor;
/// <summary>
/// Fills the <see cref="Bounds"/> with the <see cref="BackColor"/>.
/// </summary>
public virtual void DrawBackground()
{
using var backBrush = BackColor.GetCachedSolidBrushScope();
GraphicsInternal.FillRectangle(backBrush, Bounds);
}
/// <summary>
/// Draws a handy focus rect in the given rectangle.
/// </summary>
public virtual void DrawFocusRectangle()
{
if ((State & DrawItemState.Focus) == DrawItemState.Focus
&& (State & DrawItemState.NoFocusRect) != DrawItemState.NoFocusRect)
{
ControlPaint.DrawFocusRectangle(GraphicsInternal, Bounds, ForeColor, BackColor);
}
}
public void Dispose() => Dispose(disposing: true);
protected virtual void Dispose(bool disposing)
{
// We need this because of IDeviceContext, but we historically didn't take ownership of the Graphics
// object, so there is nothing to do here unless we specifically created the Graphics object.
_event.Dispose(true);
}
/// <summary>
/// For internal use to improve performance. DO NOT use this method if you modify the <see cref="Graphics"/>
/// <see cref="Graphics.Clip"/> or <see cref="Graphics.Transform"/>.
/// </summary>
internal Graphics GraphicsInternal => _event.GetOrCreateGraphicsInternal();
/// <summary>
/// Returns the <see cref="HDC"/> the event was created off of, if any.
/// </summary>
internal HDC HDC => _event.HDC;
IntPtr IDeviceContext.GetHdc() => Graphics?.GetHdc() ?? IntPtr.Zero;
HDC IHdcContext.GetHdc() => (HDC)((IDeviceContext)this).GetHdc();
void IDeviceContext.ReleaseHdc() => Graphics?.ReleaseHdc();
void IHdcContext.ReleaseHdc() => ((IDeviceContext)this).ReleaseHdc();
IGraphics? IGraphicsHdcProvider.GetGraphics(bool createIfNeeded) => _event.GetGraphics(createIfNeeded);
HDC IGraphicsHdcProvider.GetHdc() => _event.GetHDC();
bool IGraphicsHdcProvider.IsGraphicsStateClean => _event.IsStateClean;
}
|