重新定义Items属性,并且支持树结构。
为每项加入了CheckBox状态。
丰富的列表项类ListItem。
效果如图:
代码清单:
[Designer(typeof(ControlDesigner))]
publicclassComboBox:System.Windows.Forms.ComboBox
{
//Fields
privateboolblnIsChange=false;
privateintm_ImageIndex=-1;
privateImageListm_ImageList;
privateListItemCollectionm_items;
privateobjectobjSource;
privateColorm_ItemHoverBackColor;
privateColorm_ItemHoverGradientBackColor=Color.Empty;
privateColorm_ItemHoverColor;
privateintm_Indent=16;
privateboolm_CheckBoxes=false;
privateboolisUpdate=false;
privateComboBoxWindowwnd=null;
internalstaticintnextId=0;
#regionMethods
publicComboBox()
{
m_ItemHoverBackColor=SystemColors.Highlight;
m_ItemHoverColor=SystemColors.HighlightText;
base.Sorted=false;
}
///<summary>
///绑定数据。
///</summary>
publicvoidDataBind()
{
if((this.DataSource!=null)&&(base.DisplayMember!=null))
{
switch(this.DataSource.GetType().Name)
{
case"DataTable":
{
DataTabledtblTmp=(DataTable)this.DataSource;
foreach(DataRowdrowTmpindtblTmp.Rows)
{
stringstrText=drowTmp[base.DisplayMember].ToString();
stringstrValue=(base.ValueMember==null)?null:drowTmp[base.ValueMember].ToString();
ListItemitem=newListItem(strText,strValue,this.ImageIndex);
this.m_items.Add(item);
}
break;
}
}
}
}
//锁定更新
publicnewvoidBeginUpdate()
{
base.BeginUpdate();
isUpdate=true;
}
//解除更新
publicnewvoidEndUpdate()
{
InsertItem(m_items);
base.EndUpdate();
isUpdate=false;
}
//绘制项
protectedoverridevoidOnDrawItem(DrawItemEventArgse)
{
if(e.Index==-1)return;
Rectangletrect=newRectangle(0,0,0,0),crect=newRectangle(0,0,0,0);
ListItemitem=getItem(e.Index);
if(item==null)return;
boolisEdit=(e.State&DrawItemState.ComboBoxEdit)==DrawItemState.ComboBoxEdit;
if(m_CheckBoxes)//复选框的区域
{
crect=newRectangle(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,newRectangle(crect.Left-1,e.Bounds.Top,e.Bounds.Width-crect.Left+1,e.Bounds.Height),item);
Rectangleirect=newRectangle(crect.Right,0,0,0);
if(ImageList!=null&&item.ImageIndex!=-1)//画图象
{
ImagesIcon=ImageList.Images[item.ImageIndex];
irect=newRectangle(crect.Right,e.Bounds.Top+((e.Bounds.Height-sIcon.Height)/2),sIcon.Width,sIcon.Height);
//图象太大
if(irect.Height>e.Bounds.Height)
{
irect=newRectangle(crect.Right,e.Bounds.Top,e.Bounds.Height,e.Bounds.Height);
}
e.Graphics.DrawImage(sIcon,irect);
}
trect=newRectangle(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();
}
//重设项大小
protectedoverridevoidOnMeasureItem(MeasureItemEventArgse)
{
base.OnMeasureItem(e);
if(this.ImageList!=null)
{
e.ItemHeight=this.ImageList.ImageSize.Height;
}
}
protectedoverridevoidWndProc(refMessagem)
{
if(m.Msg==0x134)//WM_CTLCOLORLISTBOX
{
if(m_CheckBoxes&&wnd==null)
{
wnd=newComboBoxWindow(base.Items,Handle);//钩子
wnd.AssignHandle(m.LParam);
}
}
elseif(wnd!=null&&m.Msg==0x2)//WM_DESTROY
{
wnd.ReleaseHandle();
}
elseif(m.Msg==0x400+0x105)//自定消息设置checked
{
intindex=m.WParam.ToInt32();
ListItemitem=FindRealListItem(getItem(index));
if(item!=null)
{
item.Checked=!item.Checked;
}
}
base.WndProc(refm);
}
//画背景
privatevoidDrawBackground(DrawItemEventArgse,Rectanglerect,ListItemitem)
{
if((e.State&DrawItemState.Selected)==DrawItemState.Selected)
{
if(m_ItemHoverGradientBackColor!=Color.Empty)
{
//渐变
Rectangler=newRectangle(rect.Left,rect.Top,rect.Width,rect.Height/2);
e.Graphics.FillRectangle(newLinearGradientBrush(r,m_ItemHoverBackColor,m_ItemHoverGradientBackColor,90f),r);
r=newRectangle(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(newLinearGradientBrush(r,m_ItemHoverBackColor,m_ItemHoverGradientBackColor,270f),r);
ControlPaint.DrawBorder(e.Graphics,rect,m_ItemHoverGradientBackColor,ButtonBorderStyle.Solid);
}
else
e.Graphics.FillRectangle(newSolidBrush(m_ItemHoverBackColor),rect);
}
else
{
e.Graphics.FillRectangle(newSolidBrush(item.BackColor),rect);
}
}
//画文本
privatevoidDrawString(DrawItemEventArgse,ListItemitem,Rectanglerect)
{
StringFormatsf=newStringFormat();
sf.LineAlignment=StringAlignment.Center;
rect.Offset(0,1);
SolidBrushsb=null;
if(!item.ForeColor.Equals(SystemColors.WindowText)||m_ItemHoverGradientBackColor!=Color.Empty)
{
sb=newSolidBrush(item.ForeColor);
}
elseif((e.State&DrawItemState.Selected)==DrawItemState.Selected)
{
sb=newSolidBrush(m_ItemHoverColor);
}
else
{
sb=newSolidBrush(SystemColors.WindowText);
}
e.Graphics.DrawString(item.Text,item.Font,sb,rect,sf);
sb.Dispose();
}
//插入整个根集合
privatevoidInsertItem(ListItemCollectionitems)
{
foreach(ListItemiteminitems)
{
ListItemlit=item.CloneData();
lit.Items=null;
lit.level=item.level;
if(item.Parent.GetType()==typeof(ListItem))
{
ListItemparent=(ListItem)item.Parent;
lit.Parent=parent;
}
base.Items.Add(lit);
InsertItem(item.Items);
}
}
//插入新项
internalintInsertItem(intindex,ListItemitem,intmethod)
{
if(isUpdate)return0;
ListItemlit=item.CloneData();
lit.Items=null;
lit.level=item.level;
intcount=0;
if(item.Parent.GetType()==typeof(ListItem))
{
ListItemparent=(ListItem)item.Parent;
foreach(ListItemlt1inparent.Items)
{
GetItemLocation(lt1.Items,lit,refcount);
}
lit.Parent=parent;
inti=0;
for(;i<base.Items.Count;i++)
{
if(getItem(i).id==parent.id)
{
break;
}
}
base.Items.Insert(i+1+index+count,lit);
}
else
{
foreach(ListItemlt1in((ComboBox)item.Parent).Items)
{
GetItemLocation(lt1.Items,lit,refcount);
}
base.Items.Insert(index+count,lit);
}
returnbase.Items.Count-1;
}
privatevoidGetItemLocation(ListItemCollectionitems,ListItemowner,refintcount)
{
foreach(ListItemltinitems)
{
if(owner.id!=lt.id&&CheckIsInItems(lt.id))
{
count++;
GetItemLocation(lt.Items,owner,refcount);
}
}
}
privateboolCheckIsInItems(intid)
{
foreach(objectoinbase.Items)
{
if(((ListItem)o).id==id)
{
returntrue;
}
}
returnfalse;
}
internalvoidRemoveItem(ListItemitem)
{
if(isUpdate)return;
intindex=FindItem(item.id);
if(index!=-1)
base.Items.RemoveAt(index);
}
internalvoidClearItem()
{
base.Items.Clear();
}
privateintFindItem(intid)
{
if(this.DesignMode)return-1;
for(inti=0;i<base.Items.Count;i++)
{
if(getItem(i).id==id)
returni;
}
return-1;
}
privatevoidFindItem(intid,ListItemitem,refListItemfind)
{
foreach(objectltinitem.Items)
{
ListItemlt1=(ListItem)lt;
if(lt1.id==id)
{
find=lt1;
break;
}
FindItem(id,lt1,reffind);
}
}
privatevoidFindCheckedItem(ListItemCollectionitems,refCheckedListItemCollectioncheckeditems)
{
foreach(objectltinitems)
{
ListItemlt1=(ListItem)lt;
if(lt1.Checked)checkeditems.Add(lt1);
FindCheckedItem(lt1.Items,refcheckeditems);
}
}
privateListItemFindRealListItem(ListItemitem)
{
if(item.Parent==null)//为根节点
{
foreach(ListItemltinthis.m_items)
{
if(lt.id==item.id)
returnlt;
}
returnnull;
}
else
{
ListItemtemp=item;
while(true)//找到根级
{
if(temp.Parent==null)break;
if(temp.Parent.GetType()==typeof(ComboBox))break;
temp=(temp.ParentasListItem);
}
ListItemfind=null;
//找子项里
FindItem(item.id,temp,reffind);
returnfind;
}
}
internalvoidsetText(intid,stringtext)
{
intindex=FindItem(id);
if(index!=-1)
{
getItem(index).Text=text;
}
}
internalvoidsetImageIndex(intid,intimageIndex)
{
intindex=FindItem(id);
if(index!=-1)
getItem(index).ImageIndex=imageIndex;
}
internalvoidsetForeColor(intid,ColorforeColor)
{
intindex=FindItem(id);
if(index!=-1)
getItem(index).ForeColor=foreColor;
}
internalvoidsetBackColor(intid,ColorbackColor)
{
intindex=FindItem(id);
if(index!=-1)
getItem(index).BackColor=backColor;
}
internalvoidsetFont(intid,Fontfont)
{
intindex=FindItem(id);
if(index!=-1)
getItem(index).Font=font;
}
internalvoidsetChecked(intid,boolcheck)
{
intindex=FindItem(id);
if(index!=-1)
getItem(index).Checked=check;
}
internalvoidsetItem(intid,ListItemitem)
{
intindex=FindItem(id);
if(index!=-1)
base.Items[index]=item.CloneData();
}
privateListItemgetItem(intindex)
{
if(index<0||index>base.Items.Count-1)
thrownewArgumentNullException("索引值超出集合的范围");
return(ListItem)base.Items[index];
}
#endregion
#regionProperties
[Category("Data"),Description("用于绑定的数据源。")]
publicnewobjectDataSource
{
get
{
returnthis.objSource;
}
set
{
this.objSource=value;
base.DataSource=null;
}
}
[Category("Appearance"),
Editor("System.Windows.Forms.Design.ImageIndexEditor,System.Design",typeof(UITypeEditor)),
TypeConverter(typeof(ImageIndexConverter)),
DefaultValue(-1)]
publicintImageIndex
{
get
{
returnthis.m_ImageIndex;
}
set
{
this.m_ImageIndex=value;
}
}
[Description("组合框中的项的图象所使用的ImageList控件。"),
Browsable(true),
DefaultValue((string)null)]
publicImageListImageList
{
get
{
returnthis.m_ImageList;
}
set
{
this.m_ImageList=value;
}
}
[Category("Behavior"),
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
Editor(typeof(CollectionEditor),typeof(UITypeEditor)),
MergableProperty(false),
Description("组合框中的项。"),
DefaultValue((string)null),
Localizable(true)]
publicnewListItemCollectionItems
{
get
{
if(m_items==null)
m_items=newListItemCollection(this,this);
returnthis.m_items;
}
}
[Browsable(false)]
publicnewListItemSelectedItem
{
get
{
if(this.SelectedIndex==-1)
{
returnnull;
}
returnFindRealListItem(getItem(this.SelectedIndex));
}
}
[Browsable(false)]
publicnewstringSelectedText
{
get
{
if(this.SelectedIndex==-1)
{
returnnull;
}
returnSelectedItem.Text;
}
set
{
if((this.SelectedIndex!=-1)&&!this.blnIsChange)
{
SelectedItem.Text=value;
}
}
}
[Browsable(false)]
publicnewobjectSelectedValue
{
get
{
if(this.SelectedIndex==-1)
{
returnnull;
}
returnSelectedItem.Value;
}
set
{
if(this.SelectedIndex!=-1)
{
SelectedItem.Value=value;
}
}
}
[Browsable(false)]
publicCheckedListItemCollectionCheckedItems
{
get{
CheckedListItemCollectioncheckitems=newCheckedListItemCollection();
if(m_CheckBoxes)
FindCheckedItem(this.m_items,refcheckitems);
returncheckitems;
}
}
[Category("Appearance"),
Description("获取或设置鼠标移上列表项时的前景景颜色。")]
publicColorItemHoverColor
{
get{returnm_ItemHoverColor;}
set{m_ItemHoverColor=value;}
}
[Category("Appearance"),
Description("获取或设置鼠标移上列表项时的背景颜色。")]
publicColorItemHoverBackColor
{
get{returnm_ItemHoverBackColor;}
set{m_ItemHoverBackColor=value;}
}
[Category("Appearance"),
DefaultValue((string)null),
Description("获取或设置鼠标移上列表项时的背景颜色。")]
publicColorItemHoverGradientBackColor
{
get{returnm_ItemHoverGradientBackColor;}
set{m_ItemHoverGradientBackColor=value;}
}
[DefaultValue(16),
Description("子节点的缩进宽度。")]
publicintIndent
{
get{returnm_Indent;}
set{m_Indent=value;}
}
[DefaultValue(false),
Description("是否显示复选框。")]
publicboolCheckBoxes
{
get{returnm_CheckBoxes;}
set{m_CheckBoxes=value;}
}
#endregion
#regionListItemCollection
publicclassListItemCollection:IList,ICollection,IEnumerable
{
privateComboBoxowner;
privateobjectparent;
privateArrayListitems;
privateboolinserted=true;
internalbytelevel=0;
//Methods
internalListItemCollection(ComboBoxcomboBox,objectparent)
{
items=newArrayList();
this.owner=comboBox;
this.parent=parent;
}
publicListItemCollection()
{
items=newArrayList();
}
internalListItemCollection(boolinserted)
{
items=newArrayList();
this.inserted=inserted;
}
publicListItemthis[intindex]
{
get{
if(index<0||index>items.Count-1)
thrownewArgumentNullException("索引值超出集合的范围");
returnitems[index]asListItem;
}
set
{
if(index<0||index>items.Count-1)
thrownewArgumentNullException("索引值超出集合的范围");
ListItemitem=(ListItem)items[index];
value.id=item.id;
value.level=item.level;
items[index]=value;
if(owner!=null)owner.setItem(value.id,value);
}
}
publicintCount
{
get{returnitems.Count;}
}
publicintAdd(stringText)
{
returnInsert(-1,newListItem(Text));
}
publicintAdd(stringText,objectValue)
{
returnInsert(-1,newListItem(Text,Value));
}
publicintAdd(stringText,intImageIndex)
{
returnInsert(-1,newListItem(Text,ImageIndex));
}
publicintAdd(stringText,objectValue,intImageIndex)
{
returnInsert(-1,newListItem(Text,Value,ImageIndex));
}
publicintAdd(ListItemitem)
{
returnInsert(-1,item);
}
publicvoidAddRange(ListItem[]items)
{
for(IEnumeratore=items.GetEnumerator();e.MoveNext();)
Insert(-1,(ListItem)e.Current);
}
publicintInsert(intindex,ListItemitem)
{
intret=0;
if(inserted)
item.level=level;
intm=1;
if(index==-1)
{
index=this.Count;
m=0;//为添加
}
item.Host(owner);
item.Parent=parent;
item.Text=(item.Text.Length==0)?item.GetType().Name:item.Text;
items.Insert(index,item);
if(inserted)
{
item.id=ComboBox.nextId++;
if(owner!=null)
{
ret=item.Index=owner.InsertItem(index,item,m);
AddItem(item,item.Items);
}
}
returnret;
}
internalvoidHost(ComboBoxcomboBox,objectparent)
{
this.owner=comboBox;
this.parent=parent;
}
privatevoidAddItem(ListItemparent,ListItemCollectionitems)
{
inti=0;
foreach(ListItemiteminitems)
{
item.Host(owner);
item.Parent=parent;
item.level=items.level;
item.Index=owner.InsertItem(i,item,0);
i++;
}
}
publicvoidRemove(ListItemitem)
{
if(owner!=null)owner.RemoveItem(item);
items.Remove(item);
}
publicvoidRemoveAt(intindex)
{
if(owner!=null)owner.RemoveItem(this[index]);
items.RemoveAt(index);
}
publicintIndexOf(ListItemitem)
{
returnitems.IndexOf(item);
}
publicboolContains(ListItemitem)
{
returnitems.Contains(item);
}
publicvoidClear()
{
items.Clear();
owner.ClearItem();
}
publicIEnumeratorGetEnumerator()
{
returnitems.GetEnumerator();
}
ICollectionMembersICollectionMembers
voidICollection.CopyTo(Arrayarray,intindex)
{
for(IEnumeratore=this.GetEnumerator();e.MoveNext();)
array.SetValue(e.Current,index++);
}
boolICollection.IsSynchronized
{
get{returnfalse;}
}
objectICollection.SyncRoot
{
get{returnthis;}
}
#endregion
IListMembersIListMembers
objectIList.this[intindex]
{
get{returnthis[index];}
set{this[index]=(ListItem)value;}
}
boolIList.Contains(objectitem)
{
returnContains((ListItem)item);
}
intIList.Add(objectitem)
{
returnAdd((ListItem)item);
}
boolIList.IsFixedSize
{
get{returnfalse;}
}
intIList.IndexOf(objectitem)
{
returnIndexOf((ListItem)item);
}
voidIList.Insert(intindex,objectitem)
{
Insert(index,(ListItem)item);
}
voidIList.Remove(objectitem)
{
Remove((ListItem)item);
}
voidIList.RemoveAt(intindex)
{
RemoveAt(index);
}
voidIList.Clear()
{
Clear();
}
boolIList.IsReadOnly
{
get{returnfalse;}
}
#endregion
}
#endregion
CheckedListItemCollectionCheckedListItemCollection
publicclassCheckedListItemCollection:CollectionBase
{
publicvoidAdd(ListItemitem)
{
List.Add(item);
}
publicvoidRemove(ListItemitem)
{
List.Remove(item);
}
publicListItemthis[intindex]
{
get{
if(index<0||index>List.Count-1)
thrownewArgumentNullException("索引值超出集合的范围");
returnList[index]asListItem;
}
}
}
#endregion
ComboBoxWindowComboBoxWindow
internalclassComboBoxWindow:NativeWindow
{
privateSystem.Windows.Forms.ComboBox.ObjectCollectionitems;
privateIntPtrhandle=IntPtr.Zero;
internalComboBoxWindow(System.Windows.Forms.ComboBox.ObjectCollectionitems,IntPtrhandle)
{
this.items=items;
this.handle=handle;
}
protectedoverridevoidWndProc(refMessagem)
{
if(m.Msg==0x201)//WM_LBUTTONDOWN
{
Win32.RECTrect=newWin32.RECT();
Win32.GetClientRect(m.HWnd,refrect);
Win32.POINTAPIpt=newWin32.POINTAPI();
pt.x=Win32.LOWORD(m.LParam.ToInt32());
pt.y=Win32.HIWORD(m.LParam.ToInt32());
//如果在区域内
if(newRectangle(rect.Left,rect.Top,rect.Left+rect.Right,rect.Top+rect.Bottom).Contains(newPoint(pt.x,pt.y)))
{
intnItemHeight=Win32.SendMessage(m.HWnd,0x1A1,0,0);//LB_GETITEMHEIGHT
//获得顶部项的索引
intnTopIndex=Win32.SendMessage(m.HWnd,0x18E,0,0);//LB_GETTOPINDEX
intnIndex=nTopIndex+pt.y/nItemHeight;
if(items.Count==0)
{
base.WndProc(refm);
return;
}
//判断是否在复选框处
if(pt.x>((ListItem)items[nIndex]).checkboxLeft&&pt.x<((ListItem)items[nIndex]).checkboxLeft+16)
{
Win32.RECTre=newWin32.RECT();
//取位置
Win32.SendMessage(m.HWnd,0x198,nIndex,refre);//LB_GETITEMRECT
//重画
Win32.InvalidateRect(m.HWnd,re,0);
//发送自定消息勾选复选框
Win32.SendMessage(handle,0x400+0x105,nIndex,0);
return;
}
}
}
base.WndProc(refm);
}
}
#endregion
}
}
{
internalsealedclassListItemConverter:ExpandableObjectConverter
{
publicoverrideboolCanConvertTo(ITypeDescriptorContextcontext,TypedestinationType)
{
if(destinationType==typeof(System.ComponentModel.Design.Serialization.InstanceDescriptor))
returntrue;
else
returnbase.CanConvertTo(context,destinationType);
}
publicoverrideobjectConvertTo(ITypeDescriptorContextcontext,System.Globalization.CultureInfoculture,objectvalue,TypedestinationType)
{
if(destinationType==typeof(System.ComponentModel.Design.Serialization.InstanceDescriptor))
{
TypevalueType=value.GetType();
ConstructorInfoci=valueType.GetConstructor(System.Type.EmptyTypes);
ListItemitem=(ListItem)value;
returnnewInstanceDescriptor(ci,null,false);
}
else
returnbase.ConvertTo(context,culture,value,destinationType);
}
}
}
internalclassWin32
{
[DllImport("user32",EntryPoint="GetClientRect")]
publicstaticexternintGetClientRect(
IntPtrhwnd,
refRECTlpRect
);
[DllImport("user32",EntryPoint="GetWindowRect")]
publicstaticexternintGetWindowRect(
IntPtrhwnd,
refRECTlpRect
);
[DllImport("user32",EntryPoint="PtInRect")]
publicstaticexternintPtInRect(
refRECTlpRect,
refPOINTAPIpt
);
[DllImport("user32",EntryPoint="SendMessage")]
publicstaticexternintSendMessage(
IntPtrhwnd,
intwMsg,
intwParam,
intlParam
);
[DllImport("user32",EntryPoint="SendMessage")]
publicstaticexternintSendMessage(
IntPtrhwnd,
intwMsg,
intwParam,
refRECTrect
);
[DllImport("user32",EntryPoint="InvalidateRect")]
publicstaticexternintInvalidateRect(
IntPtrhwnd,
RECTlpRect,
intbErase
);
[StructLayout(LayoutKind.Sequential)]
publicstructRECT
{
publicintLeft;
publicintTop;
publicintRight;
publicintBottom;
}
[StructLayout(LayoutKind.Sequential)]
publicstructPOINTAPI
{
publicintx;
publicinty;
}
publicstaticintHIWORD(intlparam)
{
return((lparam>>16)&0xffff);
}
publicstaticintLOWORD(intlparam)
{
return(lparam&0xffff);
}
publicstaticintMakeLParam(intLoWord,intHiWord)
{
return(HiWord<<16)|(LoWord&0xffff);
}
}
}