Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / VB

A Checked Listbox Collection Editor

4.22/5 (8 votes)
23 Feb 2008CPOL1 min read 1   1.3K  
Implements a custom, checked listbox editor in a property grid.

Introduction

This code demonstrates how to create a custom property editor particularly suitable for key/value pairs of information. It implements IWindowsFormsEditorService and UITypeEditorEditStyle, which are used to create a custom property grid control.

Background

Several existing projects demonstrate how to create a custom ListBox, but I could not find any that demonstrated a checked ListBox, so I came up with my own.

Using the Code

The My.PropertyGridControls.CheckedListBoxEditor custom property editor is used in conjunction with a custom properties class bound to a property grid.



VB.NET
Imports System
Imports System.ComponentModel
Imports System.Windows.Forms.Design
Imports System.Windows.Forms
Imports System.Collections.Specialized

Namespace My.PropertyGridControls

    #Region "CheckedListBoxEditor"
    ''' <summary>
    ''' The control displayed in the property grid
    ''' </summary>
    ''' <remarks></remarks>
    Public Class CheckedListBoxEditor

        ''' <summary>
        ''' The default text displayed in the property grid "value" column
        ''' </summary>
        ''' <remarks></remarks>
        Private _strValue As String = "(Collection)"

        ''' <summary>
        ''' Creates a custom property editor using the CheckedListBoxEditor class
        ''' as the UITypeEditor
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        <Description("This property contains the checked ListBox collection."), _
            EditorAttribute(GetType(CheckedListBoxUITypeEditor), _
                GetType(System.Drawing.Design.UITypeEditor))> _
            Public Property CheckedListBoxCollectionProperty() As String
            Get
                Return _strValue
            End Get
            Set(ByVal value As String)
                _strValue = "(Collection)"
            End Set
        End Property

    End Class
    #End Region

    #Region "CheckedListBoxUITypeEditor"
     ''' <summary>
    ''' Custom, editable checked ListBox control
    ''' </summary>
    ''' <remarks>This demo loads a comma-delimited string collection of URLs
    ''' and boolean values to set the checked state for each item.</remarks>
    Public Class CheckedListBoxUITypeEditor
        Inherits System.Drawing.Design.UITypeEditor
        Public WithEvents cbx As New CheckedListBox
        Private es As IWindowsFormsEditorService

        ''' <summary>
        ''' Override the UITypeEditorEditStyle to return the editor style:
        ''' drop-down, modal, or none
        ''' </summary>
        ''' <param name="context"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Overloads Overrides Function GetEditStyle_
            (ByVal context As System.ComponentModel.ITypeDescriptorContext) _
                As System.Drawing.Design.UITypeEditorEditStyle

            'returns the editor style:  drop-down, modal, or none
            Return System.Drawing.Design.UITypeEditorEditStyle.DropDown

        End Function

        ''' <summary>
        ''' Override whether or not the ListBox control should be resizable
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Overloads Overrides ReadOnly Property IsDropDownResizable() As Boolean
            Get
                'if set to true, adds a grip to the lower left portion of the ListBox,
                'which makes the ListBox resizable as run time
                Return True

            End Get
        End Property

        ''' <summary>
        ''' Override the default method for editing values in the ListBox
        ''' </summary>
        ''' <param name="context"></param>
        ''' <param name="provider"></param>
        ''' <param name="value"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Overloads Overrides Function EditValue_
            (ByVal context As System.ComponentModel.ITypeDescriptorContext, _
            ByVal provider As System.IServiceProvider, ByVal value As Object) As Object

            'instantiate the custom property editor service provider
            es = DirectCast(provider.GetService(GetType(IWindowsFormsEditorService)), _
                IWindowsFormsEditorService)

            If es IsNot Nothing Then

                'load the ListBox items
                LoadListBoxItems()

                'sort the items
                cbx.Sorted = True

                'show the control
                es.DropDownControl(cbx)

            End If

            'ensure function returns a value on all code paths
            Return Nothing

        End Function

        ''' <summary>
        ''' Save the ListBox key/value pairs to My.Settings.UrlList
        ''' </summary>
        ''' <param name="sender"></param>
        ''' <param name="e"></param>
        ''' <remarks></remarks>
        Private Sub bx_Leave(ByVal sender As Object, ByVal e As System.EventArgs) _
                Handles cbx.Leave
            'clear the old list
            My.Settings.UrlsList.Clear()

            With cbx
                'load the ListBox key/value pairs
                For i As Integer = 0 To .Items.Count - 1

                    Dim txt As String = .Items(i).ToString
                    Dim chk As String = .GetItemChecked(i).ToString

                    'concatenate the key/value pair
                    Dim combined As String = LCase(txt) & "," & LCase(chk)

                    If .Items(i).ToString IsNot "" Then

                        'add the concatenated string to the "UrlsList" string collection
                        My.Settings.UrlsList.Add(combined)

                    End If
                Next
            End With
            'save the config file
            My.Settings.Save()
        End Sub

        ''' <summary>
        ''' Loads My.Settings.UrlList comma-delimited string collection
        ''' into the custom collection editor.
        ''' </summary>
        ''' <remarks></remarks>
        Private Sub LoadListBoxItems()
            'create an array list
            Dim a As New ArrayList

            'load the config file "UrlsList" string collection into the array
            For Each s As String In My.Settings.UrlsList

                'split the URL from the checked value
                a.Add(Split(s, ","))

            Next

            'create a hashtable, so we can refer to the items in a key/value pair format
            Dim h As New Hashtable

            'load the array into the hashtable
            For i As Integer = 0 To a.Count - 1

                'add the first array item as the key, the second as the value
                h.Add(CType(a.Item(i), Array).GetValue(0).ToString, _
                    CType(a.Item(i), Array).GetValue(1).ToString)

            Next

            'dispose of the array list
            a = Nothing

            'clear the ListBox items
            cbx.Items.Clear()

            'index the hashtable
            For Each de As DictionaryEntry In h

                'add the key/value pairs to the ListBox
                cbx.Items.Add(de.Key, CBool(de.Value))

            Next

            'dispose of the collection
            h = Nothing

        End Sub

    End Class
    #End Region

