Image ComboBox 控件
这是一个扩展的、属主绘制的 ComboBox,增加了在下拉列表框和编辑(文本)框中显示图像的支持。
引言
ImageComboBox
是标准 Windows ComboBox
控件的扩展,增加了与项目文本一起显示图标或图像的支持。如果您查看 Windows 界面,可以看到 Windows 资源管理器、Internet Explorer、文件打开/保存/打印对话框,它们都使用可以显示图标和不同级别缩进的 combobox。
标准的 combobox 在 Normal DrawMode
中不支持显示图形图像。但当它被设置为 OwnerDrawn
时,它可以显示图标或图像。但仍然缺少一些东西。图像可以在列表部分绘制,但当您选择一个项目时,它的图像不会显示在文本框中,除非下拉样式设置为 DropDownList
。当下拉样式为 DropDownList
时,combobox 不支持编辑。可编辑模式为 Simple
和 DropDown
。所以我想让图像在所有三种 DropDownStyle
的文本框中绘制。这个 ImageComboBox
能够在列表部分和文本部分绘制带有相应图像的项目,支持所有三种 DropDownStyle
。
除此之外,这个 ImageComboBox
还支持为单个项目进行多级缩进。缩进单个项目通过分组项目和显示层级关系来增强视觉表示。当 DrawMode
设置为 OwnerDrawVariable
时,单个项目可以拥有自己的字体和大小。因此,combobox 中的一个项目有几个属性,所有这些属性都需要在设计时或运行时动态地进行操作。因此,项目不再是简单的字符串,而是独立的 ImageComboBoxItem
对象。所以 Items
是 ImageComboBoxItem
对象的集合。
ImageComboBoxItem
ImageComboBoxItem
具有以下属性
Image
与 combobox 项目一起显示的图像。
Image
属性公开一个下拉窗口,显示来自ImageList
的图像。字体
当
DrawMode
设置为OwnerDrawVariable
时,用于 combobox 项目文本的字体。Font
属性公开一个字体编辑器来选择所需的字体。IndentLevel
项目所需的缩进级别。
ImageComboBox
支持多达四个级别的缩进,即 0-5。文本
combobox 项目的文本。
ImageComboBox
还需要两个新属性,一个 ImageList
来保存用户可以从中选择与项目关联的图像的图标/图像,以及一个 Indent
属性让用户指定缩进量。Items
属性已更改,以便项目类型为 ImageComboBoxItemCollection
。向用户提供了一个集合编辑器,以便可以在设计时添加/删除/修改单个项目的属性。
ImageComboBox
以下属性是新添加到 ImageComboBox
中的
ImageList
保存与项目一起绘制的图像集合。
Items
(已更改的属性)ImageComboBox
的项目。项目类型为ImageComboBoxItemCollection
。Items
属性公开一个新的集合编辑器来添加/删除/编辑 combobox 项目。Indent
所需的缩进量(以像素为单位)。
如何在 ComboBox 的编辑部分绘制图像?
在 combobox 下拉部分显示图像相对直接,可以通过将 combobox 设置为属主绘制并为每个项目绘制图像来实现。另一方面,当 DropDownStyle
设置为 DropDown
或 Simple
时,在 combobox 的编辑部分显示图像是一项困难的任务。它需要获取编辑框的句柄,绘制图像,并为编辑框设置边距,以便显示的文本能够正确缩进。
老旧的 Windows API 调用可以解决这个问题。
- 获取编辑框的句柄。
ComboBox
是TextBox
和ListBox
的组合。GetComboBoxInfo(IntPtr hwndCombo, ref ComboBoxInfo info)
方法检索TextBox
和ListBox
的句柄和坐标。[DllImport("user32")] private static extern bool GetComboBoxInfo(IntPtr hwndCombo, ref ComboBoxInfo info); [StructLayout(LayoutKind.Sequential)] private struct ComboBoxInfo { public int cbSize; public RECT rcItem; public RECT rcButton; public IntPtr stateButton; public IntPtr hwndCombo; public IntPtr hwndEdit; public IntPtr hwndList; }
- 为
TextBox
设置边距。[DllImport("user32", CharSet=CharSet.Auto)] private extern static int SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam); private const int EC_LEFTMARGIN = 0x1; private const int EC_RIGHTMARGIN = 0x2; private const int EM_SETMARGINS = 0xD3;
使用
SendMessage
方法设置边距。combobox 支持从左到右或从右到左显示项目。根据此设置,需要设置边距。RightMargin
需要在高字中,所以乘以 65536。SendMessage(ComboBox.Handle, EM_SETMARGINS, EC_RIGHTMARGIN, Margin * 65536); SendMessage(ComboBox.Handle, EM_SETMARGINS, EC_LEFTMARGIN, Margin);
- 将图像绘制到文本框上。
要实现这一点,需要一个派生自
NativeWindow
的类。我们将TextBox
的句柄分配给这个类,以便我们可以访问发送到TextBox
的消息流。然后重写WndProc
方法并手动重绘TextBox
。
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_PAINT:
base.WndProc(ref m);
DrawImage();
break;
case WM_LBUTTONDOWN:
base.WndProc(ref m);
DrawImage();
break;
case WM_KEYDOWN:
base.WndProc(ref m);
DrawImage();
break;
case WM_KEYUP:
base.WndProc(ref m);
DrawImage();
break;
case WM_CHAR:
base.WndProc(ref m);
DrawImage();
break;
case WM_GETTEXTLENGTH:
base.WndProc(ref m);
DrawImage();
break;
case WM_GETTEXT:
base.WndProc(ref m);
DrawImage();
break;
default:
base.WndProc(ref m);
break;
}
}
public void DrawImage()
{
if((CurrentIcon!=null))
{
// Gets a GDI drawing surface from the textbox.
gfx = Graphics.FromHwnd (this.Handle);
bool rightToLeft = false;
if(Owner.RightToLeft == RightToLeft.Inherit)
{
if(Owner.Parent.RightToLeft == RightToLeft.Yes)
rightToLeft = true;
}
if(Owner.RightToLeft == RightToLeft.Yes || rightToLeft)
{
gfx.DrawImage(CurrentIcon,
gfx.VisibleClipBounds.Width - CurrentIcon.Width,0);
}
else if(Owner.RightToLeft == RightToLeft.No || rightToLeft)
gfx.DrawImage(CurrentIcon,0,0);
gfx.Flush();
gfx.Dispose();
}
}
使用 ImageComboBox
将 ImageComoBox.dll 从 bin\Release 目录复制到您的项目目录。打开解决方案资源管理器,右键单击项目名称,然后选择“添加引用”。单击“浏览”按钮,找到 ImageComoBox.dll 并选择它。要将控件显示在工具箱中,请右键单击工具箱,然后单击“添加/删除项”。在“自定义工具箱”窗口中,选择 ImageComoBox.dll。