多选组合框(Windows 自定义控件)模拟带有弹出列表的 ComboBox






3.92/5 (12投票s)
这是一个 Windows Forms 自定义用户控件,我用它来创建一个带复选框的多选组合框,用于选择一个或多个选项。它是使用 Telerik 控件混合创建的,因为 Telerik 本身没有多选下拉列表 Windows Forms 控件。
引言
有两个附加的压缩文件夹,第一个名为 "KhaledMultiSelectCombo",其中包含带有组合框的自定义用户控件,允许多选。第二个压缩文件夹包含一个 Windows Forms 应用程序,该应用程序在 Windows Form 上使用组合框。
背景
用户应该只有 .NET 和 Windows Forms 的背景知识,我将逐步解释如何在 Windows Form 上使用自定义用户控件。
使用代码
首先,下图是最终用户将看到的多选组合框。
现在让我们逐步解释如何完成
步骤 1:附加文件夹 "KhaledMultiSelectCombo" 包含我的自定义用户控件(Multicombo),它由 4 个 Telerik 控件组成,如下图所示。
控件 1:Radtextbox 用于显示选定值。
控件 2:Radtextbox 用于显示选定的文本。
控件 3:Radtreeview 用于显示可以使用复选框选择的选项。
控件 4:一个组合框,被缩小,仅用于展开带有可用选项的 Radtree。
步骤 2: 我缩小了用户控件的宽度并隐藏它,使其类似于 Microsoft 组合框的初始大小,并且我修复了四个控件的 Dock、Anchor 和可见属性,以便在顶部显示显示所选文本的 Radtextbox,如下图所示。
步骤 3: 我将代码分为 3 个区域,第一个用于设置公共最终用户属性,第二个用于公共最终用户事件(新创建和引发的事件),第三个是充当多选逻辑引擎的函数,并使 multicombo 能够显示其选项列表,即使它被放置在 groupbox(或任何容器)内,因为它的选项列表将显示在任何父容器边框的顶部。
// //here is the properties region #Region "Setting UserControl Properties" Public Overrides Property Font As System.Drawing.Font Get Return RadTreeView.Font End Get Set(ByVal value As System.Drawing.Font) RadTextBoxValue.Font = New System.Drawing.Font("Microsoft Sans Serif", 8.25!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte)) btnFakeList.Font = New System.Drawing.Font("Microsoft Sans Serif", 8.25!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte)) RadTextBoxDisplay.Font = value RadTreeView.Font = value End Set End Property Public Property Datasource() As Object Get Return dt End Get Set(ByVal value As Object) dt = value RadTreeView.DataSource = dt End Set End Property Private dispMember As String Public Property DisplayMember() As String Get Return dispMember End Get Set(ByVal value As String) dispMember = value RadTreeView.DisplayMember = value End Set End Property Private valMember As String Public Property ValueMember() As String Get Return valMember End Get Set(ByVal value As String) valMember = value RadTreeView.ValueMember = value End Set End Property Public Property SelectedText() As String Get Return RadTextBoxDisplay.Text End Get Set(ByVal value As String) Dim s As String = "" For Each n As RadTreeNode In RadTreeView.Nodes If n.Text = value Then n.Checked = True s = value Else n.Checked = False End If Next RadTextBoxDisplay.Text = s End Set End Property Public Property SelectedValue() As String Get Return RadTextBoxValue.Text End Get Set(ByVal value As String) Dim s As String = "" If Not value = "0" Then Dim st() As String = value.Trim.Split(",") For Each el As String In st For Each n As RadTreeNode In RadTreeView.Nodes If n.Value = el Then n.Checked = True If s = "" Then s = el Else s += "," + el End If Else n.Checked = False End If Next Next RadTextBoxValue.Text = s.Trim Else RadTreeView.Nodes(0).Checked = True End If End Set End Property Public ReadOnly Property SelectedCount() As Integer Get Dim cheked As Integer For Each n As RadTreeNode In RadTreeView.Nodes If n.Checked And n.Text <> "All" Then cheked += 1 End If Next Return cheked End Get End Property Public Property MultiSelect() As Boolean Get Return RadTreeView.MultiSelect End Get Set(ByVal value As Boolean) RadTreeView.MultiSelect = value If value = False Then For Each n As RadTreeNode In RadTreeView.Nodes n.Checked = False Next RadTextBoxDisplay.Text = "" RadTextBoxValue.Text = "" End If End Set End Property Public Sub Collapse() RadTreeView.Visible = False Me.Height = 20 End Sub #End Region // //The Events Region looks as follows #Region "Setting UserControl Events" Public Event SelectedIndexChanged() Private Sub RadTextBoxRegion_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles RadTextBoxValue.TextChanged RaiseEvent SelectedIndexChanged() End Sub Public Event MouseLeaves() Private Sub RadTreeView_MouseLeave(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RadTreeView.MouseLeave RaiseEvent MouseLeaves() End Sub #End Region // //The following is the Internal functions region #Region "UserControl Internal Functions" Private Sub RadTreeView_NodeCheckedChanged(ByVal sender As System.Object, ByVal e As Telerik.WinControls.UI.RadTreeViewEventArgs) Handles RadTreeView.NodeCheckedChanged, RadTreeView.SelectedNodeChanged If Not _settingRadTreeSourceReg And Not _settingRadTreeSource Then Dim ss As String = "" Dim Al As Boolean = False If RadTreeView.Nodes.Count > 0 Then If RadTreeView.Nodes(0).Value = "0" And RadTreeView.Nodes(0).Checked Then Al = True End If _settingRadTreeSourceReg = True Dim chkdCapture As Integer = RadTreeView.CheckedNodes.Count If RadTreeView.Nodes(0).Value = "0" And Not RadTreeView.Nodes(0).Checked And chkdCapture = RadTreeView.Nodes.Count - 1 Then If RadTreeView.Nodes.Count > 0 Then If e.Node.Value <> 0 Then RadTreeView.Nodes(0).Checked = True Al = True End If End If ElseIf RadTreeView.Nodes(0).Value = "0" And RadTreeView.Nodes(0).Checked And chkdCapture = RadTreeView.Nodes.Count - 1 Then If RadTreeView.Nodes.Count > 0 Then If e.Node.Value <> 0 Then RadTreeView.Nodes(0).Checked = False Al = False End If End If ElseIf chkdCapture = 0 Then e.Node.Checked = True End If For Each it As RadTreeNode In RadTreeView.Nodes If Al Then If Not it.Checked Then it.Checked = True End If Else If RadTreeView.Nodes.Count > 1 Then If it.Checked And it.Index <> 1 And e.Node.Value = "0" Then 'when user uncheck all option it.Checked = False ElseIf it.Index = 1 And e.Node.Value = "0" And chkdCapture = 0 Then it.Checked = True Me.SubReg = it.Value Me.RadTextBoxValue.Text = it.Value Me.RadTextBoxDisplay.Text = it.Text End If End If End If If Not RadTreeView.MultiSelect And Not it.Value = e.Node.Value Then it.Checked = False End If If it.Checked Then If it.Value <> "0" Then If String.IsNullOrEmpty(ss) Then ss = it.Value.ToString RadTextBoxDisplay.Text = it.Text Else ss += "," + it.Value.ToString RadTextBoxDisplay.Text += "," + it.Text End If End If End If Next Me.SubReg = ss Me.RadTextBoxValue.Text = ss _settingRadTreeSourceReg = False CountEdits += 1 End If End If End Sub Private Sub btnFakeList_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnFakeList.Click If Me.Height = 160 Then btnFakeList.Focus() RadTreeView.Visible = False Me.Height = 20 CountEdits = 0 'Me.Focus() Else btnFakeList.Focus() Me.Height = 160 RadTreeView.Height = 140 RadTreeView.Visible = True CountEdits = 0 End If End Sub Private Sub RadTextBoxValue_KeyPress(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles RadTextBoxValue.KeyPress e.Handled = True End Sub Private Function getnewloc(ByRef c As System.Windows.Forms.Control, ByRef loc As System.Drawing.Point) If TypeOf c Is System.Windows.Forms.GroupBox Or TypeOf c Is System.Windows.Forms.Panel Then loc.X += c.Left loc.Y += c.Top getnewloc(c.Parent, loc) End If Return loc End Function Public Sub AdjustLoc(ByVal c As System.Windows.Forms.Control, ByVal f As System.Windows.Forms.Form) Dim loc As System.Drawing.Point = Nothing loc = getnewloc(c, loc) Me.Parent = f Me.Left += loc.X Me.Top += loc.Y Me.BringToFront() End Sub Public Sub AdjustLoc(ByVal c As System.Windows.Forms.Control, ByVal h As System.Windows.Forms.UserControl) Dim loc As System.Drawing.Point = Nothing loc = getnewloc(c, loc) Me.Parent = h Me.Left += loc.X Me.Top += loc.Y Me.BringToFront() End Sub Public Sub ShowInFront(ByVal f As System.Windows.Forms.Form) AdjustLoc(Me.Parent, f) End Sub Public Sub ShowInFront(ByVal h As System.Windows.Forms.UserControl) AdjustLoc(Me.Parent, h) End Sub Private Sub btnFakeList_LostFocus(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnFakeList.LostFocus, RadTreeView.LostFocus, RadTextBoxDisplay.LostFocus If Not RadTextBoxDisplay.Focused And Not btnFakeList.Focused And Not RadTreeView.Focused Then RadTreeView.Visible = False Me.Height = 20 End If End Sub Public Sub Clear() Me.RadTreeView.Nodes.Clear() Me.RadTextBoxDisplay.Text = "" End Sub Public Sub AddItem(ByVal item As String) Me.RadTreeView.Nodes.Add(item) End Sub Public Sub AddItem(ByVal txt As String, ByVal value As String) Dim newNode As New RadTreeNode() newNode.Value = value newNode.Text = txt RadTreeView.Nodes.Add(newNode) End Sub Private Sub MultiSelectionCombo_FontChanged(sender As System.Object, e As System.EventArgs) Handles MyBase.FontChanged Me.RadTreeView.Font = MyBase.Font Me.RadTextBoxDisplay.Font = MyBase.Font MyBase.Font = New System.Drawing.Font("Microsoft Sans Serif", 8.25!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte)) RadTextBoxValue.Font = New System.Drawing.Font("Microsoft Sans Serif", 8.25!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte)) btnFakeList.Font = New System.Drawing.Font("Microsoft Sans Serif", 8.25!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte)) End Sub #End Region
步骤 4: 如何将多选组合框添加到您的 Windows Forms? 这将通过以下几点详细解释,您可以使用第二个附加文件夹 "MultiComboDLLOnAnotherProject",其中包含一个添加了 Multicombo 的 Windows Form 示例。
简单来说,在您的 Windows Form 应用程序中,执行以下操作以添加和使用 Multicombo 自定义控件
* 创建一个名为 "ref" 的文件夹,然后右键单击它并按“添加现有项目”以从 "KhaledMultiSelectCombo" 文件夹中的 bin 文件夹中添加用户控件 dll "khaledMultiComboControl.dll",并从那里添加 Telerik dll。
* 有一个引用文件夹,右键单击它,然后按“添加引用”以添加您在前面一点中的“ref”文件夹中添加的 dll。
* 打开您的工具箱并右键单击它,然后按“选择项目”,在“.NET 框架组件”选项卡中浏览来自“ref”文件夹的 Multicombobox dll "khaledMultiComboControl.dll",然后按确定。 Multicombobox 控件将显示在您的工具箱上,您将能够将其拖到您的表单上。
* 最后一点是以下示例代码,它演示了如何在您的 Windows Forms 上填充和使用多选组合框。
Public Class Form1 Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Populate() End Sub Sub Populate() Dim dt As DataTable = GetTable(MultiSelectionCombo1.MultiSelect) MultiSelectionCombo1.Datasource = dt MultiSelectionCombo1.DisplayMember = "Text" MultiSelectionCombo1.ValueMember = "ID" MultiSelectionCombo1.ShowInFront(Me) MultiSelectionCombo1.SelectedValue = "0" End Sub Function GetTable(ByVal EnableMultiselect As Boolean) As DataTable ' Create new DataTable. Dim table As New DataTable ' Create 2 typed columns in the DataTable. table.Columns.Add("ID", GetType(Integer)) table.Columns.Add("Text", GetType(String)) ' Add rows table.Rows.Add(0, "All") table.Rows.Add(50, "Khaled") table.Rows.Add(10, "Ezzat") table.Rows.Add(21, "AbdelFattah") table.Rows.Add(100, "AbdelGawad") table.Rows.Add(1, "Abdelraouf") table.Rows.Add(2, "Esmael") table.Rows.Add(3, "Kareem") table.Rows.Add(4, "Janet") table.Rows.Add(1500, "Mary") Return table End Function Private Sub MultiSelectionCombo1_SelectedIndexChanged() Handles MultiSelectionCombo1.SelectedIndexChanged TextBox1.Text = MultiSelectionCombo1.SelectedText TextBox2.Text = MultiSelectionCombo1.SelectedValue lblcount.Text = MultiSelectionCombo1.SelectedCount lbltxt.Text = MultiSelectionCombo1.SelectedText End Sub Private Sub MultiSelectionCombo1_MouseLeaves() Handles MultiSelectionCombo1.MouseLeaves MultiSelectionCombo1.Collapse() End Sub Private Sub chkMultiSelect_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles chkMultiSelect.CheckedChanged If chkMultiSelect.Checked Then MultiSelectionCombo1.MultiSelect = True Else MultiSelectionCombo1.MultiSelect = False Populate() End If End Sub End Class