Click here to Skip to main content
Click here to Skip to main content

A Checked Listbox Collection Editor

, 23 Feb 2008
Rate this:
Please Sign up or sign in to vote.
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.



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

Namespace My.PropertyGridControls

    #Region "CheckedListBoxEditor"
    ''' <span class="code-SummaryComment"><summary></span>
    ''' The control displayed in the property grid
    ''' <span class="code-SummaryComment"></summary></span>
    ''' <span class="code-SummaryComment"><remarks></remarks></span>
    Public Class CheckedListBoxEditor

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

        ''' <span class="code-SummaryComment"><summary></span>
        ''' Creates a custom property editor using the CheckedListBoxEditor class
        ''' as the UITypeEditor
        ''' <span class="code-SummaryComment"></summary></span>
        ''' <span class="code-SummaryComment"><value></value></span>
        ''' <span class="code-SummaryComment"><returns></returns></span>
        ''' <span class="code-SummaryComment"><remarks></remarks></span>
        <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"

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

        ''' <span class="code-SummaryComment"><summary></span>
        ''' Override the UITypeEditorEditStyle to return the editor style:
        ''' drop-down, modal, or none
        ''' <span class="code-SummaryComment"></summary></span>
        ''' <span class="code-SummaryComment"><param name="context"></param></span>
        ''' <span class="code-SummaryComment"><returns></returns></span>
        ''' <span class="code-SummaryComment"><remarks></remarks></span>
        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

        ''' <span class="code-SummaryComment"><summary></span>
        ''' Override whether or not the ListBox control should be resizable
        ''' <span class="code-SummaryComment"></summary></span>
        ''' <span class="code-SummaryComment"><value></value></span>
        ''' <span class="code-SummaryComment"><returns></returns></span>
        ''' <span class="code-SummaryComment"><remarks></remarks></span>
        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

        ''' <span class="code-SummaryComment"><summary></span>
        ''' Override the default method for editing values in the ListBox
        ''' <span class="code-SummaryComment"></summary></span>
        ''' <span class="code-SummaryComment"><param name="context"></param></span>
        ''' <span class="code-SummaryComment"><param name="provider"></param></span>
        ''' <span class="code-SummaryComment"><param name="value"></param></span>
        ''' <span class="code-SummaryComment"><returns></returns></span>
        ''' <span class="code-SummaryComment"><remarks></remarks></span>
        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

        ''' <span class="code-SummaryComment"><summary></span>
        ''' Save the ListBox key/value pairs to My.Settings.UrlList
        ''' <span class="code-SummaryComment"></summary></span>
        ''' <span class="code-SummaryComment"><param name="sender"></param></span>
        ''' <span class="code-SummaryComment"><param name="e"></param></span>
        ''' <span class="code-SummaryComment"><remarks></remarks></span>
        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

        ''' <span class="code-SummaryComment"><summary></span>
        ''' Loads My.Settings.UrlList comma-delimited string collection
        ''' into the custom collection editor.
        ''' <span class="code-SummaryComment"></summary></span>
        ''' <span class="code-SummaryComment"><remarks></remarks></span>
        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.

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

''' <span class="code-SummaryComment"><summary></span>
''' Sample form with a property grid whose selected object is the custom ListBox editor
''' <span class="code-SummaryComment"></summary></span>
''' <span class="code-SummaryComment"><remarks></remarks></span>
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.

''' <span class="code-SummaryComment"><summary></span>
''' Override whether or not the ListBox control should be resizable
''' <span class="code-SummaryComment"></summary></span>
''' <span class="code-SummaryComment"><value></value></span>
''' <span class="code-SummaryComment"><returns></returns></span>
''' <span class="code-SummaryComment"><remarks></remarks></span>
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.

''' <span class="code-SummaryComment"><summary></span>
''' Override whether or not the ListBox control should be resizable
''' <span class="code-SummaryComment"></summary></span>
''' <span class="code-SummaryComment"><value></value></span>
''' <span class="code-SummaryComment"><returns></returns></span>
''' <span class="code-SummaryComment"><remarks></remarks></span>
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)

About the Author

pstucke
Other
United States United States
An instructional designer by trade, I have been a hobbyist developer since '96.

Comments and Discussions

 
GeneralSuperb PinmemberAlex_MBM21-Sep-08 20:27 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140709.1 | Last Updated 23 Feb 2008
Article Copyright 2008 by pstucke
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid