Browse Source

Merge branch 'master' into fixes/FontFamilyFromUri

pull/2497/head
Steven Kirk 7 years ago
committed by GitHub
parent
commit
f9669dc8a4
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 111
      src/Avalonia.Controls/Presenters/CarouselPresenter.cs
  2. 125
      src/Avalonia.Controls/Presenters/ItemContainerSync.cs
  3. 48
      src/Avalonia.Controls/Presenters/ItemVirtualizerNone.cs
  4. 9
      src/Avalonia.Controls/Presenters/ItemsPresenterBase.cs
  5. 11
      src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
  6. 38
      tests/Avalonia.Controls.UnitTests/CarouselTests.cs
  7. 753
      tests/Avalonia.Controls.UnitTests/Presenters/CarouselPresenterTests.cs

111
src/Avalonia.Controls/Presenters/CarouselPresenter.cs

@ -38,7 +38,6 @@ namespace Avalonia.Controls.Presenters
Carousel.PageTransitionProperty.AddOwner<CarouselPresenter>();
private int _selectedIndex = -1;
// private Task _current;
private Task _currentTransition;
private int _queuedTransitionIndex = -1;
@ -47,6 +46,7 @@ namespace Avalonia.Controls.Presenters
/// </summary>
static CarouselPresenter()
{
IsVirtualizedProperty.Changed.AddClassHandler<CarouselPresenter>(x => x.IsVirtualizedChanged);
SelectedIndexProperty.Changed.AddClassHandler<CarouselPresenter>(x => x.SelectedIndexChanged);
}
@ -94,58 +94,67 @@ namespace Avalonia.Controls.Presenters
set { SetValue(PageTransitionProperty, value); }
}
/// <inheritdoc/>
protected override void PanelCreated(IPanel panel)
{
#pragma warning disable 4014
MoveToPage(-1, SelectedIndex);
#pragma warning restore 4014
}
/// <inheritdoc/>
protected override void ItemsChanged(NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
if (!IsVirtualized)
{
case NotifyCollectionChangedAction.Remove:
if (!IsVirtualized)
{
var generator = ItemContainerGenerator;
var containers = generator.RemoveRange(e.OldStartingIndex, e.OldItems.Count);
Panel.Children.RemoveAll(containers.Select(x => x.ContainerControl));
base.ItemsChanged(e);
#pragma warning disable 4014
MoveToPage(-1, SelectedIndex);
#pragma warning restore 4014
}
break;
case NotifyCollectionChangedAction.Reset:
{
var generator = ItemContainerGenerator;
var containers = generator.Containers.ToList();
generator.Clear();
Panel.Children.RemoveAll(containers.Select(x => x.ContainerControl));
#pragma warning disable 4014
var newIndex = SelectedIndex;
if (Items == null || SelectedIndex >= Items.Count())
{
SelectedIndex = Items.Count() - 1;
}
if(SelectedIndex < 0)
foreach (var c in ItemContainerGenerator.Containers)
{
c.ContainerControl.IsVisible = c.Index == SelectedIndex;
}
}
else if (SelectedIndex != -1 && Panel != null)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
if (e.NewStartingIndex > SelectedIndex)
{
if(Items != null && Items.Count() > 0)
{
newIndex = 0;
}
else
{
newIndex = -1;
}
return;
}
MoveToPage(-1, newIndex);
#pragma warning restore 4014
}
break;
break;
case NotifyCollectionChangedAction.Remove:
if (e.OldStartingIndex > SelectedIndex)
{
return;
}
break;
case NotifyCollectionChangedAction.Replace:
if (e.OldStartingIndex > SelectedIndex ||
e.OldStartingIndex + e.OldItems.Count - 1 < SelectedIndex)
{
return;
}
break;
case NotifyCollectionChangedAction.Move:
if (e.OldStartingIndex > SelectedIndex &&
e.NewStartingIndex > SelectedIndex)
{
return;
}
break;
}
if (Items == null || SelectedIndex >= Items.Count())
{
SelectedIndex = Items.Count() - 1;
}
Panel.Children.Clear();
ItemContainerGenerator.Clear();
if (SelectedIndex != -1)
{
GetOrCreateContainer(SelectedIndex);
}
}
}
@ -212,6 +221,18 @@ namespace Avalonia.Controls.Presenters
return container;
}
/// <summary>
/// Called when the <see cref="IsVirtualized"/> property changes.
/// </summary>
/// <param name="e">The event args.</param>
private void IsVirtualizedChanged(AvaloniaPropertyChangedEventArgs e)
{
if (Panel != null)
{
ItemsChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
/// <summary>
/// Called when the <see cref="SelectedIndex"/> property changes.
/// </summary>

125
src/Avalonia.Controls/Presenters/ItemContainerSync.cs

@ -0,0 +1,125 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using Avalonia.Controls.Generators;
using Avalonia.Controls.Utils;
namespace Avalonia.Controls.Presenters
{
internal static class ItemContainerSync
{
public static void ItemsChanged(
ItemsPresenterBase owner,
IEnumerable items,
NotifyCollectionChangedEventArgs e)
{
var generator = owner.ItemContainerGenerator;
var panel = owner.Panel;
if (panel == null)
{
return;
}
void Add()
{
if (e.NewStartingIndex + e.NewItems.Count < items.Count())
{
generator.InsertSpace(e.NewStartingIndex, e.NewItems.Count);
}
AddContainers(owner, e.NewStartingIndex, e.NewItems);
}
void Remove()
{
RemoveContainers(panel, generator.RemoveRange(e.OldStartingIndex, e.OldItems.Count));
}
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
Add();
break;
case NotifyCollectionChangedAction.Remove:
Remove();
break;
case NotifyCollectionChangedAction.Replace:
RemoveContainers(panel, generator.Dematerialize(e.OldStartingIndex, e.OldItems.Count));
var containers = AddContainers(owner, e.NewStartingIndex, e.NewItems);
var i = e.NewStartingIndex;
foreach (var container in containers)
{
panel.Children[i++] = container.ContainerControl;
}
break;
case NotifyCollectionChangedAction.Move:
Remove();
Add();
break;
case NotifyCollectionChangedAction.Reset:
RemoveContainers(panel, generator.Clear());
if (items != null)
{
AddContainers(owner, 0, items);
}
break;
}
}
private static IList<ItemContainerInfo> AddContainers(
ItemsPresenterBase owner,
int index,
IEnumerable items)
{
var generator = owner.ItemContainerGenerator;
var result = new List<ItemContainerInfo>();
var panel = owner.Panel;
foreach (var item in items)
{
var i = generator.Materialize(index++, item, owner.MemberSelector);
if (i.ContainerControl != null)
{
if (i.Index < panel.Children.Count)
{
// TODO: This will insert at the wrong place when there are null items.
panel.Children.Insert(i.Index, i.ContainerControl);
}
else
{
panel.Children.Add(i.ContainerControl);
}
}
result.Add(i);
}
return result;
}
private static void RemoveContainers(
IPanel panel,
IEnumerable<ItemContainerInfo> items)
{
foreach (var i in items)
{
if (i.ContainerControl != null)
{
panel.Children.Remove(i.ContainerControl);
}
}
}
}
}

48
src/Avalonia.Controls/Presenters/ItemVirtualizerNone.cs

@ -60,53 +60,7 @@ namespace Avalonia.Controls.Presenters
public override void ItemsChanged(IEnumerable items, NotifyCollectionChangedEventArgs e)
{
base.ItemsChanged(items, e);
var generator = Owner.ItemContainerGenerator;
var panel = Owner.Panel;
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
if (e.NewStartingIndex + e.NewItems.Count < Items.Count())
{
generator.InsertSpace(e.NewStartingIndex, e.NewItems.Count);
}
AddContainers(e.NewStartingIndex, e.NewItems);
break;
case NotifyCollectionChangedAction.Remove:
RemoveContainers(generator.RemoveRange(e.OldStartingIndex, e.OldItems.Count));
break;
case NotifyCollectionChangedAction.Replace:
RemoveContainers(generator.Dematerialize(e.OldStartingIndex, e.OldItems.Count));
var containers = AddContainers(e.NewStartingIndex, e.NewItems);
var i = e.NewStartingIndex;
foreach (var container in containers)
{
panel.Children[i++] = container.ContainerControl;
}
break;
case NotifyCollectionChangedAction.Move:
// TODO: Handle move in a more efficient manner. At the moment we just
// drop through to Reset to recreate all the containers.
case NotifyCollectionChangedAction.Reset:
RemoveContainers(generator.Clear());
if (Items != null)
{
AddContainers(0, Items);
}
break;
}
ItemContainerSync.ItemsChanged(Owner, items, e);
Owner.InvalidateMeasure();
}

