I don't know that that charactization is accurate.
At a minimum you needed to implement an IList whos indexer creates the actual data when called. You would then set that IList on an ItemSource.
If you could not provide data synchronously you could return an observable object and raised property changed events when the data was available
I don't know if there were constraints that that unworkable for your scenario but my memory was data virtualization not being that much more code than WinForms.
Visual Studio introduced an interface that formalized fetching a page at a time so you did less bookkeeping when mapping indices to items for SQL like scenarios but I don't know if controls had better performance using that interface
This seems like it would work, but it actually didn't. One issue was that WPF uses rows with dynamic row heights instead of fixed row heights like GDI or WinForms. This forced it calculate everything it needed for the layout of each row to compute the total height, scroll position, etc...
Like I said, this got changed when Visual Studio was rewritten to use WPF, and it "works now", but the default behaviour is still the slow path, not the fast path.
At a minimum you needed to implement an IList whos indexer creates the actual data when called. You would then set that IList on an ItemSource.
If you could not provide data synchronously you could return an observable object and raised property changed events when the data was available
I don't know if there were constraints that that unworkable for your scenario but my memory was data virtualization not being that much more code than WinForms.
Visual Studio introduced an interface that formalized fetching a page at a time so you did less bookkeeping when mapping indices to items for SQL like scenarios but I don't know if controls had better performance using that interface