Tag:开源控件 , 源码下载 , 控件开发 , 控件美化 , 窗体换肤 , Skin , QQ表情 , Windows API , GDI+编程 , SQLite , Socket , 控件透明 , 下拉控件 , HTML 解析器 , 图片水印 , ScrollBar(滚动条) , Google Sitemap , 数据库 , SQL , WinForm , P/Invoke , WinForm控件美化扩展 , ImageComboBox控件

 
您的位置: >> 首页 >> C# 视角 >> C# WinForm控件美化扩展系列之ImageComboBox

C# WinForm控件美化扩展系列之ImageComboBox

2009-11-29  来自:CS 程序员之窗  字体大小:【  
  • 摘要:本文介绍怎样扩展ComboBox控件,实现列表项可以缩进和显示图标,可以实现项Windows文件浏览器那个ComboBox一样的功能,特点是在DropDown列表样式下在ComboBox控件上也能显示图标。

前面介绍了两篇关于ComboBox扩展和美化的文章:C# WinForm控件美化扩展系列之ComboBox组合框控件C# WinForm控件美化扩展系列之给ComboBox加水印今天将在前两篇的基础上实现一个ImageComboBox控件,ImageComboBox控件拥有以下功能:

(1)  美化下拉按钮和边框,前面的文章已经实现。

(2)  ComboBox没有控件选择项和没有焦点时显示提示用户操作信息,前面的也文章已经实现。

(3)  在下拉列表框的项中显示图标,项可以缩进。

(4)  ComboBox控件中也显示图标。

 

来看看最终需要实现的效果:

 

图1 ImageComboBox DropDownList效果
 


 

图2 ImageComboBox DropDown效果
 



这篇文章中我们重点需要实现的是(3)(4)两项功能,下面我们来介绍具体实现的方法。

 

第一步,实现ImageComboBoxItem类。

要实现显示图标,当然要给每个项添加与图标相关的信息了,ImageComboBoxItem类应该包括以下内容:文本(Text)、缩进的级别(Level)、图标的索引(ImageIndexImageKey),用户数据(Tag)ImageComboBoxItem类实现了ISerializable接口,实现自定义序列化。ImageComboBoxItem类的类视图如下:

 

图3 ImageComboxItem类视图


 

ImageComboBoxItem类的代码如下: 

[Serializable]
[DefaultProperty(
"Text")]
[TypeConverter(
typeof(ExpandableObjectConverter))]
public class ImageComboBoxItem :
IDisposable, ISerializable
{
Fields

Constructors

Properties

Methods

ISerializable 成员

IDisposable 成员

ImageComboBoxItemImageIndexer Class
}

第二步,实现ImageComboBoxItemCollection类。

ImageComboBoxItemCollection类实现跟ComboBox.ObjectCollection类一样的功能,用来代替ComboBox控件中ComboBox.ObjectCollection类,定义一个新的Items来存储ImageComboBoxItem对象,来实现ImageComboBox控件设计时可以支持ImageComboBoxItem对象的设计。

 

第三步,给ImageComboBox控件添加一些属性。

ImageComboBox控件主要需要添加几个属性:图标集合(ImageList)、没有选择项时ComboBox中显示的默认图标(DefaultImage)、缩进值(Indent)、提示信息(EmptyTextTip)、提示信息的文本颜色(EmptyTextTipColor)。还需要覆盖一些属性,这里不一一列出了,看下面的ImageComboBox控件的类视图:

 

图4 ImageComboBox类视图

第四步,实现EditorNativeWimdow类。

EditorNativeWimdow类的主要功能是实现当ImageComboBox控件的列表模式设为非DropDownList的时候,即DropDownStyle不是ComboBoxStyle.DropDownList的时候,实现在Editor中绘制图标。EditorNativeWimdow类的代码如下: 

private class EditorNativeWimdow
: NativeWindow, IDisposable
{
Fields

Constructors

Private Methods

IDisposable 成员
}

第五步,重写OnCreateControlOnHandleDestroyed方法。

重写这两个方法主要是为了ImageComboBox控件的DropDownStyle为不同的值时,控制是否需要在Editor中绘制图标,这两个方法的代码如下: 

protected override void OnCreateControl()
{
base.OnCreateControl();
if (DropDownStyle != ComboBoxStyle.DropDownList &&
!DesignMode)
{
if (_nativeWimdow == null)
{
_nativeWimdow
= new EditorNativeWimdow(this);
}

}

}