9
src/Avalonia.Controls/Presenters/ItemsPresenterBase.cs

@ -7,6 +7,7 @@ using System.Collections.Specialized;
using Avalonia.Collections;
using Avalonia.Controls.Generators;
using Avalonia.Controls.Templates;
using Avalonia.Controls.Utils;
using Avalonia.Styling;
namespace Avalonia.Controls.Presenters
@ -205,7 +206,13 @@ namespace Avalonia.Controls.Presenters
/// has been set, the items collection has been modified, or the panel has been created.
/// </summary>
/// <param name="e">A description of the change.</param>
protected abstract void ItemsChanged(NotifyCollectionChangedEventArgs e);
/// <remarks>
/// The panel is guaranteed to be created when this method is called.
/// </remarks>
protected virtual void ItemsChanged(NotifyCollectionChangedEventArgs e)
{
ItemContainerSync.ItemsChanged(this, Items, e);
}
/// <summary>
/// Creates the <see cref="Panel"/> when <see cref="ApplyTemplate"/> is called for the first

11
src/Avalonia.Controls/Primitives/SelectingItemsControl.cs

@ -325,14 +325,19 @@ namespace Avalonia.Controls.Primitives
if (_updateCount == 0)
{
var newIndex = -1;
if (SelectedIndex != -1)
{
SelectedIndex = IndexOf((IEnumerable)e.NewValue, SelectedItem);
newIndex = IndexOf((IEnumerable)e.NewValue, SelectedItem);
}
else if (AlwaysSelected && Items != null && Items.Cast<object>().Any())
if (AlwaysSelected && Items != null && Items.Cast<object>().Any())
{
SelectedIndex = 0;
newIndex = 0;
}
SelectedIndex = newIndex;
}
}

