博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C# 自定义控件类库(带checkbox的combox控件)
阅读量:4886 次
发布时间:2019-06-11

本文共 21074 字,大约阅读时间需要 70 分钟。

最近喜欢上了自己创建控件,感觉方便使用

其实自定义控件,除了之前说的自己建立个独立的控件库的方法外,另一个办法就是通过继承已有的控件来扩展功能

今天就是用这个办法,在combox的控件中扩展个check功能,这样就可以有选择的选择多条Item了。

其实主要的步骤就是:1.定义属性和各个属性的读写  2.定义方法和各种函数实现功能 3.关联各种方法和事件触发

首先,要确定框架

using System; using System.Collections; using System.Collections.Generic; using System.Data; using System.Drawing; using System.Diagnostics; using System.Windows.Forms; namespace PowerComboBox //带有复选框的combox {
public class xComboBox : ComboBox {
public xComboBox() {
this.DrawMode =System.Windows.Forms.DrawMode.OwnerDrawFixed; //这是关键;没有这一步自定义的控件无法显示出来 } } }

  下来我们就要看看需要定义什么样的属性了

     

private string mDividerFormat = ""; private Color mGroupColor = System.Drawing.SystemColors.WindowText; //分组的背景颜色     private System.Windows.Forms.CheckState[] mItemsChecks;//用来记录选中的状态,那些选中,那些没选中。只要读这里就知道。     private System.Windows.Forms.CheckState[] mItemsChecks_Temp; private bool mCheckBoxes; //是否使用复选框     private System.Windows.Forms.CheckState mChecked = CheckState.Unchecked; //默认的选中状态     private Color mGridColor = Color.FromArgb(240, 248, 255);//条目的背景颜色

  各种变量

private char mItemSeparator1 = ',';//用来分隔多条选中信息的     private char mItemSeparator2 = '&';//同上     private Int32 mHoverIndex; private double mHoverIndex_Dec; private Int32 mLastSelectedIndex = -1; private Timer mTimer;//定时器,用来控制在Item选中状态变化过程中,发生的事     private Int32 mFirerTimer; private Int32 mKillEvents1; private Int32 mKillEvents2; private Int32 mKillEvents3; private Int32 mLastMessage;

  再来看看各个变量的读写设置

[System.ComponentModel.Description("Use this property to set divider flag.  Recommend you use three hyphens ---."), System.ComponentModel.Category("Power Properties")] //这种写法就是要将属性在属性页中显示的样子(请参照我之前写的Property Grid的内容) public string DividerFormat     {
get {
return mDividerFormat; } set {
mDividerFormat = value; } } [System.ComponentModel.Description("Use this property to set the ForeColor of the grouping text."), System.ComponentModel.Category("Power Properties")] public Color GroupColor {
get {
return mGroupColor; } set {
mGroupColor = value; } } [System.ComponentModel.Description("Use this property to set the BackColor of the grid."), System.ComponentModel.Category("Power Properties")] public Color GridColor {
get {
return mGridColor; } set {
mGridColor = value; } } //ORIGINAL LINE: Public Property ItemsChecks(ByVal xIndex As Int32) As System.Windows.Forms.CheckState //INSTANT C# NOTE: C# does not support parameterized properties - the following property has been divided into two methods: [System.ComponentModel.Description("Use this property to get/set corresponding checkboc values."), System.ComponentModel.Category("Power Properties")] public System.Windows.Forms.CheckState get_ItemsChecks(Int32 xIndex) {
try {
return mItemsChecks[xIndex]; } catch (Exception ex) {
return CheckState.Unchecked; } } public void set_ItemsChecks(Int32 xIndex, System.Windows.Forms.CheckState value) //将条目的序号和选中状态配对mItemsChecks[xIndex] = value {
if (xIndex < 0 | xIndex > this.Items.Count) {
return; } if (mKillEvents3 != 0) {
mItemsChecks[xIndex] = value; //mItemsChecks[xIndex] = value;将条目序号和状态对应 if (ItemChecked != null) ItemChecked(SelectedIndex); } else {
if (this.CheckBoxes)//如果已经选定check功能 {
if (this.DroppedDown)// {
if (this.SelectedIndex == xIndex) {
this.SelectedIndex = -1; } this.SelectedIndex = xIndex; PrepareTimer(); if (ItemChecked != null) ItemChecked(SelectedIndex); //raises event immeadiatly } else {
if (mItemsChecks == null) {
Array.Resize(ref mItemsChecks_Temp, this.Items.Count); mItemsChecks_Temp[xIndex] = value; CommitCheckList(); } else {
mItemsChecks[xIndex] = value; } } } } } [System.ComponentModel.Description("Use this property to enable checkboxes."), System.ComponentModel.Category("Power Properties")] public bool CheckBoxes {
get {
return mCheckBoxes; } set {
mCheckBoxes = value; } } [System.ComponentModel.Description("Use this property to set CheckBox's default value."), System.ComponentModel.Category("Power Properties")] public System.Windows.Forms.CheckState Checked {
get {
return mChecked; } set {
mChecked = value; } } [System.ComponentModel.Description("Use this property to set item separator1 character."), System.ComponentModel.Category("Power Properties")] public char ItemSeparator1 {
get {
return mItemSeparator1; } set {
mItemSeparator1 = value; } } [System.ComponentModel.Description("Use this property to set item separator2 character."), System.ComponentModel.Category("Power Properties")] public char ItemSeparator2 {
get {
return mItemSeparator2; } set {
mItemSeparator2 = value; } }

  

