|
|
Posted on 2008-01-22 14:43 faib 阅读(576) 评论(2) 编辑 收藏 网摘 所属分类: C# 、 控件
个人认为winform的combobox不是那么的好用,所以自己扩展了一下。
重新定义Items属性,并且支持树结构。
为每项加入了CheckBox状态。
丰富的列表项类ListItem。
效果如图: 
代码清单:
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.Design;

namespace FaibClass.Windows.Forms
  {
[Designer(typeof(ControlDesigner))]
public class ComboBox : System.Windows.Forms.ComboBox
 {
// Fields
private bool blnIsChange = false;
private int m_ImageIndex = -1;
private ImageList m_ImageList;
private ListItemCollection m_items;
private object objSource;
private Color m_ItemHoverBackColor;
private Color m_ItemHoverGradientBackColor = Color.Empty;
private Color m_ItemHoverColor;
private int m_Indent = 16;
private bool m_CheckBoxes = false;
private bool isUpdate = false;
private ComboBoxWindow wnd = null;
internal static int nextId = 0;

 Methods#region Methods
public ComboBox()
 {
m_ItemHoverBackColor = SystemColors.Highlight;
m_ItemHoverColor = SystemColors.HighlightText;
base.Sorted = false;
}

 /**//// <summary>
/// 绑定数据。
/// </summary>
public void DataBind()
 {
if ((this.DataSource != null) && (base.DisplayMember != null))
 {
switch (this.DataSource.GetType().Name)
 {
case "DataTable":
 {
DataTable dtblTmp = (DataTable)this.DataSource;
foreach (DataRow drowTmp in dtblTmp.Rows)
 {
string strText = drowTmp[base.DisplayMember].ToString();
string strValue = (base.ValueMember == null) ? null : drowTmp[base.ValueMember].ToString();
ListItem item = new ListItem(strText, strValue, this.ImageIndex);
this.m_items.Add(item);
}
break;
}
}
}
}

//锁定更新
public new void BeginUpdate()
 {
base.BeginUpdate();
isUpdate = true;
}

//解除更新
public new void EndUpdate()
 {
InsertItem(m_items);
base.EndUpdate();
isUpdate = false;
}

//绘制项
protected override void OnDrawItem(DrawItemEventArgs e)
 {
if(e.Index == -1)return;
Rectangle trect = new Rectangle(0, 0, 0, 0), crect = new Rectangle(0, 0, 0, 0);
ListItem item = getItem(e.Index);
if(item == null)return;

bool isEdit = (e.State & DrawItemState.ComboBoxEdit) == DrawItemState.ComboBoxEdit;

if(m_CheckBoxes) //复选框的区域
 {
crect = new Rectangle(m_Indent * item.level, e.Bounds.Top + ((e.Bounds.Height - 16) / 2), 16, 16);
if(isEdit)
crect.Offset(2, 0);
}
else
 {
crect.X = m_Indent * item.level + 2;
}
//if(isEdit)
DrawBackground(e, e.Bounds, item);
//else
// DrawBackground(e, new Rectangle(crect.Left - 1, e.Bounds.Top, e.Bounds.Width - crect.Left + 1, e.Bounds.Height), item);
Rectangle irect = new Rectangle(crect.Right, 0, 0, 0);
if(ImageList != null && item.ImageIndex != -1)//画图象
 {
Image sIcon = ImageList.Images[item.ImageIndex];
irect = new Rectangle(crect.Right, e.Bounds.Top + ((e.Bounds.Height - sIcon.Height) / 2), sIcon.Width, sIcon.Height);
//图象太大
if(irect.Height > e.Bounds.Height)
 {
irect = new Rectangle(crect.Right, e.Bounds.Top, e.Bounds.Height, e.Bounds.Height);
}
e.Graphics.DrawImage(sIcon, irect);
}
trect = new Rectangle(irect.Right, e.Bounds.Top, e.Bounds.Width - irect.Width, e.Bounds.Height);
if(m_CheckBoxes) //画复选框
 {
if(item.checkboxLeft == -1)
item.checkboxLeft= crect.Left;
ControlPaint.DrawCheckBox(e.Graphics, crect , item.Checked ? ButtonState.Checked | ButtonState.Flat : ButtonState.Flat);
}
DrawString(e, item, trect); //输出文本

e.Graphics.Dispose();
}

//重设项大小
protected override void OnMeasureItem(MeasureItemEventArgs e)
 {
base.OnMeasureItem(e);
if (this.ImageList != null)
 {
e.ItemHeight = this.ImageList.ImageSize.Height;
}
}

protected override void WndProc(ref Message m)
 {
if(m.Msg == 0x134)//WM_CTLCOLORLISTBOX
 {
if(m_CheckBoxes && wnd == null)
 {
wnd = new ComboBoxWindow(base.Items, Handle); //钩子
wnd.AssignHandle(m.LParam);
}
}
else if(wnd != null && m.Msg == 0x2)//WM_DESTROY
 {
wnd.ReleaseHandle();
}
else if(m.Msg == 0x400 + 0x105) //自定消息 设置checked
 {
int index = m.WParam.ToInt32();
ListItem item = FindRealListItem(getItem(index));
if(item != null)
 {
item.Checked = !item.Checked;
}
}
base.WndProc (ref m);
}

//画背景
private void DrawBackground(DrawItemEventArgs e, Rectangle rect, ListItem item)
 {
if((e.State & DrawItemState.Selected) == DrawItemState.Selected)
 {
if(m_ItemHoverGradientBackColor != Color.Empty)
 {
//渐变
Rectangle r = new Rectangle(rect.Left, rect.Top, rect.Width, rect.Height / 2);
e.Graphics.FillRectangle(new LinearGradientBrush(r, m_ItemHoverBackColor, m_ItemHoverGradientBackColor, 90f), r);
r = new Rectangle(rect.Left, rect.Top + rect.Height / 2, rect.Width, rect.Height / 2);
 if(r.Height % 2 == 0) {r.Y -= 2; r.Height += 2;}
e.Graphics.FillRectangle(new LinearGradientBrush(r, m_ItemHoverBackColor, m_ItemHoverGradientBackColor, 270f), r);
ControlPaint.DrawBorder(e.Graphics, rect, m_ItemHoverGradientBackColor, ButtonBorderStyle.Solid);
}
else
e.Graphics.FillRectangle(new SolidBrush(m_ItemHoverBackColor), rect);
}
else
 {
e.Graphics.FillRectangle(new SolidBrush(item.BackColor), rect);
}
}

//画文本
private void DrawString(DrawItemEventArgs e, ListItem item, Rectangle rect)
 {
StringFormat sf = new StringFormat();
sf.LineAlignment = StringAlignment.Center;
rect.Offset(0, 1);
SolidBrush sb = null;
if(!item.ForeColor.Equals(SystemColors.WindowText) || m_ItemHoverGradientBackColor != Color.Empty)
 {
sb = new SolidBrush(item.ForeColor);
}
else if((e.State & DrawItemState.Selected) == DrawItemState.Selected)
 {
sb = new SolidBrush(m_ItemHoverColor);
}
else
 {
sb = new SolidBrush(SystemColors.WindowText);
}

e.Graphics.DrawString(item.Text, item.Font, sb, rect, sf);
sb.Dispose();
}

//插入整个根集合
private void InsertItem(ListItemCollection items)
 {
foreach(ListItem item in items)
 {
ListItem lit = item.CloneData();
lit.Items = null;
lit.level = item.level;
if(item.Parent.GetType() == typeof(ListItem))
 {
ListItem parent = (ListItem)item.Parent;
lit.Parent = parent;
}
base.Items.Add(lit);
InsertItem(item.Items);
}
}

//插入新项
internal int InsertItem(int index, ListItem item, int method)
 {
if(isUpdate)return 0;
ListItem lit = item.CloneData();
lit.Items = null;
lit.level = item.level;
int count = 0;
if(item.Parent.GetType() == typeof(ListItem))
 {
ListItem parent = (ListItem)item.Parent;
foreach(ListItem lt1 in parent.Items)
 {
GetItemLocation(lt1.Items, lit, ref count);
}
lit.Parent = parent;
int i = 0;
for(; i < base.Items.Count; i++)
 {
if(getItem(i).id == parent.id)
![]() |