diff --git a/src/Avalonia.Controls/Presenters/CarouselPresenter.cs b/src/Avalonia.Controls/Presenters/CarouselPresenter.cs index c6ef5a14e9..144174e371 100644 --- a/src/Avalonia.Controls/Presenters/CarouselPresenter.cs +++ b/src/Avalonia.Controls/Presenters/CarouselPresenter.cs @@ -106,7 +106,6 @@ namespace Avalonia.Controls.Presenters /// protected override void ItemsChanged(NotifyCollectionChangedEventArgs e) { - // TODO: Handle items changing. switch (e.Action) { case NotifyCollectionChangedAction.Remove: @@ -115,9 +114,21 @@ namespace Avalonia.Controls.Presenters var generator = ItemContainerGenerator; var containers = generator.RemoveRange(e.OldStartingIndex, e.OldItems.Count); Panel.Children.RemoveAll(containers.Select(x => x.ContainerControl)); + + MoveToPage(-1, SelectedIndex); } break; + case NotifyCollectionChangedAction.Reset: + { + var generator = ItemContainerGenerator; + var containers = generator.Containers.ToList(); + generator.Clear(); + Panel.Children.RemoveAll(containers.Select(x => x.ContainerControl)); + + MoveToPage(-1, SelectedIndex >= 0 ? SelectedIndex : 0); + } + break; } } diff --git a/tests/Avalonia.Controls.UnitTests/CarouselTests.cs b/tests/Avalonia.Controls.UnitTests/CarouselTests.cs index 4d38ec9856..df61698209 100644 --- a/tests/Avalonia.Controls.UnitTests/CarouselTests.cs +++ b/tests/Avalonia.Controls.UnitTests/CarouselTests.cs @@ -1,11 +1,13 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. +using System.Collections.ObjectModel; using System.Linq; using Avalonia.Controls.Presenters; using Avalonia.Controls.Primitives; using Avalonia.Controls.Templates; using Avalonia.LogicalTree; +using Avalonia.VisualTree; using Xunit; namespace Avalonia.Controls.UnitTests @@ -50,7 +52,7 @@ namespace Avalonia.Controls.UnitTests Assert.Single(target.GetLogicalChildren()); var child = target.GetLogicalChildren().Single(); - + Assert.IsType(child); Assert.Equal("Foo", ((TextBlock)child).Text); } @@ -93,6 +95,173 @@ namespace Avalonia.Controls.UnitTests Assert.Equal(2, target.ItemContainerGenerator.Containers.Count()); } + [Fact] + public void Selected_Item_Changes_To_First_Item_When_Items_Property_Changes() + { + var items = new ObservableCollection + { + "Foo", + "Bar", + "FooBar" + }; + + var target = new Carousel + { + Template = new FuncControlTemplate(CreateTemplate), + Items = items, + IsVirtualized = false + }; + + target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); + + Assert.Single(target.GetLogicalChildren()); + + var child = target.GetLogicalChildren().Single(); + + Assert.IsType(child); + Assert.Equal("Foo", ((TextBlock)child).Text); + + var newItems = items.ToList(); + newItems.RemoveAt(0); + + target.Items = newItems; + + child = target.GetLogicalChildren().Single(); + + Assert.IsType(child); + Assert.Equal("Bar", ((TextBlock)child).Text); + } + + [Fact] + public void Selected_Item_Changes_To_First_Item_When_Items_Property_Changes_And_Virtualized() + { + var items = new ObservableCollection + { + "Foo", + "Bar", + "FooBar" + }; + + var target = new Carousel + { + Template = new FuncControlTemplate(CreateTemplate), + Items = items + }; + + target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); + + Assert.Single(target.GetLogicalChildren()); + + var child = target.GetLogicalChildren().Single(); + + Assert.IsType(child); + Assert.Equal("Foo", ((TextBlock)child).Text); + + var newItems = items.ToList(); + newItems.RemoveAt(0); + + target.Items = newItems; + + child = target.GetLogicalChildren().Single(); + + Assert.IsType(child); + Assert.Equal("Bar", ((TextBlock)child).Text); + } + + [Fact] + public void Selected_Index_Is_Maintained_Carousel_Created_With_Non_Zero_SelectedIndex() + { + var items = new ObservableCollection + { + "Foo", + "Bar", + "FooBar" + }; + + var target = new Carousel + { + Template = new FuncControlTemplate(CreateTemplate), + Items = items, + IsVirtualized = false, + SelectedIndex = 2 + }; + + target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); + + Assert.Equal("FooBar", target.SelectedItem); + + var child = target.GetVisualDescendants().LastOrDefault(); + + Assert.IsType(child); + Assert.Equal("FooBar", ((TextBlock)child).Text); + } + + [Fact] + public void Selected_Item_Changes_To_Next_First_Item_When_Item_Removed_From_Beggining_Of_List() + { + var items = new ObservableCollection + { + "Foo", + "Bar", + "FooBar" + }; + + var target = new Carousel + { + Template = new FuncControlTemplate(CreateTemplate), + Items = items, + IsVirtualized = false + }; + + target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); + + Assert.Single(target.GetLogicalChildren()); + + var child = target.GetLogicalChildren().Single(); + + Assert.IsType(child); + Assert.Equal("Foo", ((TextBlock)child).Text); + + items.RemoveAt(0); + + child = target.GetLogicalChildren().Single(); + + Assert.IsType(child); + Assert.Equal("Bar", ((TextBlock)child).Text); + } + + [Fact] + public void Selected_Item_Changes_To_NextAvailable_Item_If_SelectedItem_Is_Removed_From_Middle() + { + var items = new ObservableCollection + { + "Foo", + "Bar", + "FooBar" + }; + + var target = new Carousel + { + Template = new FuncControlTemplate(CreateTemplate), + Items = items, + IsVirtualized = false + }; + + target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); + + target.SelectedIndex = 1; + + items.RemoveAt(1); + + Assert.Equal(1, target.SelectedIndex); + Assert.Equal("FooBar", target.SelectedItem); + } + private Control CreateTemplate(Carousel control) { return new CarouselPresenter