Browse DevX
Sign up for e-mail newsletters from DevX


Gaining Control of the .NET ListBox : Page 2

Although .NET's Windows Forms ListBox control has extended capabilities, it can be problematic to do some of the simplest things. But by using delegates, you can achieve near-total control.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

At the Mercy of the Class Creator
Suppose you're told to use a Person class (created by a coworker) that has four properties: ID (Long), LastName, FirstName, and Status (see Listing 1). The Person object has an overloaded constructor so you can assign all the values when you create the object.

You want to fill a ListBox with Person objects. So you create a Form and drag a ListBox onto it. You want to fill the ListBox when the user clicks a button, so you add a Fill List button to do that (see Figure 1).

VB.NET makes it very easy to display items in a ListBox, because you can set the ListBox's DataSource property to any collection that implements the IList interface (although you can still write a loop to add items to the ListBox if you wish). The ArrayList class implements the IList interface, so, you create an ArrayList member variable for the form, and fill it with Person objects during the Form_Load event.

' define an ArrayList at class level Private people As New ArrayList() Private Sub Form1_Load(ByVal sender As _ System.Object, ByVal e As System.EventArgs) _ Handles MyBase.Load Dim p As Person ListBox1.DisplayMember = "ToString" ListBox1.ValueMember = "ID" p = New Person(1, "Twain", "Mark", "MT") people.Add(p) p = New Person(2, "Austen", "Jane", "JA") people.Add(p) p = New Person(2, "Fowles", "John", "JF") people.Add(p) End Sub

Now when a user clicks the Fill List button, by setting the ListBox's DataSource property to the people ArrayList, the ListBox displays the names automatically.

Private Sub Button1_Click(ByVal sender As _ System.Object, ByVal e As System.EventArgs) _ Handles Button1.Click ListBox1.Sorted = True ListBox1.DataSource = people End Sub

Unfortunately, you find that the class creator didn't override the ToString implementation or provide any additional LastFirst method to provide the strings for the ListBox. So the result is that the ListBox calls the default Person.ToString implementation, which returns the class name, ListBoxExample.Person. The result looks like Figure 2.

OK, no problem. What about using the DisplayMember property? Add the following line to the end of the Button1_Click method.

ListBox1.DisplayMember = "LastName"

Run the project again. This time, the result is a little closer (see Figure 3).

Now you're stuck. The only good solution is to get the class creator to add a LastFirst property; otherwise, you'll have to go to a good deal of trouble to get the list to display both names. Pretend the class creator actually helps you out, and adds a LastFirst property to the Person class.

Public ReadOnly Property LastFirst() As String Get Return p.LastName & " " & p.FirstName End Get End Property

Now you can change the ListBox.DisplayMember property, and the form works as expected (see Figure 4).

ListBox1.DisplayMember = LastFirst

Just as you get the form working, your manager walks in, and says, "Oh, by the way, the client wants to be able to change the list from Last/First to First/Last—both sorted, of course." Now what? You could get the class creator to change the class again, but surely there's a better solution.

You could inherit the class, and add a FirstLast method, but then you'd have two classes to maintain. You could create a new wrapper class that exposes the people ArrayList collection, and that also implements FirstLast and LastFirst properties. But what if the clients change their minds again? You'd have to keep adding methods to the class, or bite the bullet and beg the class creator for yet more changes. Also, do you really want to create a wrapper for every class you want to display in a ListBox?

This is when you begin to miss the classic VB ListBox's ItemData property. If you could assign the Person.ID as the ItemData value, you could concatenate the names yourself, add them to the ListBox, and then look up the Person based on the ID when a user selects an item from the ListBox. But ItemData is gone.

You could inherit the ListBox class and add an ItemData property. But if you just add an ItemData property, the property is isolated from the ListBox Items collection; if the collection changes, you will have to intercept the change messages and alter the ItemData values appropriately. Unfortunately, that's a lot more work than you would normally want to do. All these are onerous choices. Things would be a lot easier if you could just control the Person class.

Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



Thanks for your registration, follow us on our social networks to keep up-to-date