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

Flexible List Control

, 7 Feb 2013
Rate this:
Please Sign up or sign in to vote.
Building a list control that allows anything to be added to it.
333864/screenshot_new.png

Introduction

In a normal listbox or listview control, you are bound with a lot of restrictions. You cannot add images or icons properly, cannot provide your own highlighting colors, or placement of text, and a most wanted feature is that you cannot add multiline text to the default list controls.

Today I will show you how to build a list control that shows list items just the way you want them to be. They can be multiline, or have images in them, various sizes of texts or background colors, complex placements of items in it, etc. Its all up to you how you design it. Complete flexibility!

Building The List Control

We're going to be using the default available controls to make this dream come true. I will show you how to make a list control, what you do with that list control is totally up to your imagination. So starting off we're going to make a list control having a FlowLayoutPanel control in it only.

Create a new project in your Visual Studio. Add a Usercontrol to your project and name it as ListControl.

On the ListControl place a FlowLayoutPanel and name it flpListBox.

Provide the following properties to the flpListBox:

  • AutoScroll = True
  • AutoSize = False
  • Dock = Fill
  • FlowDirection = TopDown
  • Margin = 0, 0, 0, 0
  • WrapContents = False

And provide following properties to the ListControl usercontrol:

  • BorderStyle = FixedSingle
  • Padding = 0, 0, 0, 0

Now we need to add code to the ListControl to handle the adding, removing, counting and clearing functions, just like any other list control. Therefore we will add four functions Add, Remove, Clear, and Count.

    Public Sub Add(c As Control)

    End Sub

    Public Sub Remove(name As String)

    End Sub

    Public Sub Clear()

    End Sub

    Public ReadOnly Property Count() As Integer
        Get
            Return flpListBox.Controls.Count
        End Get
    End Property 

Let's add the code for the Add sub. As you can see in the definition the Add sub is accepting a control as a listitem, not text or any other kind of object. This is because we're going to create a flexible list control where any type of independent control can be added to it and the our ListControl will move it around just like any other list control.

    Public Sub Add(c As Control)
        flpListBox.Controls.Add(c)
    End Sub 

That was a simple code. It only adds your control (i.e. list item) to the flow layout panel. The flow layout panel has been told to add all the controls inside it from Top to Down manner. So all controls will be added vertically. You keep on adding controls and it will keep on appending it to the list of controls added to the flow layout panel. Now lets code for Remove and Clear subs.

    Public Sub Remove(name As String)
        Dim c As Control = flpListBox.Controls(Name)
        flpListBox.Controls.Remove(c)
        c.Dispose()
    End Sub
    Public Sub Clear()
        Do
            If flpListBox.Controls.Count = 0 Then Exit Do
            Dim c As Control = flpListBox.Controls(0)
            flpListBox.Controls.Remove(c)
            c.Dispose()
        Loop
    End Sub 

I want to discuss the Clear sub first here. In order to remove all the controls from your list control, there is a very easy way of doing it. Simply call the flpListBox.Controls.Clear and it will remove all the controls. But these controls still remain in the memory. It is up to your coding method or according to your programming needs, but I prefer my list control to dispose off the control as soon as I remove them from the list control. In order to do this first we need to grab the control from the flow layout panel, remove it from its control list and then finally dispose it off.

In the Clear sub the above process of disposing is repeated until all the controls from the list have been removed. But in Remove sub of course we only need to do this process once just for the control user has asked to remove.

Using The Control

Our ListControl is complete. You can trial run this control at this stage. Place ListControl on a new Form and add the following code to the Load event.

    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        For i as Integer = 1 To 20
            Dim btn As New Button
            With btn
                .Name = "b" & i
                .Text = "Button " & i
                .Height = 25
                .Margin = New Padding(0)
            End With
            ListControl1.Add(btn)
        Next
    End Sub 

The above code will add twenty buttons to the ListControl. For each of those button you can hook a click event by AddHandler in your form's code.

333864/scr1.png

The reason why I have set the Margin property of the buttons to zero is to reduce the line gap between each row in our list control.

Our ListControl is ready. It will automatically show the scroll bar whenever the items exceed the height of the list control. You can also scroll with mouse wheel. At the moment it does not handle resize events, in case you may want to resize your control to fit the width of ListControl.

Managing Size and Resize Event

By here our list control is complete. You may want to add uneven sized controls in it, its entirely up to you. You could even make something fancy like this:

333864/scr2.png

Because it is a flow layout panel control it allows you to add anything to it and it will manage its placement by itself. But only placement, not the sizes. Size is defined by you.

In order to build a proper looking list control we need to automate the sizes as well here. For this the following code need to be added:

    Private Sub SetupAnchors()
        If flpListBox.Controls.Count > 0 Then
            For i = 0 To flpListBox.Controls.Count - 1
                Dim c As Control = flpListBox.Controls(i)
                If i = 0 Then
                    ' Its the first control, all subsequent controls follow 
                    ' the anchor behavior of this control.
                    c.Anchor = AnchorStyles.Left + AnchorStyles.Top
                    c.Width = flpListBox.Width - SystemInformation.VerticalScrollBarWidth
                Else
                    ' It is not the first control. Set its anchor to
                    ' copy the width of the first control in the list.
                    c.Anchor = AnchorStyles.Left + AnchorStyles.Right
                End If
            Next
        End If
    End Sub
    
    Private Sub flpListBox_Layout(sender As Object, e As System.Windows.Forms.LayoutEventArgs) Handles flpListBox.Layout
        If flpListBox.Controls.Count Then
            flpListBox.Controls(0).Width = flpListBox.Size.Width - SystemInformation.VerticalScrollBarWidth
        End If
    End Sub 

