I am trying to make an "infinite scrollable calendar". My idea is to generate the requested portion of the calendar on the fly, so as ItemsSource i use a custom class WeekList that implements IList. Upon initialization i calculate an interval around the current date (5 years radius at the moment, later i want to go as far as IntMax allows). From there on out i just calculate the requested weeks by the index.
I have implemented the Item Method to only create data on demand and GetEnumerator as follows:
Public Iterator Function GetEnumerator1() As IEnumerator Implements IEnumerable.GetEnumerator
For i As Integer = 1 To _Count
Yield Item(i)
Next
End Function
While trying to understand what Yield does i was under the impression that this will only calculate Items as needed.
Functionally the calendar works perfect, but upon binding a WeekList "Dates" to a ListBox.ItemsSource, all weeks are generated at once.
EDIT: I have isolated the problem in a complete code example:
My MainWindow Code-Behind:
Class MainWindow
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Me.DataContext = Me
End Sub
Private _TestList As VirtList
Public ReadOnly Property TestList As VirtList
Get
If _TestList Is Nothing Then
_TestList = New VirtList(10000)
End If
Return _TestList
End Get
End Property
End Class
And the class to procedurally generate a list of given size:
Public Class VirtList
Implements IEnumerable
Private _Count As Integer
Public Sub New(size As Integer)
_Count = size
End Sub
Private _Items As New Dictionary(Of Integer, String)
Private Function Item(i As Integer) As String
If Not _Items.ContainsKey(i) Then
_Items(i) = "I am Item Number " & i
Debug.Print("Current Cache Size: {0}", _Items.Count)
End If
Return _Items(i)
End Function
Public Iterator Function GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
For i As Integer = 0 To _Count
Yield Item(i)
Next
End Function
End Class
In my MainWindow.xaml
<ListBox
VirtualizingPanel.IsVirtualizing="True"
ItemsSource="{Binding TestList}"/>
The whole list (all 10.000 items) is generated at the time of binding. How can I achieve that only the "visible portion" is enumerated? I was under the impression that that is exactly what the ListBox does with Virtualization so I suspect my incomprehension of the GetEnumerator/Yield as the culprit.