Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stackoverflow exception in VirtualizingWrapPanel.MeasureOverride #65

Closed
GwenhaelCoray opened this issue Oct 1, 2024 · 3 comments
Closed
Assignees
Labels
bug Something isn't working

Comments

@GwenhaelCoray
Copy link

I have a case where I got a stackoverflow exception when scrolling down.
The exception is raised in VirtualizingWrapPanel.MeasureOverride call stack.

After investigation, I found out that in some cases, this line may be always true:

line 167: GetY(ScrollOffset) + GetHeight(ViewportSize) > GetHeight(Extent)

This leads to endlessly and recursively call MeasureOverride:

if (ItemsOwner is not IHierarchicalVirtualizationAndScrollInfo
    && GetY(ScrollOffset) != 0
    && GetY(ScrollOffset) + GetHeight(ViewportSize) > GetHeight(Extent))
{
    ScrollOffset = CreatePoint(GetX(ScrollOffset), Math.Max(0, GetHeight(Extent) - GetHeight(ViewportSize)));
    ScrollOwner?.InvalidateScrollInfo();
    return MeasureOverride(availableSize); // repeat measure with correct ScrollOffset
}

In my case, when crashing, I had:

  • GetY(ScrollOffset) = 1 231.52314426031
  • GetHeight(ViewportSize) = 639.4
  • GetHeight(ViewPortSize) = 1 870.92314426031

With these numbers, the comparison should return false, but it doesn't on my machine, because of double imprecision.
I would suggest to replace:
GetY(ScrollOffset) + GetHeight(ViewportSize) > GetHeight(Extent)
by something like:
GetY(ScrollOffset) + GetHeight(ViewportSize) - GetHeight(Extent) > SOME_EPSILON

Below is the xaml I am using. Note that the crash happens with a specific set of data (I mean, depending on the set of data the VirtualizingItemsControl is populated with, it may crash or not):
(Setting AllowDifferentSizedItems to True or False doesn't change the bug.)

<controls1:VirtualizingItemsControl Grid.Row="1"
                                    BorderThickness="0"
                                    ItemsSource="{Binding PuImagesInCategory, Mode=TwoWay}"
                                    ScrollViewer.HorizontalScrollBarVisibility="Disabled">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <controls1:VirtualizingWrapPanel SpacingMode="Uniform"
                                             AllowDifferentSizedItems="True" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <Button Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.SelectTileCommand}"
                        CommandParameter="{Binding Path='.'}"
                        MaxWidth="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=ActualWidth, Converter={StaticResource ResourceKey=LibraryChartsItemsMaxWidthConverter}}"
                        Background="White"
                        BorderBrush="Transparent"
                        ToolTipService.ShowOnDisabled="True"
                        ToolTipService.Placement="Left"
                        ToolTipService.HorizontalOffset="-100"
                        Margin="5,0,5,10">
                    <Button.Content>
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto" />
                                <RowDefinition Height="Auto" />
                            </Grid.RowDefinitions>
                            <Image Grid.Row="0"
                                   Source="{Binding ImagePath, Mode=OneWay}" />

                            <Grid Grid.Row="0"
                                  Visibility="{Binding IsEnabled, Converter={StaticResource ResourceKey=BoolToVisibilityConverter}, ConverterParameter={x:Static converters:BoolToVisibilityConverter.INVERTED}}">
                                <Rectangle Fill="White"
                                           Opacity="0.5" />
                                <DockPanel Grid.Row="0"
                                           Margin="5"
                                           HorizontalAlignment="Right"
                                           VerticalAlignment="Top">
                                    <Image Width="24"
                                           Height="24"
                                           Source="{Binding LockImage}">
                                        <Image.ToolTip>
                                            <TextBlock Text="{Binding Tooltip}" />
                                        </Image.ToolTip>
                                    </Image>
                                </DockPanel>
                            </Grid>

                            <Viewbox Grid.Row="1"
                                     StretchDirection="DownOnly">
                                <TextBlock Text="{Binding PuImage.Description}"
                                           HorizontalAlignment="Center" />
                            </Viewbox>
                        </Grid>
                    </Button.Content>
                    <Button.ToolTip>
                        <ToolTip Style="{StaticResource TooltipNoMargin}">
                            <Border Background="White">
                                <Grid>
                                    <Image Width="960"
                                           Height="540"
                                           Source="{Binding ImagePath, Mode=OneWay}" />
                                    <DockPanel Margin="5"
                                               Visibility="{Binding IsEnabled, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter={x:Static converters:BoolToVisibilityConverter.INVERTED}}"
                                               HorizontalAlignment="Right"
                                               VerticalAlignment="Top">
                                        <Image Width="24"
                                               Height="24"
                                               Source="{Binding LockImage}" />
                                    </DockPanel>
                                </Grid>
                            </Border>
                        </ToolTip>
                    </Button.ToolTip>
                </Button>
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</controls1:VirtualizingItemsControl>

Version Info
Package Version: 2.0.10
.NET Version: .NET Framework 4.6.2
OS Version: Windows 11 Business Build 22631.4249

@sbaeumlisberger sbaeumlisberger added the bug Something isn't working label Oct 1, 2024
@sbaeumlisberger sbaeumlisberger self-assigned this Oct 1, 2024
@sbaeumlisberger
Copy link
Owner

sbaeumlisberger commented Oct 1, 2024

I have added a small tolerance and published a new nuget package. Let me know if that solves your issue.

@GwenhaelCoray
Copy link
Author

Thanks for the really quick update!

I confirm that this new package solves my issue.

I don't know how much this tolerance is considered big or not in the context, but if you would prefer to lower it, setting 1e-6 instead of 1e-3 should also work. The bug happens here because of the ~15 digits values that are at the bounds of the double precision.

@sbaeumlisberger
Copy link
Owner

Glad to hear the problem has been solved. I don't think a 0.001 pixel tolerance will ever be visible. So it should be fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants