From 2722f9bcfd606941742d8a3641a9c68957fafc66 Mon Sep 17 00:00:00 2001 From: Julien Lebosquain Date: Thu, 21 Sep 2023 01:14:37 +0200 Subject: [PATCH] Fix VirtualizingStackPanel and nth-child for the currently realizing item container (#12957) * Added failing tests for VirtualizingStackPanel and nth-child * VirtualizingStackPanel: support index of currently realizing item --- .../VirtualizingStackPanel.cs | 10 ++++ .../VirtualizingStackPanelTests.cs | 54 +++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/src/Avalonia.Controls/VirtualizingStackPanel.cs b/src/Avalonia.Controls/VirtualizingStackPanel.cs index 6a3c7e17ee..2d9c19b859 100644 --- a/src/Avalonia.Controls/VirtualizingStackPanel.cs +++ b/src/Avalonia.Controls/VirtualizingStackPanel.cs @@ -72,6 +72,8 @@ namespace Avalonia.Controls private Dictionary>? _recyclePool; private Control? _focusedElement; private int _focusedIndex = -1; + private Control? _realizingElement; + private int _realizingIndex = -1; public VirtualizingStackPanel() { @@ -336,6 +338,8 @@ namespace Avalonia.Controls return _scrollToElement; if (_focusedIndex == index) return _focusedElement; + if (index == _realizingIndex) + return _realizingElement; if (GetRealizedElement(index) is { } realized) return realized; if (Items[index] is Control c && c.GetValue(RecycleKeyProperty) == s_itemIsItsOwnContainer) @@ -349,6 +353,8 @@ namespace Avalonia.Controls return _scrollToIndex; if (container == _focusedElement) return _focusedIndex; + if (container == _realizingElement) + return _realizingIndex; return _realizedElements?.GetIndex(container) ?? -1; } @@ -532,7 +538,9 @@ namespace Avalonia.Controls // Start at the anchor element and move forwards, realizing elements. do { + _realizingIndex = index; var e = GetOrCreateElement(items, index); + _realizingElement = e; e.Measure(availableSize); var sizeU = horizontal ? e.DesiredSize.Width : e.DesiredSize.Height; @@ -543,6 +551,8 @@ namespace Avalonia.Controls u += sizeU; ++index; + _realizingIndex = -1; + _realizingElement = null; } while (u < viewport.viewportUEnd && index < items.Count); // Store the last index and end U position for the desired size calculation. diff --git a/tests/Avalonia.Controls.UnitTests/VirtualizingStackPanelTests.cs b/tests/Avalonia.Controls.UnitTests/VirtualizingStackPanelTests.cs index ba4fb32067..0aaa28e5ae 100644 --- a/tests/Avalonia.Controls.UnitTests/VirtualizingStackPanelTests.cs +++ b/tests/Avalonia.Controls.UnitTests/VirtualizingStackPanelTests.cs @@ -501,6 +501,33 @@ namespace Avalonia.Controls.UnitTests } } + // https://github.com/AvaloniaUI/Avalonia/issues/12838 + [Fact] + public void NthChild_Selector_Works_For_ItemTemplate_Children() + { + using var app = App(); + + var style = new Style(x => x.OfType().NthChild(5, 0).Child().OfType()) + { + Setters = { new Setter(Panel.BackgroundProperty, Brushes.Red) }, + }; + + var (target, _, _) = CreateTarget(styles: new[] { style }); + var realized = target.GetRealizedContainers()!.Cast().ToList(); + + Assert.Equal(10, realized.Count); + + for (var i = 0; i < 10; ++i) + { + var container = realized[i]; + var index = target.IndexFromContainer(container); + var expectedBackground = (i == 4 || i == 9) ? Brushes.Red : null; + + Assert.Equal(i, index); + Assert.Equal(expectedBackground, ((Canvas) container.Child!).Background); + } + } + [Fact] public void NthLastChild_Selector_Works() { @@ -527,6 +554,33 @@ namespace Avalonia.Controls.UnitTests } } + // https://github.com/AvaloniaUI/Avalonia/issues/12838 + [Fact] + public void NthLastChild_Selector_Works_For_ItemTemplate_Children() + { + using var app = App(); + + var style = new Style(x => x.OfType().NthLastChild(5, 0).Child().OfType()) + { + Setters = { new Setter(Panel.BackgroundProperty, Brushes.Red) }, + }; + + var (target, _, _) = CreateTarget(styles: new[] { style }); + var realized = target.GetRealizedContainers()!.Cast().ToList(); + + Assert.Equal(10, realized.Count); + + for (var i = 0; i < 10; ++i) + { + var container = realized[i]; + var index = target.IndexFromContainer(container); + var expectedBackground = (i == 0 || i == 5) ? Brushes.Red : null; + + Assert.Equal(i, index); + Assert.Equal(expectedBackground, ((Canvas) container.Child!).Background); + } + } + [Fact] public void ContainerPrepared_Is_Raised_When_Scrolling() {