We have added a subroutine called SetupAnchors. In a flow layout panel, if you set the anchor of a control to Left + Right, all controls inside it can have their own heights, but for widths they all adopt the width of the first control in the list. Whatever the width is of the first control, other controls will automatically follow. But the first control cannot have a Left + Right anchor. You have to manually define the width of the first control. This is how flow layout panel behaves by default.

So in above I have assigned a Top+Left anchor for the very first control in the list and all the other controls have Left+Right anchor. As a result all controls will follow the width of the first control. So whenever the ListControl is resized, it will resize the first control only (see flpListBox.Resize event) and other controls will automatically copy its width.

Accordingly amend the Add and Remove subs to call the SetupAnchors sub from them whenever a control is added or removed from the list.

    Public Sub Add(c As Control)
        flpListBox.Controls.Add(c)
        SetupAnchors()
    End Sub
    Public Sub Remove(name As String)
        Dim c As Control = flpListBox.Controls(Name)
        flpListBox.Controls.Remove(c)
        c.Dispose()
        SetupAnchors()
    End Sub 

Taking It To Next Level

Since ListControl allows any kind of control to be added to it and it will handle it like any other list control item, you can even make custom user controls and add it to ListControl. In the first screenshot at the top of the page, I have created a custom usercontrol which manages its own highlighting and colors, text placement, icon and stars, etc. All ListControl does is add it to its list.

To achieve this lets make some improvements in the code that I've explained above. I've made some slight changes... now you don't have to create a new control to add to the list, the ListControl will do that for you. Its all according to your needs, really! You can turn, twist, twirl etc. with this control according to your application needs. You may embed everything inside the ListControl or manually create a new control and attach it.

I've built a list item control, called ListControlItem, that has the following properties: song name, artist name, album name, duration of song, image of the song or album, rating for the song.

Note: Since this article is only to demonstrate the possibilities of ListControl, I will not be explaining the code of ListControlItem. To see the code of ListControlItem download the sample project and have a look.

So I've changed the Add procedure like this:

    Public Sub Add(Song As String, Artist As String, Album As String, Duration As String, SongImage As Image, Rating As Integer)
        Dim c As New ListControlItem
        With c
            ' Assign an auto generated name
            .Name = "item" & flpListBox.Controls.Count + 1
            .Margin = New Padding(0)
            ' set properties
            .Song = Song
            .Artist = Artist
            .Album = Album
            .Duration = Duration
            .Image = SongImage
            .Rating = Rating
        End With
        ' To check when the selection is changed
        AddHandler c.SelectionChanged, AddressOf SelectionChanged
        '
        flpListBox.Controls.Add(c)
        SetupAnchors()
    End Sub 

And the Remove procedure has been amended as:

    Public Sub Remove(name As String)
        ' grab which control is being removed
        Dim c As ListControlItem = flpListBox.Controls(name)
        flpListBox.Controls.Remove(c)
        ' remove the event hook
        RemoveHandler c.SelectionChanged, AddressOf SelectionChanged
        ' now dispose off properly
        c.Dispose()
        SetupAnchors()
    End Sub 

As I have added a hook to an event from ListControlItem to monitor when selection is changed, therefore when disposing the control it is an efficient programming practice to remove the hook as well.

And I've added another subroutine to ensure that only one list item is selected at a time:

    Dim mLastSelected As ListControlItem = Nothing
    Private Sub SelectionChanged(sender As Object)
        If mLastSelected IsNot Nothing Then
            mLastSelected.Selected = False
        End If
        mLastSelected = sender
    End Sub 

That's it!

Now when using the modified ListControl you don't need to create or dispose controls. All will be handled by itself. You can add items to the list this way from your Windows Form:

ListControl1.Add("Party Rock Anthem (feat. Lauren Bennett & GoonRock)", "LMFAO", "For DJs Only [2011]", "4:23", ImageList1.Images(7), 5) 

See Example Code

Our ListControl is finally complete. It may not be as memory efficient as the default listview or listbox control or any other third party listview control, but it works absolutely well and provides the flexibility that other list controls don't.

This little sample project is built to demonstrate the ListControl being used for a media player type application. It depends what type of application you're building. How the list item will look like is entirely up to you as you will be designing the list item, ListControl will only manage it in a list form.

License

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

About the Author

Faraz Azhar, Dubai

United Arab Emirates United Arab Emirates
No Biography provided

Comments and Discussions

 
GeneralMy vote of 5 Pinmemberrspercy6518-Mar-12 5:48 
GeneralMy vote of 5 PinmemberJαved9-Mar-12 3:19 
GeneralMy vote of 5 PinmemberProEnggSoft7-Mar-12 20:50 
QuestionHow to make this ListControlItem To collection PinmemberSunLucDong6-Mar-12 22:22 
can u make this ListControl can add ListControlItem to Collection
so we can use it at Design time Like ListView Column Collection
AnswerRe: How to make this ListControlItem To collection PinmemberFaraz Azhar from Karachi19-Mar-12 20:09 
GeneralMy vote of 5 PinmemberPete Goodsall27-Feb-12 5:50 
GeneralMy vote of 5 PinmemberForogar24-Feb-12 11:53 
GeneralMy vote of 5 PinmemberZlosk24-Feb-12 11:11 
GeneralMy vote of 5 Pinmemberus471123-Feb-12 8:50 

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
Web02 | 2.8.140709.1 | Last Updated 7 Feb 2013
Article Copyright 2012 by Faraz Azhar, Dubai
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid