diff --git a/src/Avalonia.Controls/ItemsControl.cs b/src/Avalonia.Controls/ItemsControl.cs index 4dc8aec6f3..20d032f597 100644 --- a/src/Avalonia.Controls/ItemsControl.cs +++ b/src/Avalonia.Controls/ItemsControl.cs @@ -70,7 +70,7 @@ namespace Avalonia.Controls /// public ItemsControl() { - PseudoClasses.Add(":empty"); + UpdatePseudoClasses(0); SubscribeToItems(_items); } @@ -323,6 +323,16 @@ namespace Avalonia.Controls base.OnKeyDown(e); } + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + + if (change.Property == ItemCountProperty) + { + UpdatePseudoClasses(change.NewValue.GetValueOrDefault()); + } + } + /// /// Called when the property changes. /// @@ -371,10 +381,6 @@ namespace Avalonia.Controls } Presenter?.ItemsChanged(e); - - var collection = sender as ICollection; - PseudoClasses.Set(":empty", collection == null || collection.Count == 0); - PseudoClasses.Set(":singleitem", collection != null && collection.Count == 1); } /// @@ -431,9 +437,6 @@ namespace Avalonia.Controls /// The items collection. private void SubscribeToItems(IEnumerable items) { - PseudoClasses.Set(":empty", items == null || items.Count() == 0); - PseudoClasses.Set(":singleitem", items != null && items.Count() == 1); - if (items is INotifyCollectionChanged incc) { CollectionChangedEventManager.Instance.AddListener(incc, this); @@ -469,6 +472,12 @@ namespace Avalonia.Controls } } + private void UpdatePseudoClasses(int itemCount) + { + PseudoClasses.Set(":empty", itemCount == 0); + PseudoClasses.Set(":singleitem", itemCount == 1); + } + protected static IInputElement GetNextControl( INavigableContainer container, NavigationDirection direction, diff --git a/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs b/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs index 684486cbae..bfece7871c 100644 --- a/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs @@ -379,6 +379,17 @@ namespace Avalonia.Controls.UnitTests Assert.DoesNotContain(":empty", target.Classes); } + [Fact] + public void Empty_Class_Should_Be_Set_When_Items_Not_Set() + { + var target = new ItemsControl() + { + Template = GetTemplate(), + }; + + Assert.Contains(":empty", target.Classes); + } + [Fact] public void Empty_Class_Should_Be_Set_When_Empty_Collection_Set() { @@ -393,6 +404,118 @@ namespace Avalonia.Controls.UnitTests Assert.Contains(":empty", target.Classes); } + [Fact] + public void Item_Count_Should_Be_Set_When_Items_Added() + { + var target = new ItemsControl() + { + Template = GetTemplate(), + Items = new[] { 1, 2, 3 }, + }; + + Assert.Equal(3, target.ItemCount); + } + + [Fact] + public void Item_Count_Should_Be_Set_When_Items_Changed() + { + var items = new ObservableCollection() { 1, 2, 3 }; + + var target = new ItemsControl() + { + Template = GetTemplate(), + Items = items, + }; + + items.Add(4); + + Assert.Equal(4, target.ItemCount); + + items.Clear(); + + Assert.Equal(0, target.ItemCount); + } + + [Fact] + public void Empty_Class_Should_Be_Set_When_Items_Collection_Cleared() + { + var items = new ObservableCollection() { 1, 2, 3 }; + + var target = new ItemsControl() + { + Template = GetTemplate(), + Items = items, + }; + + items.Clear(); + + Assert.Contains(":empty", target.Classes); + } + + [Fact] + public void Empty_Class_Should_Not_Be_Set_When_Items_Collection_Count_Increases() + { + var items = new ObservableCollection() { }; + + var target = new ItemsControl() + { + Template = GetTemplate(), + Items = items, + }; + + items.Add(1); + + Assert.DoesNotContain(":empty", target.Classes); + } + + [Fact] + public void Single_Item_Class_Should_Be_Set_When_Items_Collection_Count_Increases_To_One() + { + var items = new ObservableCollection() { }; + + var target = new ItemsControl() + { + Template = GetTemplate(), + Items = items, + }; + + items.Add(1); + + Assert.Contains(":singleitem", target.Classes); + } + + [Fact] + public void Empty_Class_Should_Not_Be_Set_When_Items_Collection_Cleared() + { + var items = new ObservableCollection() { 1, 2, 3 }; + + var target = new ItemsControl() + { + Template = GetTemplate(), + Items = items, + }; + + items.Clear(); + + Assert.DoesNotContain(":singleitem", target.Classes); + } + + [Fact] + public void Single_Item_Class_Should_Not_Be_Set_When_Items_Collection_Count_Increases_Beyond_One() + { + var items = new ObservableCollection() { 1 }; + + var target = new ItemsControl() + { + Template = GetTemplate(), + Items = items, + }; + + items.Add(2); + + Assert.DoesNotContain(":singleitem", target.Classes); + } + [Fact] public void Setting_Presenter_Explicitly_Should_Set_Item_Parent() {