您的位置:首页 > 职场人生

C# WinForm控件美化扩展系列之ImageComboBox_C# 视角_CS程序员之窗

2011-09-07 17:46 726 查看
前面介绍了两篇关于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)、图标的索引(ImageIndex、ImageKey),用户数据(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 成员

}
第五步,重写OnCreateControl、OnHandleDestroyed方法。
重写这两个方法主要是为了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控件需要实现的功能就完成了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: