diff --git a/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs b/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs index a95369c..9ad968c 100644 --- a/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs +++ b/src/Ursa/Controls/Breadcrumb/Breadcrumb.cs @@ -5,6 +5,7 @@ using Avalonia.Controls.Templates; using Avalonia.Data; using Avalonia.Layout; using Avalonia.Metadata; +using Avalonia.VisualTree; namespace Ursa.Controls; @@ -84,17 +85,6 @@ public class Breadcrumb: ItemsControl return new BreadcrumbItem(); } - protected override void LogicalChildrenCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) - { - base.LogicalChildrenCollectionChanged(sender, e); - var breadcrumbItems = LogicalChildren.OfType().ToList(); - for (var i = 0; i < breadcrumbItems.Count; i++) - { - var breadcrumbItem = breadcrumbItems[i]; - breadcrumbItem.SetPseudoClassLast(i == breadcrumbItems.Count - 1); - } - } - protected override void PrepareContainerForItemOverride(Control container, object? item, int index) { if (container is not BreadcrumbItem breadcrumbItem) return; @@ -149,4 +139,13 @@ public class Breadcrumb: ItemsControl ITemplate t => t.Build(), _ => separator.ToString() }; + + internal void InvalidateContainers() + { + var breadcrumbItems = this.GetVisualDescendants().OfType().ToList(); + for (var i = 0; i < breadcrumbItems.Count; i++) + { + breadcrumbItems[i].SetPseudoClassLast(i == breadcrumbItems.Count - 1); + } + } } \ No newline at end of file diff --git a/src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs b/src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs index 4e93a35..3bb0e5e 100644 --- a/src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs +++ b/src/Ursa/Controls/Breadcrumb/BreadcrumbItem.cs @@ -79,4 +79,11 @@ public class BreadcrumbItem: ContentControl { PseudoClasses.Set(PC_Last, isLast); } + + protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) + { + base.OnAttachedToVisualTree(e); + var parent = this.Parent as Breadcrumb; + parent?.InvalidateContainers(); + } } \ No newline at end of file diff --git a/tests/HeadlessTest.Ursa/Controls/BreadcrumbTests/BreadcrumbTests.cs b/tests/HeadlessTest.Ursa/Controls/BreadcrumbTests/BreadcrumbTests.cs index d7d7ed1..9761fae 100644 --- a/tests/HeadlessTest.Ursa/Controls/BreadcrumbTests/BreadcrumbTests.cs +++ b/tests/HeadlessTest.Ursa/Controls/BreadcrumbTests/BreadcrumbTests.cs @@ -2,6 +2,7 @@ using System.Collections.ObjectModel; using Avalonia.Controls; using Avalonia.Headless.XUnit; using Avalonia.LogicalTree; +using Avalonia.VisualTree; using Ursa.Controls; namespace HeadlessTest.Ursa.Controls; @@ -34,11 +35,11 @@ public class BreadcrumbTests var item1 = new TextBlock(); var item2 = new TextBlock(); breadcrumb.Items.Add(item1); - var firstItem = breadcrumb.GetLogicalChildren().OfType().FirstOrDefault(); + var firstItem = breadcrumb.GetVisualDescendants().OfType().FirstOrDefault(); Assert.NotNull(firstItem); Assert.Contains(":last", firstItem.Classes); breadcrumb.Items.Add(item2); - var lastItem = breadcrumb.GetLogicalChildren().OfType().LastOrDefault(); + var lastItem = breadcrumb.GetVisualDescendants().OfType().LastOrDefault(); Assert.NotNull(lastItem); Assert.Contains(":last", lastItem.Classes); Assert.DoesNotContain(":last", firstItem.Classes); @@ -54,16 +55,38 @@ public class BreadcrumbTests var items = new ObservableCollection(); breadcrumb.ItemsSource = items; items.Add("Item 1"); - var item1 = breadcrumb.GetLogicalChildren().OfType().FirstOrDefault(); + var item1 = breadcrumb.GetVisualDescendants().OfType().FirstOrDefault(); Assert.NotNull(item1); Assert.Contains(":last", item1.Classes); items.Add("Item 2"); - var item2 = breadcrumb.GetLogicalChildren().OfType().LastOrDefault(); + var item2 = breadcrumb.GetVisualDescendants().OfType().LastOrDefault(); Assert.NotNull(item2); Assert.Contains(":last", item2.Classes); Assert.DoesNotContain(":last", item1.Classes); } + [AvaloniaFact] + public void BreadcrumbItem_FromItemsSource_Should_Have_Correct_PseudoClasses_When_Insert() + { + var window = new Window(); + var breadcrumb = new Breadcrumb(); + window.Content = breadcrumb; + window.Show(); + var items = new ObservableCollection(); + breadcrumb.ItemsSource = items; + items.Add("Item 1"); + var item1 = breadcrumb.GetVisualDescendants().OfType().FirstOrDefault(); + Assert.NotNull(item1); + Assert.Contains(":last", item1.Classes); + items.Insert(0, "Item 2"); + var item2 = breadcrumb.GetVisualDescendants().OfType().LastOrDefault(); + Assert.NotNull(item2); + Assert.Contains(":last", item2.Classes); + var newItem1 = breadcrumb.GetVisualDescendants().OfType().FirstOrDefault(); + Assert.NotNull(newItem1); + Assert.DoesNotContain(":last", newItem1.Classes); + } + [AvaloniaFact] public void Bulk_Added_BreadcrumbItem_Should_Have_Correct_PseudoClasses() { @@ -77,8 +100,8 @@ public class BreadcrumbTests "Item 2" }; breadcrumb.ItemsSource = items; - var item1 = breadcrumb.GetLogicalChildren().OfType().FirstOrDefault(); - var item2 = breadcrumb.GetLogicalChildren().OfType().LastOrDefault(); + var item1 = breadcrumb.GetVisualDescendants().OfType().FirstOrDefault(); + var item2 = breadcrumb.GetVisualDescendants().OfType().LastOrDefault(); Assert.NotNull(item1); Assert.NotNull(item2); Assert.Contains(":last", item2.Classes);