My Telerik Multiselect Combobox (Windows Application) simulates a ComboBox with a CheckedListBox as a Dropdown

0
16

Introduction

There are two attached zipped folders, the first named “KhaledMultiSelectCombo”  which contains the custom usercontrol with the combobox that allows Multiselection. The second zipped folder contains a windows forms application that uses the combobox on a windows form.

Background

User should only have a background in .NET and Windows forms and I will explain step by step how to use the custom usercontrol on a windows form.

Using the code

At first the following image is the MultiCombobox that will show for the end user.

Now let’s explain step by step how this could be done

Step1: the attached folder “KhaledMultiSelectCombo” contains  my custom usercontrol (Multicombo) which is composed of 4 telerik controls as shown in the following image.

Control1:Radtextbox to show Selected values.

Control2:Radtextbox to show selected texts.

Control3:Radtreeview to display options that can be selected using checkboxes.

Control4:A combobox that is shrinked and used only to expand the Radtree with the available options.

Step2: I shrinked the usercontrol width and hide to be similar to Microsoft combobox initial size and I fixed the Dock, Anchor and visible properties of the four controls so as to show Radtextbox that displays selectedtexts on the top as shown in the following image.

Step3: I divided my code into 3 regions, the first to set the public end user properties, the second is for the public end user events (newly created and raised events) and the third is the functions that acts as an engine to my logic of multi selection and enables the multicombo to show its list of options even if was put inside a groupbox(or any container) as its list of options will be displayed on the top of any parent container border.

//
//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 
 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
 
 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

Step4: How to add the Multiselect combo to your windows forms? this will be explained in details through the following points and you can use the second attached folder “MultiComboDLLOnAnotherProject” that has a windows form sample with the Multicombo added to it.

Simply, in your windows form application do the following to add and use the Multicombo custom control:

* Create a folder named “ref” then right click it and press “add existing items” to add the usercontrol dll “khaledMultiComboControl.dll” from the bin folder in the “KhaledMultiSelectCombo” folder and also add Telerik dlls from there.

*There is a referrence folder, right click it then press “Add referrence” to add the dlls just added in your “ref” folder in the previous point.

*Open your Toolbox and right click it then press “choose Items” and in the “.NET framework components” tab browse the Multicombobox dll “khaledMultiComboControl.dll” from the “ref” folder then press ok. The Multicombobox control will show on your toolbox and you will be able to drag it on your form.

* The final point is the following sample code that shoes how to populate and use the Multiselect combobox on your 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
 
 Dim table As New DataTable
 
 table.Columns.Add("ID", GetType(Integer))
 table.Columns.Add("Text", GetType(String))
 
 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

LEAVE A REPLY