下来就是事件方法了

其实大体的流程就是在选择了check功能后,下拉菜单在打开时重新绘制个带check的Items。然后在选中某个Item项时,combox的Text中就重新显示说有checked的项目

protected override void OnSelectedIndexChanged(System.EventArgs e)//当选项的check状态被选中时     {
Int32 i = 0; if (mKillEvents1 != 0 || SelectedIndex == -1) {
return; } if (this.DividerFormat.Length > 0 && IsItemAGroup(SelectedIndex)) {
if (! this.CheckBoxes) {
this.SelectedIndex = mLastSelectedIndex; return; } else {
mKillEvents3 += 1; i = SelectedIndex; do {
i += 1; if (i > (this.Items.Count - 1)) {
break; } if (IsItemAGroup(i)) {
break; } this.SelectedIndex = i; } while (true); mKillEvents3 -= 1; base.OnSelectedIndexChanged(e); return; } } //2 - standard event stuff mLastSelectedIndex = this.SelectedIndex; base.OnSelectedIndexChanged(e); //3 - toggle checkbox/force redraw if (this.CheckBoxes && SelectedIndex > -1) {
mKillEvents3 += 1; if (this.get_ItemsChecks(this.SelectedIndex) == CheckState.Checked) {
this.set_ItemsChecks(this.SelectedIndex, CheckState.Unchecked); } else {
this.set_ItemsChecks(this.SelectedIndex, CheckState.Checked); } mKillEvents3 -= 1; PrepareTimer(); } } protected override void OnDrawItem(DrawItemEventArgs e)//重新绘制Item,根据用户是否选择了check定义item项的样子 {
Int32 zX1 = 0; Pen zPen = null; float zWidth = 0F; string zText = null; Font zFont = null; Color zFore = new Color(); System.Windows.Forms.VisualStyles.CheckBoxState zState = 0; //1 - Exit if (e.Index < 0) {
base.OnDrawItem(e); return; } //2 - Grouping if (this.Items[e.Index].ToString().Contains(this.mDividerFormat) & mDividerFormat.Length > 0) {
e.DrawBackground(); if (DataSource == null) //TN Engineers {
zText = this.Items[e.Index].ToString(); } else {
zText = ((DataRowView)(this.Items[e.Index]))[this.DisplayMember].ToString(); } zText = this.Items[e.Index].ToString(); zText = " " + zText.Replace(this.mDividerFormat, "") + " "; zFont = new Font(Font, FontStyle.Bold); if (e.BackColor == System.Drawing.SystemColors.Highlight) {
zFore = Color.Gainsboro; } else {
zFore = this.GroupColor; } zPen = new Pen(zFore); zWidth = e.Graphics.MeasureString(zText, zFont).Width; zX1 = Convert.ToInt32(e.Bounds.Width - zWidth) / 2; e.Graphics.DrawRectangle(zPen, new Rectangle(e.Bounds.X, e.Bounds.Y + e.Bounds.Height / 2, zX1, 1)); e.Graphics.DrawRectangle(zPen, new Rectangle(e.Bounds.Width - zX1, e.Bounds.Y + e.Bounds.Height / 2, e.Bounds.Width, 1)); e.Graphics.DrawString(zText, zFont, new SolidBrush(zFore), zX1, e.Bounds.Top); } else {
if (mKillEvents2 == 0) {
if (true == System.Convert.ToBoolean(e.State & DrawItemState.Selected)) {
e.DrawBackground(); } else if (true == (e.Index % 2 == 0)) {
e.Graphics.FillRectangle(new SolidBrush(Color.White), e.Bounds); } else {
e.Graphics.FillRectangle(new SolidBrush(mGridColor), e.Bounds); } } if (this.DataSource == null) {
e.Graphics.DrawString(this.Items[e.Index].ToString(), Font, new SolidBrush(e.ForeColor), e.Bounds.Left, e.Bounds.Top); } else {
e.Graphics.DrawString(((DataRowView)(this.Items[e.Index]))[this.DisplayMember].ToString(), Font, new SolidBrush(e.ForeColor), e.Bounds.Left, e.Bounds.Top); } //5 - CheckBox if (mCheckBoxes) {
if (System.Convert.ToBoolean(e.State & DrawItemState.Selected)) {
if (this.get_ItemsChecks(e.Index) == CheckState.Checked) {
zState = System.Windows.Forms.VisualStyles.CheckBoxState.CheckedHot; } else {
zState = System.Windows.Forms.VisualStyles.CheckBoxState.UncheckedHot; } } else {
if (this.get_ItemsChecks(e.Index) == CheckState.Checked) {
zState = System.Windows.Forms.VisualStyles.CheckBoxState.CheckedNormal; } else {
zState = System.Windows.Forms.VisualStyles.CheckBoxState.UncheckedNormal; } } zX1 = this.FontHeight; zPen = new Pen(Color.Black, 1F); zPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot; System.Windows.Forms.CheckBoxRenderer.DrawCheckBox(e.Graphics, new System.Drawing.Point(e.Bounds.X + e.Bounds.Width - 15, e.Bounds.Y + 1 + ((e.Bounds.Height - 13) / 2)), e.Bounds, "", this.Font, false, zState); } } //6 - Base event base.OnDrawItem(e); } protected override void WndProc(ref System.Windows.Forms.Message m)//消息处理 {
const Int32 WM_SETCURSOR = 32; const Int32 WM_COMMAND = 273; const int WM_CTLCOLORLISTBOX = 308; const Int32 CB_ADDSTRING = 323; const Int32 CB_GETCURSEL = 327; const Int32 WM_LBUTTONUP = 514; const Int32 OCM_COMMAND = 8465; if (true == (m.Msg == WM_CTLCOLORLISTBOX || m.Msg == WM_SETCURSOR)) {
GetHoverIndexFromCursor(); if (mHoverIndex_Dec >= 0) {
if (mHoverIndex > -1 & mHoverIndex < this.Items.Count & this.DroppedDown) {
if (ItemHover != null) ItemHover(mHoverIndex); } } } else if (true == (m.Msg == CB_ADDSTRING)) {
base.WndProc(ref m); StretchCheckList(); return; } else if (true == (m.Msg == WM_COMMAND && m.WParam == new System.IntPtr(66536))) {
if (mLastMessage == 8235) //FIX for ignoring SIC event on keyboard controlling i.e. F4 + down arrow {
mHoverIndex = this.SelectedIndex; if (ItemHover != null) ItemHover(mHoverIndex); mLastMessage = m.Msg; return; } //1 - normal behaviour when no checkboxes if (! this.mCheckBoxes) {
base.WndProc(ref m); return; } if (! this.DroppedDown) {
return; } SendMessage(this.Handle, OCM_COMMAND, 591814, new IntPtr(1705748)); //1 SendMessage(this.Handle, OCM_COMMAND, 67526, new IntPtr(1705748)); //2 SendMessage(this.Handle, CB_GETCURSEL, 0, new IntPtr(0)); //3 SendMessage(this.Handle, WM_LBUTTONUP, 0, new IntPtr(721012)); //4 return; } mLastMessage = m.Msg; base.WndProc(ref m); } protected override void OnKeyDown(System.Windows.Forms.KeyEventArgs e) //键盘事件 {
if (this.DroppedDown && e.KeyCode == Keys.Space) {
mKillEvents3 += 1; e.SuppressKeyPress = true; if (this.CheckBoxes) {
if (this.get_ItemsChecks(this.SelectedIndex) == CheckState.Checked) //如果选择的条目是被选中的状态 {
this.set_ItemsChecks(this.SelectedIndex, CheckState.Unchecked);//则是变反 } else {
this.set_ItemsChecks(this.SelectedIndex, CheckState.Checked); } mKillEvents3 -= 1; } else //如果没有选用check的形式条目,那么就不用处理 {
this.DroppedDown = false; } PrepareTimer(); //时间空间处理刷新text } base.OnKeyDown(e); }

  下面是方法中用到的各个处理方法

