在做Winform项目的时候经常要用到利用下拉选项控件存在键和值,但是Combobox只提供存取一列值的功能。
解决方案:
方案一:放置2个combobox,其中一个存值的隐藏起来。
方案二:.重写combobox,存在键与值。
第一种方案我相信很多人都不愿意用,而且当一个界面上百个控件的时候更加不可能这么使用,所以我重写xombobox来实现这一效果。
做成DLL之后,可以在项目里面引用,像用微软自带的控件一样拖放使用。
09年做项目里面实现的这一效果,项目中已经全面普及,特做记录。
源代码:
DropDownList.vb源代码:
Imports System Imports System.Collections.Generic Imports System.ComponentModel Imports System.Data Imports System.Drawing Imports System.Text Imports System.Windows.Forms Imports System.Runtime.InteropServices ''' <summary> ''' ComboBox的扩展控件 解决ComboBox不能存储键值对的问题 ''' 支持添加键值对,或者只添加键 ''' </summary> ''' <remarks></remarks> Public Class DropDownList Inherits ComboBox Private _selectedtext As String = String.Empty Public Shadows Items As New ItemsCollection(Me) '必须声明为PUBLIC覆盖基类的方法 否则访问的依然是基类的Items对象 ''' <summary> ''' 设置或者取得DropDownList的当前文本 ''' </summary> ''' <value></value> ''' <returns>String</returns> ''' <remarks></remarks> Public Shadows Property SelectedText() As String Get If Me.SelectedIndex > -1 AndAlso Me.Items.Count > 0 Then If TypeOf (Me.SelectedItem) Is Item Then _selectedtext = TryCast(Me.SelectedItem, Item).Text Else _selectedtext = Me.SelectedItem.ToString() End If End If Return _selectedtext End Get Set(ByVal value As String) If Me.Items.Count > 0 Then For i As Integer = 0 To Me.Items.Count - 1 If TypeOf (Me.Items(i)) Is Item Then If (TryCast(Me.Items(i), Item).Text = value) Then Me.SelectedIndex = i Exit For Else Me.SelectedIndex = -1 End If Else If Me.Items(i).ToString() = value Then Me.SelectedIndex = i Exit For Else Me.SelectedIndex = -1 End If End If Next End If _selectedtext = value End Set End Property Private _selectedvalue As String = String.Empty ''' <summary> ''' 设置或者取得DropDownList的当前值 ''' </summary> ''' <value></value> ''' <returns>String</returns> ''' <remarks></remarks> Public Shadows Property SelectedValue() As String Get If Me.SelectedIndex > -1 AndAlso Me.Items.Count > 0 Then If TypeOf (Me.SelectedItem) Is Item Then _selectedvalue = TryCast(Me.SelectedItem, Item).Value Else _selectedvalue = Me.SelectedItem.ToString() End If End If Return _selectedvalue End Get Set(ByVal value As String) If Me.Items.Count > 0 Then For i As Integer = 0 To Me.Items.Count - 1 If TypeOf (Me.Items(i)) Is Item Then If (TryCast(Me.Items(i), Item).Value = value) Then Me.SelectedIndex = i Exit For Else Me.SelectedIndex = -1 End If Else If Me.Items(i).ToString() = value Then Me.SelectedIndex = i Exit For Else Me.SelectedIndex = -1 End If End If Next End If _selectedvalue = value End Set End Property Private _selecteditem As Object = Nothing ''' <summary> ''' 设置或者取得DropDownList的当前项(注:取的时候,可以判断是否Item对象,如果是,可以转换为Item对象之后取得TEXT,VALUE值。默认Item的Tostring()是取Text值) ''' </summary> ''' <value></value> ''' <returns>Object</returns> ''' <remarks></remarks> Public Shadows Property SelectedItem() As Object Get If Me.SelectedIndex > -1 AndAlso Me.Items.Count > 0 Then If TypeOf (Me.Items(Me.SelectedIndex)) Is Item Then _selecteditem = TryCast(Me.Items(Me.SelectedIndex), Item) Else _selecteditem = Me.Items(Me.SelectedIndex) End If End If Return _selecteditem End Get Set(ByVal value As Object) If Me.Items.Count > 0 Then For i As Integer = 0 To Me.Items.Count - 1 If TypeOf (value) Is Item Then If TryCast(Me.Items(i), Item) = TryCast(value, Item) Then Me.SelectedIndex = i Exit For Else Me.SelectedIndex = -1 End If Else If Me.Items(i).ToString() = value.ToString() Then Me.SelectedIndex = i Exit For Else Me.SelectedIndex = -1 End If End If Next End If _selecteditem = value End Set End Property Public Sub New() MyBase.New() '组件设计器需要此调用。 InitializeComponent() ' Items.Add(MyBase.Items) 'MyBase.Items.Clear() Me.SelectedIndex = -1 ' Me.DropDownStyle = ComboBoxStyle.DropDownList End Sub Protected Overrides Sub Dispose(ByVal disposing As Boolean) If disposing AndAlso components IsNot Nothing Then components.Dispose() End If MyBase.Dispose(disposing) End Sub ''' <summary> ''' 向项的集合中添加键值对 ''' </summary> ''' <param name="strText">键</param> ''' <param name="strValue">值</param> ''' <returns>Integer</returns> ''' <remarks></remarks> Public Function Add(ByVal strText As String, ByVal strValue As String) As Integer Return Me.Items.Add(strText, strValue) End Function ''' <summary> ''' 向项的集合中只添加键 ''' </summary> ''' <param name="value">键(注:默认情况下,值与键的结果一样)</param> ''' <returns>Integer</returns> ''' <remarks></remarks> Public Function Add(ByVal value As String) As Integer Return Me.Items.Add(value) End Function ''' <summary> ''' 向项的集合中添加项的集合 ''' </summary> ''' <param name="items">项的集合</param> ''' <remarks></remarks> Public Sub AddRange(ByVal items As Object()) Me.Items.AddRange(items) End Sub ''' <summary> ''' 将一项插入项的集合中指定索引处 ''' </summary> ''' <param name="index">插入项的从零开始的索引位置</param> ''' <param name="item">插入的项</param> ''' <remarks></remarks> Public Sub Insert(ByVal index As Integer, ByVal item As Object) Me.Items.Insert(index, item) End Sub ''' <summary> ''' 清除项的集合中的所有项 ''' </summary> ''' <remarks></remarks> Public Sub Clear() Me.Items.Clear() End Sub ''' <summary> ''' 移除项的集合中的项 ''' </summary> ''' <param name="objItem">移除的项</param> ''' <remarks></remarks> Public Sub Remove(ByVal objItem As Object) If Me.Items.Count > 0 Then For i As Integer = 0 To Me.Items.Count - 1 If TypeOf (Me.Items(i)) Is Item Then If TryCast(Me.Items(i), Item) = TryCast(objItem, Item) Then Me.Items.RemoveAt(i) Exit For End If Else If Me.Items(i).ToString() = objItem.ToString() Then Me.Items.RemoveAt(i) Exit For End If End If Next End If End Sub ''' <summary> ''' 检索指定的项在项的集合中的索引 ''' </summary> ''' <param name="value">检索的项</param> ''' <returns></returns> ''' <remarks></remarks> Public Function IndexOf(ByVal value As Object) As Integer If Me.Items.Count > 0 Then For i As Integer = 0 To Me.Items.Count - 1 If TypeOf (value) Is Item Then If TypeOf (Me.Items(i)) Is Item Then If TryCast(Me.Items(i), Item) = TryCast(value, Item) Then Return i End If End If Else If Me.Items(i).ToString() = value.ToString() Then Return i End If End If Next Return -1 End If End Function ''' <summary> ''' 移除项的集合中指定索引处的项 ''' </summary> ''' <param name="index">移除的索引值</param> ''' <remarks></remarks> Public Shadows Sub RemoveAt(ByVal index As Integer) Me.Items.RemoveAt(index) End Sub ''' <summary> ''' 返回项的集合的项数 ''' </summary> ''' <value></value> ''' <returns>Integer</returns> ''' <remarks></remarks> Public ReadOnly Property Count() As Integer Get Return Me.Items.Count End Get End Property
#Region "重写Items类" Public Class ItemsCollection Inherits ComboBox.ObjectCollection ' Implements IList, ICollection, IEnumerable Private myComboBox As ComboBox Sub New(ByVal myComboBox As ComboBox) MyBase.New(myComboBox) Me.myComboBox = myComboBox End Sub ''' <summary> ''' 添加键值对 ''' </summary> ''' <param name="strText">键</param> ''' <param name="strValue">值</param> ''' <returns>Integer</returns> ''' <remarks></remarks> Public Overloads Function Add(ByVal strText As String, ByVal strValue As String) As Integer Dim item As New Item(strText, strValue) Return myComboBox.Items.Add(item) End Function ''' <summary> ''' 只添加键 ''' </summary> ''' <param name="value">键(注:默认情况下,值与键的结果一样)</param> ''' <returns>Integer</returns> ''' <remarks></remarks> Public Overloads Function Add(ByVal value As Object) As Integer Return myComboBox.Items.Add(value) End Function ''' <summary> ''' 添加项的集合 ''' </summary> ''' <param name="items">项的集合</param> ''' <remarks></remarks> Public Shadows Sub AddRange(ByVal items As Object()) myComboBox.Items.AddRange(items) End Sub ''' <summary> ''' 将一项插入集合中指定索引处 ''' </summary> ''' <param name="index">插入项的从零开始的索引位置</param> ''' <param name="item">插入的项</param> ''' <remarks></remarks> Public Shadows Sub Insert(ByVal index As Integer, ByVal item As Object) myComboBox.Items.Insert(index, item) End Sub ''' <summary> ''' 移除项 ''' </summary> ''' <param name="objItem">移除的项</param> ''' <remarks></remarks> Public Shadows Sub Remove(ByVal objItem As Object) If myComboBox.Items.Count > 0 Then For i As Integer = 0 To MyBase.Count - 1 If TypeOf (myComboBox.Items.Item(i)) Is Item Then If TryCast(myComboBox.Items.Item(i), Item) = TryCast(objItem, Item) Then Me.RemoveAt(i) Exit For End If Else If myComboBox.Items.Item(i).ToString() = objItem.ToString() Then Me.RemoveAt(i) Exit For End If End If Next End If End Sub ''' <summary> ''' 检索指定的项在集合中的索引 ''' </summary> ''' <param name="value">检索的项</param> ''' <returns></returns> ''' <remarks></remarks> Public Shadows Function IndexOf(ByVal value As Object) As Integer If myComboBox.Items.Count > 0 Then For i As Integer = 0 To myComboBox.Items.Count - 1 If TypeOf (value) Is Item Then If TypeOf (myComboBox.Items.Item(i)) Is Item Then If TryCast(myComboBox.Items.Item(i), Item) = TryCast(value, Item) Then Return i End If End If Else If myComboBox.Items.Item(i).ToString() = value.ToString() Then Return i End If End If Next Return -1 End If End Function #Region "重写迭代器,也可以直接调用父类的迭代器" '' ---------重写迭代器-------- 'Public Shadows Function GetEnumerator() As System.Collections.IEnumerator ' Return New ItemsEnumerator(myComboBox.Items) 'End Function 'Private Class ItemsEnumerator ' Implements IEnumerator ' Private position As Integer = -1 ' Private itemscollection As ItemsCollection ' Public Sub New(ByVal itemscollection As ItemsCollection) ' Me.itemscollection = itemscollection ' End Sub ' Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext ' If (position < itemscollection.Count - 1) Then ' position = position + 1 ' Return True ' Else ' Return False ' End If ' End Function ' Public Sub Reset() Implements IEnumerator.Reset ' position = -1 ' End Sub ' Public ReadOnly Property Current() As Object Implements IEnumerator.Current ' Get ' Return itemscollection(position) ' End Get ' End Property 'End Class ''------------------------------------ #End Region '直接调用系统的迭代器 ''' <summary> ''' 返回一个可用于循环访问项集合的枚举数 ''' </summary> ''' <returns>System.Collections.IEnumerator</returns> ''' <remarks></remarks> Public Shadows Function GetEnumerator() As System.Collections.IEnumerator Return myComboBox.Items.GetEnumerator() End Function ''' <summary> ''' 检索指定索引处的项 ''' </summary> ''' <param name="index">索引值</param> ''' <value></value> ''' <returns>Object</returns> ''' <remarks></remarks> Default Public Shadows Property Item(ByVal index As Integer) As Object Get If index <= -1 Then Return Nothing Return myComboBox.Items.Item(index) End Get Set(ByVal value As Object) myComboBox.Items.Item(index) = value End Set End Property ''' <summary> ''' 返回集合的项数 ''' </summary> ''' <value></value> ''' <returns>Integer</returns> ''' <remarks></remarks> Public Shadows ReadOnly Property Count() As Integer Get Return myComboBox.Items.Count End Get End Property ''' <summary> ''' 检索某项是否在集合内 ''' </summary> ''' <param name="value">检索的项</param> ''' <returns>Boolean</returns> ''' <remarks></remarks> Public Shadows Function Contains(ByVal value As Object) As Boolean If myComboBox.Items.Count > 0 Then For i As Integer = 0 To myComboBox.Items.Count - 1 If TypeOf (value) Is Item Then If TypeOf (myComboBox.Items.Item(i)) Is Item Then If TryCast(myComboBox.Items.Item(i), Item) = TryCast(value, Item) Then Return True End If End If Else If myComboBox.Items.Item(i).ToString() = value.ToString() Then Return False End If End If Next Return False End If End Function ''' <summary> ''' 将整个集合复制到现有对象的数组中,从该数组内的指定位置开始复制 ''' </summary> ''' <param name="destination">要将该集合复制到的对象数组</param> ''' <param name="arrayIndex">要将该集合复制到的目标数组中的位置</param> ''' <remarks></remarks> Public Shadows Sub CopyTo(ByVal destination() As Object, ByVal arrayIndex As Integer) myComboBox.Items.CopyTo(destination, arrayIndex) End Sub ''' <summary> ''' 获取当前实例的 System.Type ''' </summary> ''' <returns>System.Type</returns> ''' <remarks></remarks> Public Shadows Function [GetType]() As System.Type Return myComboBox.Items.GetType() End Function ''' <summary> ''' 移除集合中指定索引处的项 ''' </summary> ''' <param name="index">移除的索引值</param> ''' <remarks></remarks> Public Shadows Sub RemoveAt(ByVal index As Integer) myComboBox.Items.RemoveAt(index) End Sub ''' <summary> ''' 确定指定的 System.Object 是否等于当前的 System.Object ''' </summary> ''' <param name="obj">比较的项</param> ''' <returns></returns> ''' <remarks></remarks> Public Shadows Function Equals(ByVal obj As Object) As Boolean Return myComboBox.Items.Equals(obj) End Function ''' <summary> ''' 用作特定类型的哈希函数。System.Object.GetHashCode 适合在哈希算法和数据结构(如哈希表)中使用 ''' </summary> ''' <returns>Integer</returns> ''' <remarks></remarks> Public Shadows Function GetHashCode() As Integer Return myComboBox.Items.GetHashCode() End Function ''' <summary> ''' 获取指示能否修改该集合的值 ''' </summary> ''' <value></value> ''' <returns>Boolean</returns> ''' <remarks></remarks> Public Shadows ReadOnly Property IsReadOnly() As Boolean Get Return myComboBox.Items.IsReadOnly() End Get End Property ''' <summary> ''' 返回表示当前 System.Object 的 System.String ''' </summary> ''' <returns>String</returns> ''' <remarks></remarks> Public Overridable Shadows Function ToString() As String Return myComboBox.Items.ToString() End Function ''' <summary> ''' 清除所有项 ''' </summary> ''' <remarks></remarks> Public Shadows Sub Clear() myComboBox.Items.Clear() End Sub End Class #End Region End Class #Region "创建下拉列表的项" ''' <summary> ''' 创建下拉列表的项 ''' </summary> ''' <remarks></remarks> Public Class Item Private _text As String Public Property Text() As String Get Return _text End Get Set(ByVal value As String) _text = value End Set End Property Private _value As String Public Property Value() Get Return _value End Get Set(ByVal value) _value = value End Set End Property Public Sub New(ByVal strText As String, ByVal strValue As String) Me._text = strText Me._value = strValue End Sub Public Overrides Function ToString() As String Return Me._text End Function '重写= Public Shared Operator =(ByVal OneItem As Item, ByVal TwoItem As Item) As Boolean If OneItem IsNot Nothing AndAlso TwoItem IsNot Nothing AndAlso OneItem._text = TwoItem._text AndAlso OneItem._value = TwoItem._value Then Return True Else Return False End If End Operator Public Shared Operator <>(ByVal OneItem As Item, ByVal TwoItem As Item) As Boolean If OneItem IsNot Nothing AndAlso TwoItem IsNot Nothing AndAlso OneItem._text = TwoItem._text AndAlso OneItem._value = TwoItem._value Then Return False Else Return True End If End Operator End Class #End Region
DropDownList.Designer.vb源代码:
Partial Class DropDownList Inherits System.Windows.Forms.ComboBox <System.Diagnostics.DebuggerNonUserCode()> _ Public Sub New(ByVal Container As System.ComponentModel.IContainer) MyClass.New() 'Windows.Forms 类撰写设计器支持所必需的 Container.Add(Me) End Sub '组件设计器所必需的 Private components As System.ComponentModel.IContainer '注意: 以下过程是组件设计器所必需的 '可使用组件设计器修改它。 '不要使用代码编辑器修改它。 <System.Diagnostics.DebuggerStepThrough()> _ Private Sub InitializeComponent() components = New System.ComponentModel.Container() End Sub End Class
调用界面
Form1.vb源代码:
Imports System.Windows.Forms Public Class Form1 Private Sub DropDownList1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles DropDownList1.SelectedIndexChanged 'MsgBox(Me.DropDownList1.SelectedText & "----" & Me.DropDownList1.SelectedValue) 'MsgBox(TryCast(Me.DropDownList1.SelectedItem, Item).Value) 'MsgBox(Me.DropDownList1.IndexOf(Me.DropDownList1.SelectedItem)) End Sub Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Me.DropDownList1.BeginUpdate() Me.DropDownList1.Items.Add("1") Me.DropDownList1.Items.Add("2") Me.DropDownList1.Items.Add("3") Me.DropDownList1.Items.Add("4") Me.DropDownList1.Items.Add("aa", "11") Me.DropDownList1.Items.Add("开始", "11实施") Me.DropDownList1.Items.Add("盛大") Me.DropDownList1.Items.Add("盛大发撒旦法") Me.DropDownList1.Items.Add("bb", "22") Me.DropDownList1.Items.Add("cc", "33") Me.DropDownList1.EndUpdate() DropDownList1.DropDownStyle = ComboBoxStyle.DropDown DropDownList1.MaxDropDownItems = 10 ' Me.DropDownList1.SelectedIndex = 3 ' Me.DropDownList1.SelectedText = "a" ' Dim items As Item() = New Item(2) {New Item("a1", "a1"), New Item("b1", "b1"), New Item("c1", "c1")} ' Me.DropDownList1.Items.Insert(0, "11") Dim item As Item = New Item("开始", "11实施") ' MsgBox(Me.DropDownList1.Items.IndexOf(item)) 'MsgBox(Me.DropDownList1.Items(3).ToString()) ' MsgBox(Me.DropDownList1.FindString("开始")) ' Me.DropDownList1.Remove(item) 'MsgBox(DropDownList1.Items.Count()) ' MsgBox(DropDownList1.Items.ToString()) Me.ComboBox1.Items.Add("1") Me.ComboBox1.Items.Add("2") Me.ComboBox1.Items.Add("3") Me.ComboBox1.Items.Add("4") Me.ComboBox1.DropDownStyle = ComboBoxStyle.DropDown 'Me.DropDownList1.Items(-1) = 11111 'MsgBox(Me.DropDownList1.SelectedText & "----" & Me.DropDownList1.SelectedValue) End Sub Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click MsgBox(Me.DropDownList1.SelectedText & "----" & Me.DropDownList1.SelectedValue) MsgBox(Me.ComboBox1.SelectedItem) End Sub End Class
Form1.Designer.vb源代码:
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _ Partial Class Form1 Inherits System.Windows.Forms.Form 'Windows 窗体设计器所必需的 Private components As System.ComponentModel.IContainer '注意: 以下过程是 Windows 窗体设计器所必需的 '可以使用 Windows 窗体设计器修改它。 '不要使用代码编辑器修改它。 <System.Diagnostics.DebuggerStepThrough()> _ Private Sub InitializeComponent() Me.components = New System.ComponentModel.Container Me.Button1 = New System.Windows.Forms.Button Me.DropDownList3 = New WindowsApplication1.DropDownList(Me.components) Me.DropDownList2 = New WindowsApplication1.DropDownList(Me.components) Me.DropDownList1 = New WindowsApplication1.DropDownList(Me.components) Me.ComboBox1 = New System.Windows.Forms.ComboBox Me.SuspendLayout() ' 'Button1 ' Me.Button1.Location = New System.Drawing.Point(190, 182) Me.Button1.Name = "Button1" Me.Button1.Size = New System.Drawing.Size(75, 23) Me.Button1.TabIndex = 3 Me.Button1.Text = "Button1" Me.Button1.UseVisualStyleBackColor = True ' 'DropDownList3 ' Me.DropDownList3.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList Me.DropDownList3.FormattingEnabled = True Me.DropDownList3.Location = New System.Drawing.Point(47, 185) Me.DropDownList3.Name = "DropDownList3" Me.DropDownList3.SelectedValue = "" Me.DropDownList3.Size = New System.Drawing.Size(121, 20) Me.DropDownList3.TabIndex = 2 ' 'DropDownList2 ' Me.DropDownList2.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList Me.DropDownList2.FormattingEnabled = True Me.DropDownList2.Location = New System.Drawing.Point(111, 127) Me.DropDownList2.Name = "DropDownList2" Me.DropDownList2.SelectedValue = "" Me.DropDownList2.Size = New System.Drawing.Size(121, 20) Me.DropDownList2.TabIndex = 1 ' 'DropDownList1 ' Me.DropDownList1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList Me.DropDownList1.FormattingEnabled = True Me.DropDownList1.Location = New System.Drawing.Point(47, 47) Me.DropDownList1.Name = "DropDownList1" Me.DropDownList1.SelectedValue = "" Me.DropDownList1.Size = New System.Drawing.Size(121, 20) Me.DropDownList1.TabIndex = 0 ' 'ComboBox1 ' Me.ComboBox1.FormattingEnabled = True Me.ComboBox1.Location = New System.Drawing.Point(60, 212) Me.ComboBox1.Name = "ComboBox1" Me.ComboBox1.Size = New System.Drawing.Size(121, 20) Me.ComboBox1.TabIndex = 4 ' 'Form1 ' Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 12.0!) Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font Me.ClientSize = New System.Drawing.Size(292, 256) Me.Controls.Add(Me.ComboBox1) Me.Controls.Add(Me.Button1) Me.Controls.Add(Me.DropDownList3) Me.Controls.Add(Me.DropDownList2) Me.Controls.Add(Me.DropDownList1) Me.Name = "Form1" Me.Text = "Form1" Me.ResumeLayout(False) End Sub Friend WithEvents DropDownList1 As WindowsApplication1.DropDownList Friend WithEvents DropDownList2 As WindowsApplication1.DropDownList Friend WithEvents DropDownList3 As WindowsApplication1.DropDownList Friend WithEvents Button1 As System.Windows.Forms.Button Friend WithEvents ComboBox1 As System.Windows.Forms.ComboBox End Class