Here's what I put together over the last few hours of trial and error
and a bunch of searching. I originally was using DrawThemeBackground
and so forth but eventually dumped it and used the easier
VisualStyleRender's(which are just wrappers, I know, but at least they
are included). Its got a lot of specific stuff to the app I'm using
but should at least give someone a lot of cut-n-paste if they find
this topic in the future.
public class ColoredComboBox : ComboBox
{
#region Private Members
private bool IsVista;
private ComboBoxState cb_State = ComboBoxState.Normal;
#endregion
#region Public Members
private Image ListaImg1 = null;
public Image ImageData1
{
set
{
ListaImg1 = value;
if (value != null)
{
if (this.DrawMode !=
System.Windows.Forms.DrawMode.OwnerDrawFixed)
{
this.DrawMode =
System.Windows.Forms.DrawMode.OwnerDrawFixed;
if (this.DropDownStyle !=
ComboBoxStyle.DropDownList)
this.DropDownStyle =
ComboBoxStyle.DropDownList;
}
}
}
get { return (ListaImg1); }
}
private Image ListaImg2 = null;
public Image ImageData2
{
set
{
ListaImg2 = value;
if (value != null)
{
if (this.DrawMode !=
System.Windows.Forms.DrawMode.OwnerDrawFixed)
{
this.DrawMode =
System.Windows.Forms.DrawMode.OwnerDrawFixed;
if (this.DropDownStyle !=
ComboBoxStyle.DropDownList)
this.DropDownStyle =
ComboBoxStyle.DropDownList;
}
}
}
get { return (ListaImg2); }
}
#endregion
#region Constructor
public ColoredComboBox()
{
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.UserPaint, true);
IsVista = ((Environment.OSVersion.Version >= new
Version("6.0.0")) && (Environment.OSVersion.Platform ==
PlatformID.Win32NT));
this.DropDownStyle = ComboBoxStyle.DropDownList;
this.FlatStyle = FlatStyle.System;
this.DrawMode =
System.Windows.Forms.DrawMode.OwnerDrawFixed;
this.DrawItem += new
DrawItemEventHandler(ColoredComboBox_DrawItem);
}
#endregion
#region DrawIcon
private Rectangle DrawIcon(Graphics g,Rectangle r, object
iconData1, object iconData2)
{
Rectangle newBounds = r;
if (iconData2 != null && iconData1 != null)
{
int x = r.X;
int w = this.Height - 4;
newBounds.X += w;
newBounds.Width -= w;
if (iconData2.ToString() == "True" && ImageData2 !=
null) // draw icon
{
w -= 4;
g.DrawImage(ImageData2, r.X + 1, r.Y + 1, w, w);
}
else if (iconData1.ToString() == "True" && ImageData1 !
= null) // draw icon
{
w -= 4;
g.DrawImage(ImageData1, r.X + 1, r.Y + 1, w, w);
}
}
return (newBounds);
}
#endregion
#region DrawItem
protected void ColoredComboBox_DrawItem(object sender,
DrawItemEventArgs e)
{
e.DrawBackground();
DrawItemText(e.Graphics, e.Bounds, e.Index);
e.DrawFocusRectangle();
}
private void DrawItemText(Graphics g,Rectangle r,int Index)
{
if (Index == -1 || Items.Count == 0)
return;
Color c = ForeColor;
Descriptor d = new Descriptor(Items[Index].ToString(),
Items[Index].ToString(), null, null, null);
try
{
d = (Descriptor)Items[Index];
if (d.Data3 != null)
c = (Color)d.Data3;
}
catch { }
SolidBrush b = new SolidBrush(c);
g.DrawString(d.Name, this.Font, b, DrawIcon(g,r, d.Data1,
d.Data2));
b.Dispose();
}
private void DrawArrow(Graphics g, Rectangle rect)
{
Point p1 = new Point(rect.X + 3, rect.Y + rect.Height / 2
- 2);
Point p2 = new Point(rect.X + rect.Width - 3, rect.Y +
rect.Height / 2 - 2);
Point p3 = new Point(rect.X + rect.Width / 2, rect.Y +
rect.Height / 2 + 2);
g.FillPolygon(new
SolidBrush(System.Drawing.SystemColors.ControlText), new Point[]{p1,
p2, p3});
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (Enabled == false)
cb_State=ComboBoxState.Disabled;
Rectangle r = e.ClipRectangle;
if (IsVista)
{
PushButtonState pb_State = PushButtonState.Normal;
if (cb_State == ComboBoxState.Disabled)
pb_State = PushButtonState.Disabled;
else if (cb_State == ComboBoxState.Hot)
pb_State = PushButtonState.Hot;
else if (cb_State == ComboBoxState.Pressed)
pb_State = PushButtonState.Pressed;
ButtonRenderer.DrawButton(e.Graphics, r,pb_State);
r = new Rectangle(r.Right -
System.Windows.Forms.SystemInformation.VerticalScrollBarWidth+2,
e.ClipRectangle.Top,
System.Windows.Forms.SystemInformation.VerticalScrollBarWidth-4,
e.ClipRectangle.Height);
DrawArrow(e.Graphics, r);
}
else
{
ComboBoxRenderer.DrawTextBox(e.Graphics, r, cb_State);
r = e.ClipRectangle;
r = new Rectangle(r.Right -
System.Windows.Forms.SystemInformation.VerticalScrollBarWidth,
e.ClipRectangle.Top,
System.Windows.Forms.SystemInformation.VerticalScrollBarWidth,
e.ClipRectangle.Height);
ComboBoxRenderer.DrawDropDownButton(e.Graphics, r,
cb_State);
}
r = e.ClipRectangle;
r.Inflate(0, -2);
r.Offset(0, 1);
DrawItemText(e.Graphics,r,SelectedIndex);
}
#endregion
#region Mouse Movement
// Draw the smaller pressed button image.
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
cb_State = ComboBoxState.Pressed;
Invalidate();
}
// Draw the button in the hot state.
protected override void OnMouseEnter(EventArgs e)
{
base.OnMouseEnter(e);
cb_State = ComboBoxState.Hot;
Invalidate();
}
// Draw the button in the unpressed state.
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
cb_State = ComboBoxState.Normal;
Invalidate();
}
// Draw the button hot if the mouse is released on the
button.
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
OnMouseEnter(e);
}
// Detect when the cursor leaves the button area while
// it is pressed.
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
// Detect when the left mouse button is down and
// the cursor has left the pressed button area.
if ((e.Button & MouseButtons.Left) == MouseButtons.Left &&
!ClientRectangle.Contains(e.Location) &&
cb_State == ComboBoxState.Pressed)
{
OnMouseLeave(e);
}
}
#endregion
}