private void PrepareTimer() //通过时间控件来刷新combox的text显示的内容     {
mTimer = null; mTimer = new Timer(); mTimer.Interval = 64; mTimer.Enabled = true; mTimer.Tick += mTimer_Tick; mFirerTimer = 1; } private void mTimer_Tick(object sender, System.EventArgs e) {
if (mFirerTimer > 0) {
mTimer.Enabled = false; mTimer.Dispose(); ForceRedraw(); this.Text = FormatCheckString(); //将选中的显示出来 mFirerTimer = 0;//判断是否启动timer控件的 } } public void StretchCheckList() {
Int32 i = 0; Array.Resize(ref mItemsChecks, this.Items.Count); //1. suck in temp if (mItemsChecks_Temp != null) {
mItemsChecks = mItemsChecks_Temp; mItemsChecks_Temp = null; //2. formats list with pre-defined format } else {
if (mChecked != CheckState.Checked) {
return; } for (i = 0; i <= mItemsChecks.GetUpperBound(0); i++) {
if (! (IsItemAGroup(i))) {
mItemsChecks[i] = CheckState.Checked; } } } this.Text = FormatCheckString(); } public void CommitCheckList() {
mItemsChecks = mItemsChecks_Temp; this.Text = FormatCheckString(); } //private private void GetHoverIndexFromCursor() {
Int32 yPos = 0; yPos = this.PointToClient(System.Windows.Forms.Cursor.Position).Y; if (this.DropDownStyle == ComboBoxStyle.Simple) {
yPos -= (this.ItemHeight + 10); } else {
yPos -= (this.Size.Height + 1); } mHoverIndex_Dec = yPos / (double)this.ItemHeight; mHoverIndex = System.Convert.ToInt32(Math.Floor(mHoverIndex_Dec)); } private void ForceRedraw() {
if (this.Items.Count > 0) {
mKillEvents1 += 1; mKillEvents2 += 1; this.SelectedIndex -= 1; mKillEvents2 -= 1; this.SelectedIndex += 1; mKillEvents1 -= 1; } } private string FormatCheckString() //形成text {
//NOTE returns "a,b & c" for internal use Int32 i = 0; System.Text.StringBuilder sb = new System.Text.StringBuilder(""); string s = null; string zFirst = null; string zLast = null; Int32 zLastComa = 0; string zSpace = " "; if (! this.CheckBoxes) //首先要确定是check的item {
return this.Text; } for (i = 0; i < this.Items.Count; i++) {
if (IsItemAGroup(i)) //什么意思啊 {
continue; } if (this.get_ItemsChecks(i) == CheckState.Checked)//确定选项是被选中的 {
if (DataSource == null) //TN Engineers {
sb.Append(this.Items[i].ToString()); } else {
sb.Append(((DataRowView)(this.Items[i]))[this.DisplayMember].ToString()); } sb.Append(mItemSeparator1); //没加一项就加一个分隔符& } } s = sb.ToString(); if (s.Length == 0) {
return ""; } s = s.Substring(0, s.Length - 1); zLastComa = s.LastIndexOf(mItemSeparator1); if (zLastComa != -1) {
zLast = s.Substring(zLastComa); zFirst = s.Substring(0, zLastComa); s = zFirst + zSpace + zLast.Replace(Convert.ToString(mItemSeparator1), Convert.ToString(mItemSeparator2) + zSpace); return s; } else {
return s + " "; } } private bool IsItemAGroup(Int32 xIndex) {
if (this.mDividerFormat.Length > 0 && this.Items[xIndex].ToString().Contains(this.mDividerFormat)) {
return true; } //INSTANT C# NOTE: Inserted the following 'return' since all code paths must return a value in C#: return false; } //public public string CHECKED2CSV() {
//NOTE returns "a,b,c" for external user Int32 i = 0; System.Text.StringBuilder sb = new System.Text.StringBuilder(""); string s = null; for (i = 0; i < this.Items.Count; i++) {
if (IsItemAGroup(i)) {
continue; } if (this.get_ItemsChecks(i) == CheckState.Checked) {
if (DataSource == null) //TN Engineers {
sb.Append(this.Items[i].ToString() + ","); } else {
sb.Append(((DataRowView)(this.Items[i]))[this.ValueMember].ToString() + ","); } } } s = sb.ToString(); if (s.Length > 0) {
s = s.Substring(0, s.Length - 1); } return s; } public string CHECKED2IDCSV() {
return CHECKED2IDCSV(true); } //INSTANT C# NOTE: Overloaded method(s) are created above to convert the following method having optional parameters: //ORIGINAL LINE: Public Function CHECKED2IDCSV(Optional ByVal xZeroBound As Boolean = true) As String public string CHECKED2IDCSV(bool xZeroBound) {
Int32 i = 0; Int32 c = 0; Int32 a = 0; System.Text.StringBuilder sb = new System.Text.StringBuilder(""); string s = null; if (xZeroBound) {
a = 0; } else {
a = 1; } for (i = 0; i < this.Items.Count; i++) {
if (IsItemAGroup(i)) {
continue; } if (this.get_ItemsChecks(i) == CheckState.Checked) {
if (this.mDividerFormat.Length > 0) {
sb.Append((c + a).ToString() + ","); } else {
sb.Append((i + a).ToString() + ","); } } c += 1; } s = sb.ToString(); if (s.Length > 0) {
s = s.Substring(0, s.Length - 1); } return s; } public string CHECKED2BITSHIFT() {
Int32 i = 0; Int32 c = 1; Int32 a = 0; for (i = 0; i < this.Items.Count; i++) {
if (IsItemAGroup(i)) {
continue; } if (this.get_ItemsChecks(i) != CheckState.Checked) {
a += c; } c = (c * 2); } return a.ToString(); } public void CheckAll(CheckState xChecked) {
Int32 i = 0; for (i = 0; i < this.Items.Count; i++) {
this.set_ItemsChecks(i, xChecked); } this.Text = FormatCheckString(); }

  其实知道了流程,完全就可以自定义控件来使用。方便好用

