C# Winform 自定义Combobox的颜色、样式

比较复杂,需要绘制边框,主体,下拉项目,文字,下拉按钮。

根据MSDN:那些由 Windows 完成其所有绘图的控件(例如 Textbox)从不调用它们的 OnPaint 方法,因此不能重写OnPaint。请参见您要修改的特定控件的文档,
查看 OnPaint 方法是否可用。如果某个控件未将 OnPaint 作为成员方法列出, 则您无法通过重写此方法改变其外观。
MSDN:要了解可用的 Message.Msg、Message.LParam 和 Message.WParam 值,
请参考位于 MSDN Library 中的 Platform SDK 文档参考。可在 Platform SDK(“Core SDK”一节)
下载中包含的 windows.h 头文件中找到实际常数值,该文件也可在 MSDN 上找到。

使用下面的代码,DropDownStyle 设置为DropDownList,FlatStyle设置为Flat或Popup,DrawMode设置为OwnerDrawVariable,可以得到一个蓝色边框,淡蓝色的Combobox。 可参考.NET源码(https://referencesource.microsoft.com/#system.windows.forms/winforms/Managed/System/WinForms/ComboBox.cs)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
public class CustomComboBox : ComboBox
{
/// <summary>
/// 获得当前进程,以便重绘控件
/// </summary>
/// <param name="hWnd"></param>
/// <returns></returns>
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern IntPtr GetWindowDC(IntPtr hWnd);
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);

public CustomComboBox()
: base()
{
SetStyle(
ControlStyles.UserPaint //控件自行绘制,而不使用操作系统的绘制
ControlStyles.AllPaintingInWmPaint //忽略擦出的消息,减少闪烁。
ControlStyles.OptimizedDoubleBuffer //在缓冲区上绘制,不直接绘制到屏幕上,减少闪烁。
ControlStyles.ResizeRedraw //控件大小发生变化时,重绘。
ControlStyles.SupportsTransparentBackColor, true);
}
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == 0xf m.Msg == 0x133)
{
IntPtr hDC = GetWindowDC(m.HWnd);
if (hDC.ToInt32() == 0)
{
return;
}
Pen pen = new Pen(Color.FromArgb(0,163,235), 1);
Graphics g = Graphics.FromHdc(hDC);
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
g.DrawRectangle(pen, 0, 0, this.Width - 1, this.Height - 1);
pen.Dispose();

int dropDownButtonWidth = 30;
var outerBorder = new Rectangle(ClientRectangle.Location, new Size(ClientRectangle.Width - 1, ClientRectangle.Height - 1));
var innerBorder = new Rectangle(outerBorder.X + 1, outerBorder.Y + 1, outerBorder.Width - dropDownButtonWidth - 2, outerBorder.Height - 2);
var innerInnerBorder = new Rectangle(innerBorder.X + 1, innerBorder.Y + 1, innerBorder.Width - 2, innerBorder.Height - 2);
var dropDownRect = new Rectangle(innerBorder.Right + 1, innerBorder.Y, dropDownButtonWidth, innerBorder.Height + 1);


g.FillRectangle(new SolidBrush(Color.FromArgb(241,251,255)), outerBorder);
Brush brush = new SolidBrush(Color.FromArgb(0, 163, 235));


Point middle = new Point(dropDownRect.Left + dropDownRect.Width / 2, dropDownRect.Top + dropDownRect.Height / 2);

middle.X += (dropDownRect.Width % 2);

int Offset2Pixels = 2;
g.FillPolygon(brush, new Point[] {
new Point(middle.X - Offset2Pixels, middle.Y - 1),
new Point(middle.X + Offset2Pixels + 1, middle.Y - 1),
new Point(middle.X, middle.Y + Offset2Pixels)
});
if (!(SelectedIndex == -1))
{
g.DrawString(Items[SelectedIndex].ToString(), new Font(Font.FontFamily, size, FontStyle.Regular), Brushes.Black, innerInnerBorder);

}


m.Result = IntPtr.Zero;
//释放
ReleaseDC(m.HWnd, hDC);

}
}
private float size = 9;
private Color animalColor = Color.FromArgb(0, 163, 235);
private Font myFont;

protected override void OnDrawItem(DrawItemEventArgs e)
{
//base.OnDrawItem(e);
// Draw the background of the item.
e.DrawBackground();

// Create a square filled with the animals color. Vary the size
// of the rectangle based on the length of the animals name.
Rectangle rectangle = new Rectangle(2, e.Bounds.Top + 2,
e.Bounds.Width, e.Bounds.Height - 4);

//Console.WriteLine("e.State:{0}", e.State);
if ((e.State & DrawItemState.Selected)!=0 (e.State & DrawItemState.ComboBoxEdit) != 0)
{
e.Graphics.FillRectangle(new SolidBrush(animalColor), rectangle);
}

// Draw each string in the array, using a different size, color,
// and font for each item.
myFont = new Font(Font.FontFamily, size, FontStyle.Regular);

if (e.Index == -1)
return;
if ((e.State & DrawItemState.Selected) != 0 (e.State & DrawItemState.ComboBoxEdit) != 0)
{
e.Graphics.DrawString(Items[e.Index].ToString(), myFont, Brushes.White, new RectangleF(e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height));

}
else
{
e.Graphics.DrawString(Items[e.Index].ToString(), myFont, Brushes.Black, new RectangleF(e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height));
}

}
protected override void OnSelectedIndexChanged(EventArgs e)
{
base.OnSelectedIndexChanged(e);
//base.Invalidate();
}
}