Reputation: 4435
I'm trying to lazy load thumbnail image for each item in a Listbox asynchronously.
<Image Source="{Binding Path=Thumbnail, TargetNullValue={StaticResource DefaultImage}}"/>
Since Listbox is virtualized Thumbnail property's getter is called only when an item is in display port or near to that.
public BitmapSource Thumbnail
{
get
{
TriggerLoad();
return _thumbnail;
}
}
I am awaiting on expensive operation that loads Thumbail in TriggerLoad function, but UI isn't very responsive especially when you try to scroll fastly through large list of items.
private async void TriggerLoad()
{
if (!LoadTriggered)
{
LoadTriggered = true;
var cacheItem = _cache[key] as CacheItem;
if (cacheItem != null)
await LoadBitmapFromCache(cacheItem); // returns a Task
else
await LoadBitmapFromService(Id); // returns a Task
}
}
Found a similar questions here but it is not about loading items to a Listbox. Is there any better approach to lazy load only some part of the data you bind to Listbox?
Edit: I tried PriorityBinding and IsAsync option and scrolling is not better than my current solution.
Upvotes: 2
Views: 3255
Reputation: 88
Sounds like although your UI is virtualizing it isn't loading newer images quickly enough to keep up with your user's scrolling. Try setting VirtualizationMode to Recycling and set a longer CacheLength. Like so:
<ListBox
VirtualizingPanel.IsContainerVirtualizable="True"
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.VirtualizationMode="Recycling"
VirtualizingPanel.CacheLengthUnit="Page"
VirtualizingPanel.CacheLength="2,2"
etc.../>
Increasing CacheLength from "1,1" to "2,2" means two "pages" (or view-ports worth of items) will be loaded into memory before and after the page displayed to the user. Your app will consume that much more memory but users will be able to scroll further, faster, before running into images that aren't loaded.
Upvotes: 5