From a2ea7e36e3fcca791a0942761cd0bbb7858d0302 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sat, 16 Apr 2016 14:39:39 +0200 Subject: [PATCH] Added Carousel.IsVirtualized. --- src/Perspex.Controls/Carousel.cs | 18 ++++++++ .../Generators/ItemContainerGenerator.cs | 2 +- .../Presenters/CarouselPresenter.cs | 44 ++++++++++++++---- src/Perspex.Themes.Default/Carousel.xaml | 3 +- .../CarouselTests.cs | 45 +++++++++++++++++-- .../Presenters/CarouselPresenterTests.cs | 38 ++++++++++++++++ 6 files changed, 137 insertions(+), 13 deletions(-) diff --git a/src/Perspex.Controls/Carousel.cs b/src/Perspex.Controls/Carousel.cs index fda48d0b42..36e586321c 100644 --- a/src/Perspex.Controls/Carousel.cs +++ b/src/Perspex.Controls/Carousel.cs @@ -14,6 +14,12 @@ namespace Perspex.Controls /// public class Carousel : SelectingItemsControl { + /// + /// Defines the property. + /// + public static readonly StyledProperty IsVirtualizedProperty = + PerspexProperty.Register(nameof(IsVirtualized), true); + /// /// Defines the property. /// @@ -35,6 +41,18 @@ namespace Perspex.Controls SelectionModeProperty.OverrideDefaultValue(SelectionMode.AlwaysSelected); ItemsPanelProperty.OverrideDefaultValue(PanelTemplate); } + + /// + /// Gets or sets a value indicating whether the items in the carousel are virtualized. + /// + /// + /// When the carousel is virtualized, only the active page is held in memory. + /// + public bool IsVirtualized + { + get { return GetValue(IsVirtualizedProperty); } + set { SetValue(IsVirtualizedProperty, value); } + } /// /// Gets or sets the transition to use when moving between pages. diff --git a/src/Perspex.Controls/Generators/ItemContainerGenerator.cs b/src/Perspex.Controls/Generators/ItemContainerGenerator.cs index 0e30518346..a162ce08de 100644 --- a/src/Perspex.Controls/Generators/ItemContainerGenerator.cs +++ b/src/Perspex.Controls/Generators/ItemContainerGenerator.cs @@ -29,7 +29,7 @@ namespace Perspex.Controls.Generators } /// - public IEnumerable Containers => _containers; + public IEnumerable Containers => _containers.Where(x => x != null); /// public event EventHandler Materialized; diff --git a/src/Perspex.Controls/Presenters/CarouselPresenter.cs b/src/Perspex.Controls/Presenters/CarouselPresenter.cs index 8d25729e74..cde7bcf823 100644 --- a/src/Perspex.Controls/Presenters/CarouselPresenter.cs +++ b/src/Perspex.Controls/Presenters/CarouselPresenter.cs @@ -20,6 +20,12 @@ namespace Perspex.Controls.Presenters /// public class CarouselPresenter : Control, IItemsPresenter { + /// + /// Defines the property. + /// + public static readonly StyledProperty IsVirtualizedProperty = + Carousel.IsVirtualizedProperty.AddOwner(); + /// /// Defines the property. /// @@ -96,6 +102,18 @@ namespace Perspex.Controls.Presenters } } + /// + /// Gets or sets a value indicating whether the items in the carousel are virtualized. + /// + /// + /// When the carousel is virtualized, only the active page is held in memory. + /// + public bool IsVirtualized + { + get { return GetValue(IsVirtualizedProperty); } + set { SetValue(IsVirtualizedProperty, value); } + } + /// /// Gets or sets the items to display. /// @@ -212,13 +230,17 @@ namespace Perspex.Controls.Presenters if (toIndex != -1) { var item = Items.Cast().ElementAt(toIndex); - to = generator.ContainerFromIndex(toIndex) ?? - generator.Materialize(toIndex, new[] { item }, MemberSelector) - .FirstOrDefault()?.ContainerControl; + to = generator.ContainerFromIndex(toIndex); - if (to != null) + if (to == null) { - Panel.Children.Add(to); + to = generator.Materialize(toIndex, new[] { item }, MemberSelector) + .FirstOrDefault()?.ContainerControl; + + if (to != null) + { + Panel.Children.Add(to); + } } } @@ -233,10 +255,16 @@ namespace Perspex.Controls.Presenters if (from != null) { - Panel.Children.Remove(from); - generator.Dematerialize(fromIndex, 1); + if (IsVirtualized) + { + Panel.Children.Remove(from); + generator.Dematerialize(fromIndex, 1); + } + else + { + from.IsVisible = false; + } } - } } diff --git a/src/Perspex.Themes.Default/Carousel.xaml b/src/Perspex.Themes.Default/Carousel.xaml index 8c0c87143c..ff9fa77b57 100644 --- a/src/Perspex.Themes.Default/Carousel.xaml +++ b/src/Perspex.Themes.Default/Carousel.xaml @@ -4,7 +4,8 @@ - (CreateTemplate), + Items = new[] { "foo", "bar" }, + IsVirtualized = true, + SelectedIndex = 0, + }; + + target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); + + Assert.Equal(1, target.ItemContainerGenerator.Containers.Count()); + target.SelectedIndex = 1; + Assert.Equal(1, target.ItemContainerGenerator.Containers.Count()); + } + + [Fact] + public void Should_Not_Remove_NonCurrent_Page_When_IsVirtualized_False() + { + var target = new Carousel + { + Template = new FuncControlTemplate(CreateTemplate), + Items = new[] { "foo", "bar" }, + IsVirtualized = false, + SelectedIndex = 0, + }; + + target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); + + Assert.Equal(1, target.ItemContainerGenerator.Containers.Count()); + target.SelectedIndex = 1; + Assert.Equal(2, target.ItemContainerGenerator.Containers.Count()); + } + private Control CreateTemplate(Carousel control) { return new CarouselPresenter { Name = "PART_ItemsPresenter", - [~ItemsPresenter.ItemsProperty] = control[~ItemsControl.ItemsProperty], - [~ItemsPresenter.ItemsPanelProperty] = control[~ItemsControl.ItemsPanelProperty], - [~CarouselPresenter.SelectedIndexProperty] = control[~SelectingItemsControl.SelectedIndexProperty], + [~CarouselPresenter.IsVirtualizedProperty] = control[~Carousel.IsVirtualizedProperty], + [~CarouselPresenter.ItemsProperty] = control[~Carousel.ItemsProperty], + [~CarouselPresenter.ItemsPanelProperty] = control[~Carousel.ItemsPanelProperty], + [~CarouselPresenter.SelectedIndexProperty] = control[~Carousel.SelectedIndexProperty], [~CarouselPresenter.TransitionProperty] = control[~Carousel.TransitionProperty], }; } diff --git a/tests/Perspex.Controls.UnitTests/Presenters/CarouselPresenterTests.cs b/tests/Perspex.Controls.UnitTests/Presenters/CarouselPresenterTests.cs index 3d715b93fb..31aebb6124 100644 --- a/tests/Perspex.Controls.UnitTests/Presenters/CarouselPresenterTests.cs +++ b/tests/Perspex.Controls.UnitTests/Presenters/CarouselPresenterTests.cs @@ -1,6 +1,7 @@ // Copyright (c) The Perspex Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. +using System.Linq; using Moq; using Perspex.Controls.Generators; using Perspex.Controls.Presenters; @@ -78,6 +79,43 @@ namespace Perspex.Controls.UnitTests.Presenters Assert.Equal("bar", ((TextBlock)target.Panel.Children[0]).Text); } + [Fact] + public void Should_Remove_NonCurrent_Page_When_IsVirtualized_True() + { + var target = new CarouselPresenter + { + Items = new[] { "foo", "bar" }, + IsVirtualized = true, + SelectedIndex = 0, + }; + + target.ApplyTemplate(); + Assert.Equal(1, target.ItemContainerGenerator.Containers.Count()); + target.SelectedIndex = 1; + Assert.Equal(1, target.ItemContainerGenerator.Containers.Count()); + } + + [Fact] + public void Should_Not_Remove_NonCurrent_Page_When_IsVirtualized_False() + { + var target = new CarouselPresenter + { + Items = new[] { "foo", "bar" }, + IsVirtualized = false, + SelectedIndex = 0, + }; + + target.ApplyTemplate(); + Assert.Equal(1, target.ItemContainerGenerator.Containers.Count()); + Assert.Equal(1, target.Panel.Children.Count); + target.SelectedIndex = 1; + Assert.Equal(2, target.ItemContainerGenerator.Containers.Count()); + Assert.Equal(2, target.Panel.Children.Count); + target.SelectedIndex = 0; + Assert.Equal(2, target.ItemContainerGenerator.Containers.Count()); + Assert.Equal(2, target.Panel.Children.Count); + } + private class TestItem : ContentControl { }