protected override void OnHandleDestroyed(EventArgs e)
{
if (_nativeWimdow != null)
{
_nativeWimdow.Dispose();
_nativeWimdow
= null;
}

base.OnHandleDestroyed(e);
}

第六步,重写OnDropDown方法。

重写这个方法是为了实现调节下拉列表框显示的大小,因为画了图标,以免项显示不完全。OnDropDown方法代码如下: 

protected override void OnDropDown(
EventArgs e)
{
base.OnDropDown(e);

int ddWidth = 0;
int textWidth = 0;
int itemWidth = 0;
int scrollBarWidth =
Items.Count
> MaxDropDownItems ?
SystemInformation.VerticalScrollBarWidth :
0;
Graphics g
= CreateGraphics();

foreach (ImageComboBoxItem item in Items)
{
textWidth
= g.MeasureString(
item.Text, Font).ToSize().Width;
itemWidth
=
textWidth
+
ItemHeight
+ 8 +
_indent
* item.Level +
scrollBarWidth;

if (itemWidth > ddWidth)
ddWidth
= itemWidth;
}


DropDownWidth
= (ddWidth > Width) ?
ddWidth : Width;
g.Dispose();
}
 

第七步,重绘列表项,让其缩进和显示图标。

重绘列表项,需要把ImageComboBox控件的DrawMode设为DrawMode.OwnerDrawFixed,然后通过重写OnDrawItem方法实现,具体代码如下: 

protected override void OnDrawItem(DrawItemEventArgs e)
{
if (e.Index != -1)
{
ImageComboBoxItem item
= Items[e.Index];
Graphics g
= e.Graphics;
Rectangle bounds
= e.Bounds;

int indentOffset = Indent * item.Level;

if ((e.State & DrawItemState.ComboBoxEdit) ==
DrawItemState.ComboBoxEdit)
{
indentOffset
= 0;
}


int imageWidth = bounds.Height;
Rectangle imageRect;
Rectangle textRect;
TextFormatFlags format
=
TextFormatFlags.VerticalCenter
|
TextFormatFlags.SingleLine
|
TextFormatFlags.WordBreak;

imageRect
= new Rectangle(
bounds.Left
+ indentOffset + 2,
bounds.Top,
imageWidth,
imageWidth);
textRect
= new Rectangle(
imageRect.Right
+ 3,
bounds.Y,
bounds.Width
- imageRect.Width - indentOffset - 5,
bounds.Height);

Rectangle backRect
= new Rectangle(
textRect.X,
textRect.Y
+ 1,
textRect.Width,
textRect.Height
- 2);

backRect.Width
= TextRenderer.MeasureText(
item.Text, e.Font, textRect.Size, format).Width;

if (base.RightToLeft == RightToLeft.Yes)
{
imageRect.X
= bounds.Right - imageRect.Right;
textRect.X
= bounds.Right - textRect.Right;
backRect.X
= textRect.Right - backRect.Width;
}


bool selected = ((e.State & DrawItemState.Selected) ==
DrawItemState.Selected);

Color backColor
= selected ?
SystemColors.Highlight :
base.BackColor;

using (Brush backBrush = new SolidBrush(backColor))
{
g.FillRectangle(backBrush, backRect);
}


if (selected)
{
ControlPaint.DrawFocusRectangle(
g,
backRect);
}


Image image
= item.Image;
if (image != null)
{
using (InterpolationModeGraphics graphics =
new InterpolationModeGraphics(
g, InterpolationMode.HighQualityBicubic))
{
if (selected)
{
IntPtr hIcon
= NativeMethods.ImageList_GetIcon(
ImageList.Handle,
item.ImageIndexer.ActualIndex,
(
int)NativeMethods.ImageListDrawFlags.ILD_SELECTED);
g.DrawIcon(Icon.FromHandle(hIcon), imageRect);
NativeMethods.DestroyIcon(hIcon);
}

else
{
g.DrawImage(
image,
imageRect,
0,
0,
image.Width,
image.Height,
GraphicsUnit.Pixel);
}

}

}


TextRenderer.DrawText(
g,
item.Text,
e.Font,
textRect,
base.ForeColor,
format);
}

}

 

到此为止,ImageComboBox控件需要实现的功能就完成了。

 

声明:

本文版权归作者和CS 程序员之窗所有,欢迎转载,转载必须保留以下版权信息,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

作者:Starts_2000

出处:CS 程序员之窗 http://www.csharpwin.com

你可以免费使用或修改提供的源代码,但请保留源代码中的版权信息,详情请查看:

CS程序员之窗开源协议 http://www.csharpwin.com/csol.html