diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/VirtualizingStackPanel.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/VirtualizingStackPanel.cs index d85ce7355cd..02d18590589 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/VirtualizingStackPanel.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/VirtualizingStackPanel.cs @@ -931,16 +931,19 @@ private void OnAnchorOperation(bool isAnchorOperationPending) // situations where the viewport size has changed) if (!success) { + double computedOffset, maxOffset; if (isHorizontal) { - success = DoubleUtil.GreaterThanOrClose(_scrollData._computedOffset.X, - _scrollData._extent.Width - _scrollData._viewport.Width); + computedOffset = _scrollData._computedOffset.X; + maxOffset = _scrollData._extent.Width - _scrollData._viewport.Width; } else { - success = DoubleUtil.GreaterThanOrClose(_scrollData._computedOffset.Y, - _scrollData._extent.Height - _scrollData._viewport.Height); + computedOffset = _scrollData._computedOffset.Y; + maxOffset = _scrollData._extent.Height - _scrollData._viewport.Height; } + success = LayoutDoubleUtil.LessThan(maxOffset, computedOffset) || + LayoutDoubleUtil.AreClose(maxOffset, computedOffset); } } } @@ -973,7 +976,7 @@ private void OnAnchorOperation(bool isAnchorOperationPending) else { bool remeasure = false; - double actualOffset, expectedOffset; + double actualOffset, expectedOffset, maxOffset; if (isHorizontal) { @@ -981,13 +984,14 @@ private void OnAnchorOperation(bool isAnchorOperationPending) actualOffset = _scrollData._computedOffset.X + actualDistanceBetweenViewports; expectedOffset = _scrollData._computedOffset.X + _scrollData._expectedDistanceBetweenViewports; + maxOffset = _scrollData._extent.Width - _scrollData._viewport.Width; - if (DoubleUtil.LessThan(expectedOffset, 0) || DoubleUtil.GreaterThan(expectedOffset, _scrollData._extent.Width - _scrollData._viewport.Width)) + if (LayoutDoubleUtil.LessThan(expectedOffset, 0) || LayoutDoubleUtil.LessThan(maxOffset, expectedOffset)) { // the condition can fail due to estimated sizes in subtrees that contribute // to FindScrollOffset(_scrollData._firstContainerInViewport) but not to // _scrollData._extent. If that happens, remeasure. - if (DoubleUtil.AreClose(actualOffset, 0) || DoubleUtil.AreClose(actualOffset, _scrollData._extent.Width - _scrollData._viewport.Width)) + if (LayoutDoubleUtil.AreClose(actualOffset, 0) || LayoutDoubleUtil.AreClose(actualOffset, maxOffset)) { _scrollData._computedOffset.X = actualOffset; _scrollData._offset.X = actualOffset; @@ -1010,13 +1014,14 @@ private void OnAnchorOperation(bool isAnchorOperationPending) actualOffset = _scrollData._computedOffset.Y + actualDistanceBetweenViewports; expectedOffset = _scrollData._computedOffset.Y + _scrollData._expectedDistanceBetweenViewports; + maxOffset = _scrollData._extent.Height - _scrollData._viewport.Height; - if (DoubleUtil.LessThan(expectedOffset, 0) || DoubleUtil.GreaterThan(expectedOffset, _scrollData._extent.Height - _scrollData._viewport.Height)) + if (LayoutDoubleUtil.LessThan(expectedOffset, 0) || LayoutDoubleUtil.LessThan(maxOffset, expectedOffset)) { // the condition can fail due to estimated sizes in subtrees that contribute // to FindScrollOffset(_scrollData._firstContainerInViewport) but not to // _scrollData._extent. If that happens, remeasure. - if (DoubleUtil.AreClose(actualOffset, 0) || DoubleUtil.AreClose(actualOffset, _scrollData._extent.Height - _scrollData._viewport.Height)) + if (LayoutDoubleUtil.AreClose(actualOffset, 0) || LayoutDoubleUtil.AreClose(actualOffset, maxOffset)) { _scrollData._computedOffset.Y = actualOffset; _scrollData._offset.Y = actualOffset; @@ -2824,11 +2829,11 @@ private Size MeasureOverrideImpl(Size constraint, ref scrollGeneration); if (ItemsChangedDuringMeasure) - { - // if the Items collection changed, our state is now invalid. Start over. - remeasure = true; - goto EscapeMeasure; - } + { + // if the Items collection changed, our state is now invalid. Start over. + remeasure = true; + goto EscapeMeasure; + } } } @@ -2873,11 +2878,11 @@ private Size MeasureOverrideImpl(Size constraint, ref scrollGeneration); if (ItemsChangedDuringMeasure) - { - // if the Items collection changed, our state is now invalid. Start over. - remeasure = true; - goto EscapeMeasure; - } + { + // if the Items collection changed, our state is now invalid. Start over. + remeasure = true; + goto EscapeMeasure; + } } } @@ -12321,6 +12326,12 @@ private void IdentifyTrace(ItemsControl ic, VirtualizingStackPanel vsp) "ScrollUnit:", VirtualizingPanel.GetScrollUnit(ic), "CacheLen:", VirtualizingPanel.GetCacheLength(ic), VirtualizingPanel.GetCacheLengthUnit(ic)); + DpiScale dpiScale = vsp.GetDpi(); + AddTrace(null, ScrollTraceOp.ID, _nullInfo, + "DPIScale:", dpiScale.DpiScaleX, dpiScale.DpiScaleY, + "UseLayoutRounding:", vsp.UseLayoutRounding, + "Rounding Quantum:", 1.0/dpiScale.DpiScaleY); + AddTrace(null, ScrollTraceOp.ID, _nullInfo, "CanContentScroll:", ScrollViewer.GetCanContentScroll(ic), "IsDeferredScrolling:", ScrollViewer.GetIsDeferredScrollingEnabled(ic),