dotnet / wpf

WPF is a .NET Core UI framework for building Windows desktop applications.
MIT License
7.02k stars 1.16k forks source link

Virtualized ListBox doesn't layout its items correctly if they have right "aligned" controls #8824

Open Camios opened 6 months ago

Camios commented 6 months ago

Description

Right-docked controls are being hidden when in horizontally stretched list box items of a virtualized list box. Seems like the layout isn't being re-evaluated after scrolling.

Reproduction Steps

  1. Build and run the attached WPF project. It launches a small window containing a virtualizing list box where each item has a left-docked TextBlock with text trimming and a right-docked button.
  2. Using the vertical scroll bar click in the bottom gutter to page down once.
  3. Then using the right hand edge of the application Window, reduce the width until the text of the line "six million nine hundred" starts being trimmed (character ellipses). App.zip

Expected behavior

The button "Click!" should continue to right-docked and should not be clipped no matter the width of the list box.

image

Actual behavior

The button "Click!" gets clipped incorrectly

image

Regression?

No response

Known Workarounds

There doesn't appears to be a coding workaround that I could find. I tried swapping the item's data template from a DockPanel to a Grid, but it still had the problem. Tried invalidating measure and arrange when size changed too but no good.

So while this bug will still occur the user might be able to workaround it by scrolling vertically by a page and then returning (which actually performs the arrangement properly - see the screenshot in the "Expected Behavior" section); or resizing the width to make it wide again (although resizing may not be practical in some circumstances). But it happening at all is very undesirable.

Impact

This bug hides parts of the UI unexpectedly and there is no simple code workaround.

Configuration

Reproduced in .NET 6 and .NET 8 Windows 11 x64

Other information

No response

Camios commented 6 months ago

I also tested this with a visible horizontal scroll bar and found it is buggy too. When you've scrolled down a page and reduce the width, it starts clipping the button, which is expected, but it should be showing a horizontal scroll bar and it's not. If you scroll up and back down again, then it is reevaluating something which fixes it and the horizontal scrollbar shows up correctly.

Do the offscreen list items (those children outside of the extended viewport) have stale widths that are too wide (still using the width when the app is first loaded, before scrolling down and resizing). And those old widths are incorrectly informing the available width calculations. The correct width of the offscreen children is only recalculated by scrolling up to them again.

https://github.com/dotnet/wpf/assets/2810835/9f857953-4573-40ac-b7c1-185f2d01881c

Camios commented 6 months ago

As another experiment I built against the WPF source code and changed the method VirtualizingStackPanel.GetMaxChildArrangeLength(IList, bool) to loop over the onscreen children (i.e. _firstItemInExtendedViewportChildIndex to _firstItemInExtendedViewportChildIndex + _actualItemsInExtendedViewportCount) instead of all the children and it fixed the problem when horizontal scroll bar was disabled, but caused flickering of the button when the horizontal scrollbar was visible.