i have a solution where i generate a DataGrid (or multiple instances) based on user criteria.. each grid keeps receiving data as it comes in via ObservableCollection
I also have same issue with my DataGrid and finally I did:
ScrollViewer.CanContentScroll="True"
EnableRowVirtualization="True"
VirtualizingPanel.VirtualizationMode="Standard"
Now everything is working fine in my DataGrid.
You are encountering the differences between physical scrolling and logical scrolling.
As you have discovered, each has its tradeoffs.
Physical scrolling
Physical scrolling (CanContentScroll=false) just goes by pixels, so:
but
Logical scrolling
Logical scrolling (CanContentScroll=true) calculates its scroll viewport and extent by items instead of pixels, so:
The viewport may show a different number of items at different times, meaning the number of items in the viewport as compared to the number of items in the extent varies, causing the scrollbar length to change, and
Scrolling moves from one item to the next and never in between, leading to "jerky" scrolling
but
As long as you're using VirtualizingStackPanel under the hood, it only needs to apply templates and measure and arrange the items that are actually visible at the moment, and
ScrollIntoView is much simpler since it just needs to get the right item index into view
Choosing between them
These are the only two kinds of scrolling provided by WPF. You must choose between them based on the above tradeoffs. Generally logical scrolling is best for medium to large datasets, and physical scrolling is best for small ones.
A trick to speed loading during physical scrolling is to make the physical scrolling better is to wrap your items in a custom Decorator that has a fixed size and sets its child's Visibility to Hidden when it is not visible. This prevents the ApplyTemplate, Measure and Arrange from occuring on the descendant controls of that item until you're ready for it to happen.
A trick to make physical scrolling's ScrollIntoView more reliable is to call it twice: Once immediately and once in a dispatcher callback of DispatcherPriority.ApplicationIdle.
Making logical scroll scrollbar more stable
If all your items are the same height, the number of items visible in the viewport at any time will stay the same, causing the scroll thumb size to stay the same (because the ratio with total number if items doesn't change).
It is also possible to modify the behavior of the ScrollBar itself so the thumb is always calculated to be a fixed size. To do this without any hacky code-behind:
This means copying a lot of template code fom the built-in WPF templates, so it is not a very elegant solution. But the alternative to this is to use hacky code-behind to wait until all the templates are expanded, then find the ScrollBar and just replace the ScrollBar template with the one that uses your custom Track. This code saves two large templates (ListBox, ScrollViewer) at the cost of some very tricky code.
Using a different Panel would be a much larger amount of work: VirtualizingStackPanel is the only Panel that virtualizes, and only it and StackPanel to logical scrolling. Since you are taking advantage of VirtualizingStackPanel's virtualization abilities you would have to re-implement all of these plus all IScrollInfo info function plus your regular Panel functions. I could do something like that but I would allocate several, perhaps many, days to get it right. I recommend you not try it.