The ListBox is a great control for showing users lists of data, even data with lots and lots of rows. But the ListBox, being a UI control, is not meant to also be a container for hundreds of thousands of rows of data. It can take noticeable amount of time to to populate and you end up with your data being duplicated because it exists in both the ListBox and the original source (file, database or other data structure).
One way to avoid this problem is to not actually load all the data at once. This is often a great idea because the user can’t actually see all the data at once anyway. So why not only load the data they can actually see?
One way to do this is to use a ScrollBar to track the data the user wants to see and then to only load that data into the ListBox.
To demonstrate this, start by creating a simple class as a container for data. The class structure is like this:
Class ListData Property Num As Integer Property Value As Double Property Desc As String End Class
On Window1, add a property that is an array of this class:
Data() As ListData
Now on Window1, add two Buttons, a Vertical Scroll Bar and a ListBox. Align the ScrollBar so that it is to the right of the ListBox and the same height and change its Allow Live Scrolling property to True (ON). Change the ListBox to have 3 columns using the Column Count property in the Inspector. In the Open event of the Window add 1 million elements to the Data array:
For i As Integer = 1 To 1000000 Var d As New ListData d.Num = i d.Value = Rnd() d.Desc = "Testing" Data.AddRow(d) Next
In the Action event of the 1st Button, add this code to load the entire 1 million element array into the ListBox:
Listbox1.HasVerticalScrollbar = True ScrollBar1.Visible = False Listbox1.RemoveAllRows For i As Integer = 0 To Data.LastRowIndex Listbox1.AddRow(Data(i).Num.ToString, Data(i).Value.ToString, Data(i).Desc) Next
Pretty standard stuff. Now in the 2nd Button’s Action event add this code, which populates the ListBox only with the first 50 rows:
Listbox1.RemoveAllRows Listbox1.HasVerticalScrollbar = False ScrollBar1.Visible = True ScrollBar1.MinimumValue = 0 ScrollBar1.MaximumValue = Data.LastRowIndex ScrollBar1.Value = 0 For i As Integer = 0 To 50 Listbox1.AddRow(Data(i).Num.ToString, Data(i).Value.ToString, Data(i).Desc) Next
Lastly add the ValueChanged event to the ScrollBar with this code, which fetches 50 rows after the value of the ScrollBar:
Listbox1.RemoveAllRows For i As Integer = Me.Value To Me.Value + 50 If i <= Data.LastRowIndex Then Listbox1.AddRow(Data(i).Num.ToString, Data(i).Value.ToString, Data(i).Desc) End If Next
Now go ahead and run the project. Click the first button to see how long it takes to populate the ListBox. It took my computer about 11 seconds. You can scroll around at a reasonable speed, although it’s a bit unwieldy with that many rows. Another thing to note is that this uses about 750MB of RAM.
Now click the second button that does the lazy loading. It will show the first bunch of rows instantly. Use the scrollbar to display other rows and you’ll see they are also displayed instantly even thought they are not technically in the ListBox. This also uses only about 110MB of RAM.
Now this is just a quick example (download here) and doesn’t handle every situation, but you can certainly expand on it as needed. If you’d rather not create this yourself, another option is to try 3rd party ListBox or DataView controls which have this built-in. You can find some on our 3rd Party Product page: