sbaeumlisberger / VirtualizingWrapPanel

Implementation of a comprehensive VirtualisingWrapPanel for WPF
MIT License
254 stars 35 forks source link

VirtualizingWrapPanel does not shrink when items are changed #51

Closed DSPaul closed 9 months ago

DSPaul commented 9 months ago

I am testing out the new 2.0 version and it works great overall. I did however run into an issue where the container doesn't shrink when items are removed from the collection or if the collection changes to have less items such as when a filter is applied. Instead you can scroll right past the items into the void until you reach the bottom of the original container size.

Here is a minimal repo that showcases the problem: just press any key to generate a new collection of a random size and you will see it doesn't shrink unlike a regular listview for example which does shrink. https://github.com/DSPaul/ContainerNotResizing

Version Info Package Version 2.0.0 .NET Version: .NET 7 OS Version: Windows 10 22H2

sbaeumlisberger commented 9 months ago

Thanks for reporting. I will have a look.

sbaeumlisberger commented 9 months ago

I have released a new nuget package with some fixes regarding item collection changes: https://www.nuget.org/packages/VirtualizingWrapPanel/2.0.3

When AllowDifferentSizedItems is true and not ItemSizeProvider is set the scroll offset is now set to zero when the item collection is cleared/replaced. Changes to individual items to not reset the scoll offset and should be handled without any problems. In all my test cases the panel has the correct extend now . Let me know if you find any edge-case which does not work.

If you items all have the same size I would recommend to remove the AllowDifferentSizedItems property. In this case the scroll offset is never reset and you have the same behavior as with the default ListView.

DSPaul commented 9 months ago

I tried it out and it works great when AllowDifferentSizedItems is set to true but it crashes when I remove the AllowDifferentSizedItems property. I updated the minimal repo to replicate it.

Call stack to save you some time:

System.InvalidOperationException: Nullable object must have a value.
   at System.Nullable`1.get_Value()
   at WpfToolkit.Controls.VirtualizingWrapPanel.CalculateExtentForSameSizedItems()
   at WpfToolkit.Controls.VirtualizingWrapPanel.UpdateExtent()
   at WpfToolkit.Controls.VirtualizingWrapPanel.MeasureOverride(Size availableSize)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at MS.Internal.Helper.MeasureElementWithSingleChild(UIElement element, Size constraint)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at MS.Internal.Helper.MeasureElementWithSingleChild(UIElement element, Size constraint)
   at System.Windows.Controls.ScrollContentPresenter.MeasureOverride(Size constraint)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at System.Windows.Controls.Grid.MeasureCell(Int32 cell, Boolean forceInfinityV)
   at System.Windows.Controls.Grid.MeasureCellsGroup(Int32 cellsHead, Size referenceSize, Boolean ignoreDesiredSizeU, Boolean forceInfinityV, Boolean& hasDesiredSizeUChanged)
   at System.Windows.Controls.Grid.MeasureOverride(Size constraint)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at System.Windows.Controls.ScrollViewer.MeasureOverride(Size constraint)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at System.Windows.Controls.Border.MeasureOverride(Size constraint)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at System.Windows.Controls.Control.MeasureOverride(Size constraint)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at MS.Internal.Helper.MeasureElementWithSingleChild(UIElement element, Size constraint)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at System.Windows.Controls.Border.MeasureOverride(Size constraint)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at System.Windows.Controls.Control.MeasureOverride(Size constraint)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at MS.Internal.Helper.MeasureElementWithSingleChild(UIElement element, Size constraint)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at System.Windows.ContextLayoutManager.UpdateLayout()
   at System.Windows.Interop.HwndSource.SetLayoutSize()
   at System.Windows.Interop.HwndSource.set_RootVisualInternal(Visual value)
   at System.Windows.Window.SetRootVisualAndUpdateSTC()
   at System.Windows.Window.SetupInitialState(Double requestedTop, Double requestedLeft, Double requestedWidth, Double requestedHeight)
   at System.Windows.Window.CreateSourceWindow(Boolean duringShow)
   at System.Windows.Window.ShowHelper(Object booleanBox)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
sbaeumlisberger commented 9 months ago

fixed: https://www.nuget.org/packages/VirtualizingWrapPanel/2.0.4

DSPaul commented 9 months ago

Seems to work great, thanks a lot!