自定义控件的实现
-------- 带图标和自定义颜色的 ListBox
在一个点对点文件传输的项目中,我需要显示文件传输的实时信息:传输的文件列表和当前传输的文件,当时我想到了用 ListBox, 但是但我用了 ListBox 后,我发现它不能改变控件中文本想的颜色,于是我就想扩展一下 ListBox 控件 ------ListBoxEx 。
我的目标是给空间加上图标,还要能时时改变控件文本颜色。于是从 ListBox 派生类
public class ListBoxEx : ListBox {…}
为了操作方便我为 ListBoxEx 的每一项设计专门的类 ListBoxExItem
public class ListBoxExItem {…}
为了保持我这个控件与 WinForm 的标准控件的操作借口一致,我又重新设计了两个集合类
public class ListBoxExItemCollection : IList, ICollection, IEnumerator {}// 这个类相对于标准 ListBox 中的 ObjectCollection ,这个类作为 ListBoxEx 中的 Items 属性的类型
public class SelectedListBoxExItemCollection : : IList, ICollection, IEnumerator{}// 这个类相对于标准 ListBox 中的 SelectedObjectCollection ,这个类作为 ListBoxEx 中的 SelectedItems 属性的类型
下面看两个集合类的实现:
ListBoxExItemCollection 的实现:为了做到对集合 (Items) 的操作能够及时反映到 ListBoxEx 的控件中所以,此类只是对 ListBox 中 Items(ObjectCollection 类型 ) 作了一层包装,就是把 ListBox 中 Items 属性的所有方法的只要是 object 类型的参数都转换成 ListBoxExItem ,比如 :
public void Remove(ListBoxExItem item)
{
this._Items.Remove(item); //_Items 为 ObjectCollection 类型
}
public void Insert(int index, ListBoxExItem item)
{
this._Items.Insert(index, item);
}
public int Add(ListBoxExItem item)
{
return this._Items.Add(item);
}
由上可知, ListBoxExItemCollection 中有一个构造函数来传递 ListBox 中的 Items 对象
private ObjectCollection _Items;
public ListBoxExItemCollection(ObjectCollection baseItems)
{
this._Items = baseItems;
}
而 SelectedListBoxExItemCollection 类的实现也用同样的方法,只不过是对 SelectedObjectCollection 包装罢了。
集合实现后,再来看 ListBoxExItem 的实现:
为了使它支持图标和多种颜色添加如下成员
private int _ImageIndex;
public int ImageIndex
{
get { return this._ImageIndex; }
set { this._ImageIndex = value;}
}
private Color _ForeColor;
public Color ForeColor
{
get{ return this._ForeColor;}
set
{
this._ForeColor = value;
this.Parent.Invalidate();
}
}
当然还有
private string _Text;
public string Text
{
get { return this._Text; }
set { this._Text = value; }
}
为了控件能正确显示此项的文本,还必须重写 ToString() 方法
public override string ToString()
{
return this._Text;
}
再看 ListBoxEx 的实现 :
为了使控件能够自我绘制,所以 DrawMode = DrawMode.OwnerDrawFixed;
为了覆盖基类的 Items 等相关属性添加
private ListBoxExItemCollection _Items; // 在构造函数中创建
同时还需要重写属性 Items
new public ListBoxExItemCollection Items
{
get
{
return this._Items;
}
}
new public ListBoxExItem SelectedItem // 强制转换为 ListBoxExItem
{
get{ return base.SelectedItem as ListBoxExItem;}
set{ base.SelectedItem = value;}
}
new public SelectedListBoxExItemCollection SelectedItems // 重新包装 SelectedItems
{
get
{
return new SelectedListBoxExItemCollection(base.SelectedItems);
}
}
为了支持图标,添加一个图像列表 imagelist
private ImageList imageList;
public ImageList ImageList
{
get { return this.imageList; }
set
{
this.imageList = value;
this.Invalidate();// 图像列表改变后马上更新控件
}
}
而此控件的核心却在一个方法 OnDrawItem, 这个方法每当控件的项需要重绘时就被调用
protected override void OnDrawItem(System.Windows.Forms.DrawItemEventArgs pe)
{
pe.DrawBackground(); // 画背景
pe.DrawFocusRectangle(); // 画边框
Rectangle bounds = pe.Bounds;
// Check whether the index is valid
if(pe.Index >= 0 && pe.Index < base.Items.Count)
{
ListBoxExItem item = this.Items[pe.Index]; // 取得需要绘制项的引用
int iOffset = 0;
// If the image list is present and the image index is set, draw the image
if(this.imageList != null)
{
if (item.ImageIndex > -1 && item.ImageIndex < this.imageList.Images.Count)
{
this.imageList.Draw(pe.Graphics, bounds.Left, bounds.Top, bounds.Height, bounds.Height, item.ImageIndex); // 绘制图标
}
iOffset += bounds.Height;//this.imageList.ImageSize.Width;
}
// Draw item text
pe.Graphics.DrawString(item.Text, pe.Font, new SolidBrush(item.ForeColor),
bounds.Left + iOffset, bounds.Top); // 根据项的颜色绘制文本
}
base.OnDrawItem(pe);
}
}
到此为止, ListBoxEx 以完整的实现,并且支持可视化设计。
如果需要完整代码,请联系[email protected]