Is it possible to stop refreshing the ListBox content while scrolling and refreshing only after releasing the left mouse button?
-
See this [answer](https://stackoverflow.com/a/2889763/2902996). TL;DR - use `ListView`, not `ListBox`. – Joel Jun 07 '20 at 09:12
1 Answers
You need to configure the ScrollViewer
of the ListBox
to defer content rendering by setting the attached property ScrollViewer.IsDeferredScrolling
:
<ListBox ScrollViewer.IsDeferredScrolling="True" />
The following example only works when ScrollViewer.CanContentScroll=true
. If ScrollViewer.CanContentScroll=false
, then ScrollViewer.VerticalOffset
would not return the item index, but the item's position offset in pixel. In this case you'd have to find the first visible item based on the item position.
Example to get the first visible item inside the ScrollViewer.ScrollChanged
event, when ScrollViewer.CanContentScroll=true
(default fro ListBox
or ListView
):
<ListBox ScrollViewer.IsDeferredScrolling="True"
ScrollViewer.ScrollChanged="OnScrollChanged" />
private void OnScrollChanged(object sender, ScrollChangedEventArgs e)
{
var listBox = sender as System.Windows.Controls.ListBox;
var firstVisibleItem = listBox.Items[(int) e.VerticalOffset];
}
Note that ScrollViewer.ScrollChanged
is raised on every index change or when IsDeferredScrolling=True
only after the scroll bar is released and scroll completed.

- 1
- 4
- 28
- 44
-
Works, thanks. Is it possible to easily extract the index of the first "visible" element during such scrolling? I used [VerticalOffset](https://learn.microsoft.com/pl-pl/dotnet/api/system.windows.controls.scrollchangedeventargs.verticaloffset?f1url=https%3A%2F%2Fmsdn.microsoft.com%2Fquery%2Fdev15.query%3FappId%3DDev15IDEF1%26l%3DPL-PL%26k%3Dk(System.Windows.Controls.ScrollChangedEventArgs.VerticalOffset);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.5.2);k(DevLang-csharp)%26rd%3Dtrue%26f%3D255%26MSPPError%3D-2147217396&view=netcore-3.1) but now it returns something different. – Jarosław Pietras Jun 07 '20 at 15:35
-
I have updated my answer to show how to get the first visible item. If this doesn't work for you, please let me know. In this case please also tell me about any special configuration of the `ListBox` e.g., disabled virtualization. – BionicCode Jun 07 '20 at 17:53
-
I have a simple balloon for the scrollbar with the index of the first item in the list. When I set `ScrollViewer.IsDeferredScrollingEnabled =" True "` I get the value only when I release the key. I have nothing extra set. Large files will be loaded, so I wanted to turn off content refreshing because it freezes the application terribly and at the same time know which index I'm currently scrolling on. Is this possible for this control? – Jarosław Pietras Jun 09 '20 at 05:47
-
Yes it is possible. But when using deferred scrolling this becomes more complicated. Before we do this we should ensure that build-in performance features are used properly to take full effect. By default `ListBox` or `ListView` use UI virtualization. Item containers are only loaded when needed for rendering. Only a fixed number of containers are loaded i.e. generated at a time. The goal right now is to make sure UI virtualization is used and rendering speed maximized. We want to disable deferred scrolling and still get smooth scrolling! – BionicCode Jun 09 '20 at 09:33
-
Please check: **1)** You didn't set `CanContentScroll` to `false` **2)** You didn't set `IsVirtualizing` to `false` **3)** You use only data binding to add data to the `ItemsSource` **4)** Only one data type is contained in the source collection and only one single `DataTemplate` is defined to layout the item container --- If any of the points can be answered with false then virtualization will be implicitly disabled. – BionicCode Jun 09 '20 at 09:34
-
More points to consider: **1)** Try to reduce the `DataTemplate` tree by removing every element e.g., `Border` that is not needed. Dig deep into the template tree which is usually composed of other elements. Consider to override each element's `ControlTemplate` to remove not used elements e.g. `Border`. `DataTemplate` should lightweight as possible to enhance rendering performance. – BionicCode Jun 09 '20 at 09:34
-
**2)** Enable container recycling (only possible if you are using a single data type and a single `DataTemplate`). Reuse containers by setting the attached property on the `ItemsControl`: `
`. --- If you did all you should experience a significant performance gain and be able to disable deferred scrolling. The `ScrollChanged` event will now be raised for every index change. You can now use the method from my answer to get the current index while the scrollbar thumb is moving. – BionicCode Jun 09 '20 at 09:35 -
If all this doesn't improve the experience you'd have to dig into the scroll viewer to get access to the `ScrollBar` or `Thumb` in order to manually track the current position and then transform this position into an index. – BionicCode Jun 09 '20 at 09:37