Skip to content

Lazy Loading Data with ListBox

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:

https://docs.xojo.com/Resources:3rd_Party_Products