转载于:https://www.cnblogs.com/Tammie/archive/2011/09/01/2161583.html

你可能感兴趣的文章
ExtJs4.2 RadioGroup CheckboxGroup
查看>>
在Application中集成Microsoft Translator服务之使用http获取服务
查看>>
flask页面中Head标签内容为空问题
查看>>
小说Symbian的签名
查看>>
高级java面试宝典
查看>>
声明,本博客文章均为转载,只为学习,不为其他用途。感谢技术大牛的技术分享,让我少走弯路。...
查看>>
c# 导出Excel
查看>>
Status: Checked in and viewable by authorized users 出现在sharepoint 2013 home 页面
查看>>
python数据预处理
查看>>
Python之路,Day21 - 常用算法学习
查看>>
Android安全-代码安全1-ProGuard混淆处理
查看>>
部署core
查看>>
mysql 时间设置
查看>>
如何在 Xcode 中修改应用的名字
查看>>
有关交换机——熟悉原理是必须的【转载】
查看>>
ACM(数学问题)——UVa202:输入整数a和b(0≤a≤3000,1≤b≤3000),输出a/b的循环小数表示以及循环节长度。...
查看>>
【转】Android 读取doc文件
查看>>
js 数据绑定
查看>>
jsp的C标签一般使用方法以及js接收servlet中的对象及对象数字
查看>>
window.frameElement的使用
查看>>