38
tests/Avalonia.Controls.UnitTests/CarouselTests.cs

@ -76,25 +76,6 @@ namespace Avalonia.Controls.UnitTests
Assert.Single(target.ItemContainerGenerator.Containers);
}
[Fact]
public void Should_Not_Remove_NonCurrent_Page_When_IsVirtualized_False()
{
var target = new Carousel
{
Template = new FuncControlTemplate<Carousel>(CreateTemplate),
Items = new[] { "foo", "bar" },
IsVirtualized = false,
SelectedIndex = 0,
};
target.ApplyTemplate();
target.Presenter.ApplyTemplate();
Assert.Single(target.ItemContainerGenerator.Containers);
target.SelectedIndex = 1;
Assert.Equal(2, target.ItemContainerGenerator.Containers.Count());
}
[Fact]
public void Selected_Item_Changes_To_First_Item_When_Items_Property_Changes()
{
@ -115,9 +96,9 @@ namespace Avalonia.Controls.UnitTests
target.ApplyTemplate();
target.Presenter.ApplyTemplate();
Assert.Single(target.GetLogicalChildren());
Assert.Equal(3, target.GetLogicalChildren().Count());
var child = target.GetLogicalChildren().Single();
var child = target.GetLogicalChildren().First();
Assert.IsType<TextBlock>(child);
Assert.Equal("Foo", ((TextBlock)child).Text);
@ -127,7 +108,7 @@ namespace Avalonia.Controls.UnitTests
target.Items = newItems;
child = target.GetLogicalChildren().Single();
child = target.GetLogicalChildren().First();
Assert.IsType<TextBlock>(child);
Assert.Equal("Bar", ((TextBlock)child).Text);
@ -146,7 +127,8 @@ namespace Avalonia.Controls.UnitTests
var target = new Carousel
{
Template = new FuncControlTemplate<Carousel>(CreateTemplate),
Items = items
Items = items,
IsVirtualized = true,
};
target.ApplyTemplate();
@ -190,9 +172,9 @@ namespace Avalonia.Controls.UnitTests
target.ApplyTemplate();
target.Presenter.ApplyTemplate();
Assert.Single(target.GetLogicalChildren());
Assert.Equal(3, target.GetLogicalChildren().Count());
var child = target.GetLogicalChildren().Single();
var child = target.GetLogicalChildren().First();
Assert.IsType<TextBlock>(child);
Assert.Equal("Foo", ((TextBlock)child).Text);
@ -254,16 +236,16 @@ namespace Avalonia.Controls.UnitTests
target.ApplyTemplate();
target.Presenter.ApplyTemplate();
Assert.Single(target.GetLogicalChildren());
Assert.Equal(3, target.GetLogicalChildren().Count());
var child = target.GetLogicalChildren().Single();
var child = target.GetLogicalChildren().First();
Assert.IsType<TextBlock>(child);
Assert.Equal("Foo", ((TextBlock)child).Text);
items.RemoveAt(0);
child = target.GetLogicalChildren().Single();
child = target.GetLogicalChildren().First();
Assert.IsType<TextBlock>(child);
Assert.Equal("Bar", ((TextBlock)child).Text);

753
tests/Avalonia.Controls.UnitTests/Presenters/CarouselPresenterTests.cs

@ -8,6 +8,7 @@ using Avalonia.Controls.Presenters;
using Avalonia.Controls.Templates;
using Xunit;
using System.Collections.ObjectModel;
using System.Collections;
namespace Avalonia.Controls.UnitTests.Presenters
{
@ -49,148 +50,672 @@ namespace Avalonia.Controls.UnitTests.Presenters
Assert.IsType<ItemContainerGenerator<TestItem>>(target.ItemContainerGenerator);
}
[Fact]
public void Setting_SelectedIndex_Should_Show_Page()
public class Virtualized
{
var target = new CarouselPresenter
[Fact]
public void Should_Initially_Materialize_Selected_Container()
{
Items = new[] { "foo", "bar" },
SelectedIndex = 0,
};
var target = new CarouselPresenter
{
Items = new[] { "foo", "bar" },
SelectedIndex = 0,
IsVirtualized = true,
};
target.ApplyTemplate();
target.ApplyTemplate();
Assert.IsType<ContentPresenter>(target.Panel.Children[0]);
Assert.Equal("foo", ((ContentPresenter)target.Panel.Children[0]).Content);
}
AssertSingle(target);
}
[Fact]
public void Changing_SelectedIndex_Should_Show_Page()
{
var target = new CarouselPresenter
[Fact]
public void Should_Initially_Materialize_Nothing_If_No_Selected_Container()
{
Items = new[] { "foo", "bar" },
SelectedIndex = 0,
};
var target = new CarouselPresenter
{
Items = new[] { "foo", "bar" },
IsVirtualized = true,
};
target.ApplyTemplate();
target.SelectedIndex = 1;
target.ApplyTemplate();
Assert.IsType<ContentPresenter>(target.Panel.Children[0]);
Assert.Equal("bar", ((ContentPresenter)target.Panel.Children[0]).Content);
}
Assert.Empty(target.Panel.Children);
Assert.Empty(target.ItemContainerGenerator.Containers);
}
[Fact]
public void Should_Remove_NonCurrent_Page_When_IsVirtualized_True()
{
var target = new CarouselPresenter
[Fact]
public void Switching_To_Virtualized_Should_Reset_Containers()
{
Items = new[] { "foo", "bar" },
IsVirtualized = true,
SelectedIndex = 0,
};
var target = new CarouselPresenter
{
Items = new[] { "foo", "bar" },
SelectedIndex = 0,
IsVirtualized = false,
};
target.ApplyTemplate();
Assert.Single(target.ItemContainerGenerator.Containers);
target.SelectedIndex = 1;
Assert.Single(target.ItemContainerGenerator.Containers);
}
target.ApplyTemplate();
target.IsVirtualized = true;
[Fact]
public void Should_Not_Remove_NonCurrent_Page_When_IsVirtualized_False()
{
var target = new CarouselPresenter
AssertSingle(target);
}
[Fact]
public void Changing_SelectedIndex_Should_Show_Page()
{
Items = new[] { "foo", "bar" },
IsVirtualized = false,
SelectedIndex = 0,
};
var target = new CarouselPresenter
{
Items = new[] { "foo", "bar" },
SelectedIndex = 0,
IsVirtualized = true,
};
target.ApplyTemplate();
AssertSingle(target);
target.SelectedIndex = 1;
AssertSingle(target);
}
target.ApplyTemplate();
Assert.Single(target.ItemContainerGenerator.Containers);
Assert.Single(target.Panel.Children);
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);
}
[Fact]
public void Should_Remove_NonCurrent_Page()
{
var target = new CarouselPresenter
{
Items = new[] { "foo", "bar" },
IsVirtualized = true,
SelectedIndex = 0,
};
[Fact]
public void Should_Remove_Controls_When_IsVirtualized_Is_False()
{
ObservableCollection<string> items = new ObservableCollection<string>();
var target = new CarouselPresenter
target.ApplyTemplate();
AssertSingle(target);
target.SelectedIndex = 1;
AssertSingle(target);
}
[Fact]
public void Should_Handle_Inserting_Item_At_SelectedItem()
{
Items = items,
SelectedIndex = 0,
IsVirtualized = false,
};
var items = new ObservableCollection<string>
{
"item0",
"item1",
"item2",
};
var target = new CarouselPresenter
{
Items = items,
SelectedIndex = 1,
IsVirtualized = true,
};
target.ApplyTemplate();
items.Insert(1, "item1a");
AssertSingle(target);
}
target.ApplyTemplate();
target.SelectedIndex = 0;
items.Add("foo");
target.SelectedIndex = 0;
[Fact]
public void Should_Handle_Inserting_Item_Before_SelectedItem()
{
var items = new ObservableCollection<string>
{
"item0",
"item1",
"item2",
};
var target = new CarouselPresenter
{
Items = items,
SelectedIndex = 2,
IsVirtualized = true,
};
target.ApplyTemplate();
items.Insert(1, "item1a");
AssertSingle(target);
}
[Fact]
public void Should_Do_Nothing_When_Inserting_Item_After_SelectedItem()
{
var items = new ObservableCollection<string>
{
"item0",
"item1",
"item2",
};
var target = new CarouselPresenter
{
Items = items,
SelectedIndex = 1,
IsVirtualized = true,
};
target.ApplyTemplate();
var child = AssertSingle(target);
items.Insert(2, "after");
Assert.Same(child, AssertSingle(target));
}
Assert.Single(target.ItemContainerGenerator.Containers);
Assert.Single(target.Panel.Children);
[Fact]
public void Should_Handle_Removing_Item_At_SelectedItem()
{
var items = new ObservableCollection<string>
{
"item0",
"item1",
"item2",
};
var target = new CarouselPresenter
{
Items = items,
SelectedIndex = 1,
IsVirtualized = true,
};
target.ApplyTemplate();
items.RemoveAt(1);
AssertSingle(target);
}
items.Add("bar");
Assert.Single(target.ItemContainerGenerator.Containers);
Assert.Single(target.Panel.Children);
[Fact]
public void Should_Handle_Removing_Item_Before_SelectedItem()
{
var items = new ObservableCollection<string>
{
"item0",
"item1",
"item2",
};
var target = new CarouselPresenter
{
Items = items,
SelectedIndex = 1,
IsVirtualized = true,
};
target.ApplyTemplate();
items.RemoveAt(0);
AssertSingle(target);
}
[Fact]
public void Should_Do_Nothing_When_Removing_Item_After_SelectedItem()
{
var items = new ObservableCollection<string>
{
"item0",
"item1",
"item2",
};
var target = new CarouselPresenter
{
Items = items,
SelectedIndex = 1,
IsVirtualized = true,
};
target.ApplyTemplate();
var child = AssertSingle(target);
items.RemoveAt(2);
Assert.Same(child, AssertSingle(target));
}
target.SelectedIndex = 1;
Assert.Equal(2, target.ItemContainerGenerator.Containers.Count());
Assert.Equal(2, target.Panel.Children.Count);
[Fact]
public void Should_Handle_Removing_SelectedItem_When_Its_Last()
{
var items = new ObservableCollection<string>
{
"item0",
"item1",
"item2",
};
var target = new CarouselPresenter
{
Items = items,
SelectedIndex = 2,
IsVirtualized = true,
};
target.ApplyTemplate();
items.RemoveAt(2);
Assert.Equal(1, target.SelectedIndex);
AssertSingle(target);
}
items.Remove(items[0]);
Assert.Single(target.ItemContainerGenerator.Containers);
Assert.Single(target.Panel.Children);
[Fact]
public void Should_Handle_Removing_Last_Item()
{
var items = new ObservableCollection<string>
{
"item0",
};
var target = new CarouselPresenter
{
Items = items,
SelectedIndex = 0,
IsVirtualized = true,
};
target.ApplyTemplate();
items.RemoveAt(0);
Assert.Empty(target.Panel.Children);
Assert.Empty(target.ItemContainerGenerator.Containers);
}
items.Remove(items[0]);
Assert.Empty(target.ItemContainerGenerator.Containers);
Assert.Empty(target.Panel.Children);
[Fact]
public void Should_Handle_Replacing_SelectedItem()
{
var items = new ObservableCollection<string>
{
"item0",
"item1",
"item2",
};
var target = new CarouselPresenter
{
Items = items,
SelectedIndex = 1,
IsVirtualized = true,
};
target.ApplyTemplate();
items[1] = "replaced";
AssertSingle(target);
}
[Fact]
public void Should_Do_Nothing_When_Replacing_Non_SelectedItem()
{
var items = new ObservableCollection<string>
{
"item0",
"item1",
"item2",
};
var target = new CarouselPresenter
{
Items = items,
SelectedIndex = 1,
IsVirtualized = true,
};
target.ApplyTemplate();
var child = AssertSingle(target);
items[0] = "replaced";
Assert.Same(child, AssertSingle(target));
}
[Fact]
public void Should_Handle_Moving_SelectedItem()
{
var items = new ObservableCollection<string>
{
"item0",
"item1",
"item2",
};
var target = new CarouselPresenter
{
Items = items,
SelectedIndex = 1,
IsVirtualized = true,
};
target.ApplyTemplate();
items.Move(1, 0);
AssertSingle(target);
}
private static IControl AssertSingle(CarouselPresenter target)
{
var items = (IList)target.Items;
var index = target.SelectedIndex;
var content = items[index];
var child = Assert.Single(target.Panel.Children);
var presenter = Assert.IsType<ContentPresenter>(child);
var container = Assert.Single(target.ItemContainerGenerator.Containers);
var visible = Assert.Single(target.Panel.Children.Where(x => x.IsVisible));
Assert.Same(child, container.ContainerControl);
Assert.Same(child, visible);
Assert.Equal(content, presenter.Content);
Assert.Equal(content, container.Item);
Assert.Equal(index, container.Index);
return child;
}
}
[Fact]
public void Should_Have_Correct_ItemsContainer_Index()
public class NonVirtualized
{
ObservableCollection<string> items = new ObservableCollection<string>();
[Fact]
public void Should_Initially_Materialize_All_Containers()
{
var target = new CarouselPresenter
{
Items = new[] { "foo", "bar" },
IsVirtualized = false,
};
target.ApplyTemplate();
AssertAll(target);
}
var target = new CarouselPresenter
[Fact]
public void Should_Initially_Show_Selected_Item()
{
Items = items,
SelectedIndex = 0,
IsVirtualized = false,
};
var target = new CarouselPresenter
{
Items = new[] { "foo", "bar" },
SelectedIndex = 1,
IsVirtualized = false,
};
target.ApplyTemplate();
AssertAll(target);
}
target.ApplyTemplate();
target.SelectedIndex = 0;
items.Add("foo");
target.SelectedIndex = 0;
Assert.Single(target.ItemContainerGenerator.Containers);
Assert.Single(target.Panel.Children);
items.Add("bar");
Assert.Single(target.ItemContainerGenerator.Containers);
Assert.Single(target.Panel.Children);
target.SelectedIndex = 1;
Assert.Equal(2, target.ItemContainerGenerator.Containers.Count());
Assert.Equal(2, target.Panel.Children.Count);
Assert.Equal(0, target.ItemContainerGenerator.Containers.First().Index);
items.Remove(items[0]);
Assert.Single(target.ItemContainerGenerator.Containers);
Assert.Single(target.Panel.Children);
Assert.Equal(0, target.ItemContainerGenerator.Containers.First().Index);
items.Remove(items[0]);
Assert.Empty(target.ItemContainerGenerator.Containers);
Assert.Empty(target.Panel.Children);
[Fact]
public void Switching_To_Non_Virtualized_Should_Reset_Containers()
{
var target = new CarouselPresenter
{
Items = new[] { "foo", "bar" },
SelectedIndex = 0,
IsVirtualized = true,
};
target.ApplyTemplate();
target.IsVirtualized = false;
AssertAll(target);
}
[Fact]
public void Changing_SelectedIndex_Should_Show_Page()
{
var target = new CarouselPresenter
{
Items = new[] { "foo", "bar" },
SelectedIndex = 0,
IsVirtualized = false,
};
target.ApplyTemplate();
AssertAll(target);
target.SelectedIndex = 1;
AssertAll(target);
}
[Fact]
public void Should_Handle_Inserting_Item_At_SelectedItem()
{
var items = new ObservableCollection<string>
{
"item0",
"item1",
"item2",
};
var target = new CarouselPresenter
{
Items = items,
SelectedIndex = 1,
IsVirtualized = false,
};
target.ApplyTemplate();
items.Insert(1, "item1a");
AssertAll(target);
}
[Fact]
public void Should_Handle_Inserting_Item_Before_SelectedItem()
{
var items = new ObservableCollection<string>
{
"item0",
"item1",
"item2",
};
var target = new CarouselPresenter
{
Items = items,
SelectedIndex = 2,
IsVirtualized = false,
};
target.ApplyTemplate();
items.Insert(1, "item1a");
AssertAll(target);
}
[Fact]
public void Should_Do_Handle_Inserting_Item_After_SelectedItem()
{
var items = new ObservableCollection<string>
{
"item0",
"item1",
"item2",
};
var target = new CarouselPresenter
{
Items = items,
SelectedIndex = 1,
IsVirtualized = false,
};
target.ApplyTemplate();
items.Insert(2, "after");
AssertAll(target);
}
[Fact]
public void Should_Handle_Removing_Item_At_SelectedItem()
{
var items = new ObservableCollection<string>
{
"item0",
"item1",
"item2",
};
var target = new CarouselPresenter
{
Items = items,
SelectedIndex = 1,
IsVirtualized = false,
};
target.ApplyTemplate();
items.RemoveAt(1);
AssertAll(target);
}
[Fact]
public void Should_Handle_Removing_Item_Before_SelectedItem()
{
var items = new ObservableCollection<string>
{
"item0",
"item1",
"item2",
};
var target = new CarouselPresenter
{
Items = items,
SelectedIndex = 1,
IsVirtualized = false,
};
target.ApplyTemplate();
items.RemoveAt(0);
AssertAll(target);
}
[Fact]
public void Should_Handle_Removing_Item_After_SelectedItem()
{
var items = new ObservableCollection<string>
{
"item0",
"item1",
"item2",
};
var target = new CarouselPresenter
{
Items = items,
SelectedIndex = 1,
IsVirtualized = false,
};
target.ApplyTemplate();
items.RemoveAt(2);
AssertAll(target);
}
[Fact]
public void Should_Handle_Removing_SelectedItem_When_Its_Last()
{
var items = new ObservableCollection<string>
{
"item0",
"item1",
"item2",
};
var target = new CarouselPresenter
{
Items = items,
SelectedIndex = 2,
IsVirtualized = false,
};
target.ApplyTemplate();
items.RemoveAt(2);
Assert.Equal(1, target.SelectedIndex);
AssertAll(target);
}
[Fact]
public void Should_Handle_Removing_Last_Item()
{
var items = new ObservableCollection<string>
{
"item0",
};
var target = new CarouselPresenter
{
Items = items,
SelectedIndex = 0,
IsVirtualized = false,
};
target.ApplyTemplate();
items.RemoveAt(0);
Assert.Empty(target.Panel.Children);
Assert.Empty(target.ItemContainerGenerator.Containers);
}
[Fact]
public void Should_Handle_Replacing_SelectedItem()
{
var items = new ObservableCollection<string>
{
"item0",
"item1",
"item2",
};
var target = new CarouselPresenter
{
Items = items,
SelectedIndex = 1,
IsVirtualized = false,
};
target.ApplyTemplate();
items[1] = "replaced";
AssertAll(target);
}
[Fact]
public void Should_Handle_Moving_SelectedItem()
{
var items = new ObservableCollection<string>
{
"item0",
"item1",
"item2",
};
var target = new CarouselPresenter
{
Items = items,
SelectedIndex = 1,
IsVirtualized = false,
};
target.ApplyTemplate();
items.Move(1, 0);
AssertAll(target);
}
private static void AssertAll(CarouselPresenter target)
{
var items = (IList)target.Items;
Assert.Equal(items?.Count ?? 0, target.Panel.Children.Count);
Assert.Equal(items?.Count ?? 0, target.ItemContainerGenerator.Containers.Count());
for (var i = 0; i < items?.Count; ++i)
{
var content = items[i];
var child = target.Panel.Children[i];
var presenter = Assert.IsType<ContentPresenter>(child);
var container = target.ItemContainerGenerator.ContainerFromIndex(i);
Assert.Same(child, container);
Assert.Equal(i == target.SelectedIndex, child.IsVisible);
Assert.Equal(content, presenter.Content);
Assert.Equal(i, target.ItemContainerGenerator.IndexFromContainer(container));
}
}
}
private class TestItem : ContentControl

Loading…
Cancel
Save