End Namespace

A StringCollection from the app.config settings file is used to load the items displayed in the ListBox. My.Settings.UrlsList items are stored as comma-delimited key/value pairs.

XML
<userSettings>
    <CheckedListBoxCollectionEditor.My.MySettings>
        <setting name="UrlsList" serializeAs="Xml">
            <value>
                <ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
                    <string>http://www.thefreedictionary.com/,true</string>
                    <string>http://medical-dictionary.thefreedictionary.com/,
                        true</string>
                    <string>http://legal-dictionary.thefreedictionary.com/,true</string>
                    <string>http://financial-dictionary.thefreedictionary.com/,
                        true</string>
                    <string>http://acronyms.thefreedictionary.com/,true</string>
                    <string>http://idioms.thefreedictionary.com/,true</string>
                    <string>http://encyclopedia2.thefreedictionary.com/,true</string>
                    <string>http://encyclopedia.thefreedictionary.com/,true</string>
                    <string>http://www.m-w.com/dictionary/,true</string>
                    <string>http://www.freedictionary.org/search/,true</string>
                    <string>http://www.yourdictionary.com/,true</string>
                    <string>http://en.wikipedia.org/wiki/,true</string>
                </ArrayOfString>
            </value>
        </setting>
    </CheckedListBoxCollectionEditor.My.MySettings>
</userSettings>

To use the control:

  • Create a form
  • Add a property grid
  • Instantiate the custom property editor, and
  • Bind it to the property grid

Remember to change the values in My.Settings.UrlsList accordingly. You can also replace LoadListBoxItems() with your own ListBox item-loading function.

VB.NET
''' <summary>
''' Sample form with a property grid whose selected object is the custom ListBox editor
''' </summary>
''' <remarks></remarks>
Public Class Form1

    Public Sub New()

        ' This call is required by the Windows Form Designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.

        'create the custom checked ListBox editor
        Dim c As New My.PropertyGridControls.CheckedListBoxEditor

        'bind it to the property grid
        Me.PropertyGrid1.SelectedObject = c
    End Sub
End Class


The ListBox is made resizable by overriding the IsDropDownResizable() property, which is set to True in the demo.

VB.NET
''' <summary>
''' Override whether or not the ListBox control should be resizable
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Overloads Overrides ReadOnly Property IsDropDownResizable() As Boolean
    Get

        Return True

    End Get
End Property


If you prefer a non-resizable ListBox, simply change IsDropDownResizable() to False.

VB.NET
''' <summary>
''' Override whether or not the ListBox control should be resizable
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Overloads Overrides ReadOnly Property IsDropDownResizable() As Boolean
    Get
        'if set to true, adds a grip to the lower left portion of the ListBox,
        'which makes the ListBox resizable as run time
        Return False

    End Get
End Property


To Do

  • Allow in-place editing of the text strings
  • Add custom "add record" control to the bottom of the ListBox

History

  • Initial release

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)