65.9K
CodeProject 正在变化。 阅读更多。
Home

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

2017 年 7 月 24 日

CPOL

2分钟阅读

viewsIcon

50265

downloadIcon

353

这是一个 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

 

© . All rights reserved.