maui-linux/Xamarin.Forms.Core.UnitTests/ListViewTests.cs

1528 строки
38 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
using NUnit.Framework;
using Xamarin.Forms.Internals;
namespace Xamarin.Forms.Core.UnitTests
{
[TestFixture]
public class ListViewTests : BaseTestFixture
{
[TearDown]
public override void TearDown()
{
base.TearDown ();
Device.PlatformServices = null;
Device.Info = null;
}
[SetUp]
public override void Setup ()
{
base.Setup ();
Device.PlatformServices = new MockPlatformServices ();
Device.Info = new TestDeviceInfo ();
}
[Test]
public void TestConstructor ()
{
var listView = new ListView ();
Assert.Null (listView.ItemsSource);
Assert.Null (listView.ItemTemplate);
Assert.AreEqual (LayoutOptions.FillAndExpand, listView.HorizontalOptions);
Assert.AreEqual (LayoutOptions.FillAndExpand, listView.VerticalOptions);
}
internal class ListItem
{
public string Name { get; set; }
public string Description { get; set; }
}
[Test]
public void TestTemplating ()
{
var cellTemplate = new DataTemplate (typeof (TextCell));
cellTemplate.SetBinding (TextCell.TextProperty, new Binding ("Name"));
cellTemplate.SetBinding (TextCell.DetailProperty, new Binding ("Description"));
var listView = new ListView {
ItemsSource = new[] {
new ListItem {Name = "Foo", Description = "Bar"},
new ListItem {Name = "Baz", Description = "Raz"}
},
ItemTemplate = cellTemplate
};
var cell = (Cell)listView.ItemTemplate.CreateContent ();
var textCell = (TextCell)cell;
cell.BindingContext = listView.ItemsSource.OfType<ListItem> ().First ();
Assert.AreEqual ("Foo", textCell.Text);
Assert.AreEqual ("Bar", textCell.Detail);
}
[Test]
public void TemplateNullObject()
{
var listView = new ListView {
ItemsSource = new object[] {
null
}
};
Cell cell = listView.TemplatedItems[0];
Assert.That (cell, Is.Not.Null);
Assert.That (cell, Is.InstanceOf<TextCell>());
Assert.That (((TextCell) cell).Text, Is.Null);
}
[Test]
[Description("Setting BindingContext should trickle down to Header and Footer.")]
public void SettingBindingContextPassesToHeaderAndFooter()
{
var bc = new object();
var header = new BoxView();
var footer = new BoxView();
var listView = new ListView
{
Header = header,
Footer = footer,
BindingContext = bc,
};
Assert.That(header.BindingContext, Is.SameAs(bc));
Assert.That(footer.BindingContext, Is.SameAs(bc));
}
[Test]
[Description("Setting Header and Footer should pass BindingContext.")]
public void SettingHeaderFooterPassesBindingContext()
{
var bc = new object();
var listView = new ListView
{
BindingContext = bc,
};
var header = new BoxView();
var footer = new BoxView();
listView.Footer = footer;
listView.Header = header;
Assert.That(header.BindingContext, Is.SameAs(bc));
Assert.That(footer.BindingContext, Is.SameAs(bc));
}
[Test]
[Description ("Setting GroupDisplayBinding or GroupHeaderTemplate when the other is set should set the other one to null.")]
public void SettingGroupHeaderTemplateSetsDisplayBindingToNull()
{
var listView = new ListView {
GroupDisplayBinding = new Binding ("Path")
};
listView.GroupHeaderTemplate = new DataTemplate (typeof (TextCell));
Assert.That (listView.GroupDisplayBinding, Is.Null);
}
[Test]
[Description ("Setting GroupDisplayBinding or GroupHeaderTemplate when the other is set should set the other one to null.")]
public void SettingGroupDisplayBindingSetsHeaderTemplateToNull()
{
var listView = new ListView {
GroupHeaderTemplate = new DataTemplate (typeof (TextCell))
};
listView.GroupDisplayBinding = new Binding ("Path");
Assert.That (listView.GroupHeaderTemplate, Is.Null);
}
[Test]
[Description ("You should be able to set ItemsSource without having set the other properties first without issue")]
public void SettingItemsSourceWithoutBindingsOrItemsSource()
{
var listView = new ListView {
IsGroupingEnabled = true
};
Assert.That (() => listView.ItemsSource = new[] { new[] { new object() } }, Throws.Nothing);
}
[Test]
public void DefaultGroupHeaderTemplates()
{
var items = new[] { new[] { new object() } };
var listView = new ListView {
IsGroupingEnabled = true,
ItemsSource = items
};
var til = (TemplatedItemsList<ItemsView<Cell>, Cell>)((IList)listView.TemplatedItems)[0];
Cell cell = til.HeaderContent;
Assert.That (cell, Is.Not.Null);
Assert.That (cell, Is.InstanceOf<TextCell>());
Assert.That (((TextCell) cell).Text, Is.EqualTo (items[0].ToString()));
}
[Test]
[Description ("Tapping a different item (row) that is equal to the current item selection should still raise ItemSelected")]
public void NotifyRowTappedDifferentIndex()
{
string item = "item";
var listView = new ListView {
ItemsSource = new[] {
item,
item
}
};
listView.NotifyRowTapped (0);
bool raised = false;
listView.ItemSelected += (sender, arg) => raised = true;
listView.NotifyRowTapped (1);
Assert.That (raised, Is.True, "ItemSelected was not raised");
}
[Test]
public void DoesNotCrashWhenAddingToSource ()
{
var items = new ObservableCollection<string> {
"Foo",
"Bar",
"Baz"
};
var listView = new ListView {
ItemsSource = items,
ItemTemplate = new DataTemplate(typeof(TextCell))
};
Assert.DoesNotThrow (() => items.Add ("Blah"));
}
[Test]
public void DoesNotThrowWhenMovingInSource ()
{
var items = new ObservableCollection<string> {
"Foo",
"Bar",
"Baz"
};
var listView = new ListView {
ItemsSource = items,
ItemTemplate = new DataTemplate (typeof (TextCell))
};
Assert.DoesNotThrow (() => items.Move (0, 1));
}
[Test]
[Description ("A cell being tapped from the UI should raise both tapped events, but not change ItemSelected")]
public void NotifyTappedSameItem()
{
int cellTapped = 0;
int itemTapped = 0;
int itemSelected = 0;
var listView = new ListView {
ItemsSource = new[] { "item" },
ItemTemplate = new DataTemplate (() => {
var cell = new TextCell();
cell.Tapped += (s, e) => {
cellTapped++;
};
return cell;
})
};
listView.ItemTapped += (sender, arg) => itemTapped++;
listView.ItemSelected += (sender, arg) => itemSelected++;
listView.NotifyRowTapped (0);
Assert.That (cellTapped, Is.EqualTo (1), "Cell.Tapped was not raised");
Assert.That (itemTapped, Is.EqualTo (1), "ListView.ItemTapped was not raised");
Assert.That (itemSelected, Is.EqualTo (1), "ListView.ItemSelected was not raised");
listView.NotifyRowTapped (0);
Assert.That (cellTapped, Is.EqualTo (2), "Cell.Tapped was not raised a second time");
Assert.That (itemTapped, Is.EqualTo (2), "ListView.ItemTapped was not raised a second time");
Assert.That (itemSelected, Is.EqualTo (1), "ListView.ItemSelected was raised a second time");
}
[Test]
public void ScrollTo()
{
var listView = new ListView {
IsPlatformEnabled = true,
Platform = new UnitPlatform()
};
object item = new object();
bool requested = false;
listView.ScrollToRequested += (sender, args) => {
requested = true;
Assert.That (args.Item, Is.SameAs (item));
Assert.That (args.Group, Is.Null);
Assert.That (args.Position, Is.EqualTo (ScrollToPosition.Center));
Assert.That (args.ShouldAnimate, Is.EqualTo (true));
};
listView.ScrollTo (item, ScrollToPosition.Center, animated: true);
Assert.That (requested, Is.True);
}
[Test]
public void ScrollToDelayed()
{
var listView = new ListView();
object item = new object();
bool requested = false;
listView.ScrollToRequested += (sender, args) => {
requested = true;
Assert.That (args.Item, Is.SameAs (item));
Assert.That (args.Group, Is.Null);
Assert.That (args.Position, Is.EqualTo (ScrollToPosition.Center));
Assert.That (args.ShouldAnimate, Is.EqualTo (true));
};
listView.ScrollTo (item, ScrollToPosition.Center, animated: true);
Assert.That (requested, Is.False);
listView.IsPlatformEnabled = true;
listView.Platform = new UnitPlatform();
Assert.That (requested, Is.True);
}
[Test]
public void ScrollToGroup()
{
// Fake a renderer so we pass along messages right away
var listView = new ListView {
IsPlatformEnabled = true,
Platform = new UnitPlatform(),
IsGroupingEnabled = true
};
object item = new object();
object group = new object();
bool requested = false;
listView.ScrollToRequested += (sender, args) => {
requested = true;
Assert.That (args.Item, Is.SameAs (item));
Assert.That (args.Group, Is.SameAs (group));
Assert.That (args.Position, Is.EqualTo (ScrollToPosition.Center));
Assert.That (args.ShouldAnimate, Is.EqualTo (true));
};
listView.ScrollTo (item, group, ScrollToPosition.Center, animated: true);
Assert.That (requested, Is.True);
}
[Test]
public void ScrollToInvalid()
{
var listView = new ListView {
IsPlatformEnabled = true,
Platform = new UnitPlatform()
};
Assert.That (() => listView.ScrollTo (new object(), (ScrollToPosition) 500, true), Throws.ArgumentException);
Assert.That (() => listView.ScrollTo (new object(), new object(), ScrollToPosition.Start, true), Throws.InvalidOperationException);
listView.IsGroupingEnabled = true;
Assert.That (() => listView.ScrollTo (new object(), new object(), (ScrollToPosition) 500, true), Throws.ArgumentException);
}
[Test]
public void GetSizeRequest ()
{
var listView = new ListView {
IsPlatformEnabled = true,
Platform = new UnitPlatform (),
HasUnevenRows = false,
RowHeight = 50,
ItemsSource = Enumerable.Range (0, 20).ToList ()
};
var sizeRequest = listView.GetSizeRequest (double.PositiveInfinity, double.PositiveInfinity);
Assert.AreEqual (40, sizeRequest.Minimum.Width);
Assert.AreEqual (40, sizeRequest.Minimum.Height);
Assert.AreEqual (50, sizeRequest.Request.Width);
Assert.AreEqual (50 * 20, sizeRequest.Request.Height);
}
[Test]
public void GetSizeRequestUneven ()
{
var listView = new ListView {
IsPlatformEnabled = true,
Platform = new UnitPlatform (),
HasUnevenRows = true,
RowHeight = 50,
ItemsSource = Enumerable.Range (0, 20).ToList ()
};
var sizeRequest = listView.GetSizeRequest (double.PositiveInfinity, double.PositiveInfinity);
Assert.AreEqual (40, sizeRequest.Minimum.Width);
Assert.AreEqual (40, sizeRequest.Minimum.Height);
Assert.AreEqual (50, sizeRequest.Request.Width);
Assert.AreEqual (100, sizeRequest.Request.Height);
}
public class ListItemValue : IComparable<ListItemValue>
{
public string Name { get; private set; }
public ListItemValue (string name)
{
Name = name;
}
int IComparable<ListItemValue>.CompareTo (ListItemValue value)
{
return Name.CompareTo (value.Name);
}
public string Label
{
get { return Name[0].ToString (); }
}
}
public class ListItemCollection : ObservableCollection<ListItemValue>
{
public string Title { get; private set; }
public ListItemCollection (string title)
{
Title = title;
}
public static List<ListItemValue> GetSortedData ()
{
var items = ListItems;
items.Sort ();
return items;
}
// Data used to populate our list.
static readonly List<ListItemValue> ListItems = new List<ListItemValue> () {
new ListItemValue ("Babbage"),
new ListItemValue ("Boole"),
new ListItemValue ("Berners-Lee"),
new ListItemValue ("Atanasoff"),
new ListItemValue ("Allen"),
new ListItemValue ("Cormack"),
new ListItemValue ("Cray"),
new ListItemValue ("Dijkstra"),
new ListItemValue ("Dix"),
new ListItemValue ("Dewey"),
new ListItemValue ("Erdos"),
};
}
public class TestCell : TextCell
{
public static int NumberOfCells = 0;
public TestCell ()
{
Interlocked.Increment (ref NumberOfCells);
}
~TestCell ()
{
Interlocked.Decrement (ref NumberOfCells);
}
}
ObservableCollection<ListItemCollection> SetupList ()
{
var allListItemGroups = new ObservableCollection<ListItemCollection> ();
foreach (var item in ListItemCollection.GetSortedData ()) {
// Attempt to find any existing groups where theg group title matches the first char of our ListItem's name.
var listItemGroup = allListItemGroups.FirstOrDefault (g => g.Title == item.Label);
// If the list group does not exist, we create it.
if (listItemGroup == null) {
listItemGroup = new ListItemCollection (item.Label) { item };
allListItemGroups.Add (listItemGroup);
} else {
// If the group does exist, we simply add the demo to the existing group.
listItemGroup.Add (item);
}
}
return allListItemGroups;
}
[Test]
public void UncollectableHeaderReferences ()
{
var list = new ListView {
Platform = new UnitPlatform (),
IsPlatformEnabled = true,
ItemTemplate = new DataTemplate (typeof (TextCell)) {
Bindings = {
{TextCell.TextProperty, new Binding ("Name")}
}
},
GroupHeaderTemplate = new DataTemplate (typeof (TestCell)) {
Bindings = {
{TextCell.TextProperty, new Binding ("Title")}
}
},
IsGroupingEnabled = true,
ItemsSource = SetupList (),
};
Assert.AreEqual (5, TestCell.NumberOfCells);
var newList1 = SetupList ();
var newList2 = SetupList ();
for (var i = 0; i < 400; i++) {
list.ItemsSource = i % 2 > 0 ? newList1 : newList2;
// grab a header just so we can be sure its reailized
var header = list.TemplatedItems.GetGroup (0).HeaderContent;
}
GC.Collect ();
GC.WaitForPendingFinalizers ();
// use less or equal because mono will keep the last header var alive no matter what
Assert.True (TestCell.NumberOfCells <= 6);
var keepAlive = list.ToString ();
}
[Test]
public void CollectionChangedMultipleFires ()
{
var source = new ObservableCollection<string> {
"Foo",
"Bar"
};
var list = new ListView {
Platform = new UnitPlatform (),
IsPlatformEnabled = true,
ItemsSource = source,
ItemTemplate = new DataTemplate (typeof (TextCell))
};
int fireCount = 0;
list.TemplatedItems.CollectionChanged += (sender, args) => {
fireCount++;
};
source.Add ("Baz");
Assert.AreEqual (1, fireCount);
}
[Test]
public void GroupedCollectionChangedMultipleFires ()
{
var source = new ObservableCollection<ObservableCollection <string>> {
new ObservableCollection<string> {"Foo"},
new ObservableCollection<string> {"Bar"}
};
var list = new ListView {
Platform = new UnitPlatform (),
IsPlatformEnabled = true,
IsGroupingEnabled = true,
ItemsSource = source,
ItemTemplate = new DataTemplate (typeof (TextCell)) {
Bindings = {
{TextCell.TextProperty, new Binding (".") }
}
}
};
int fireCount = 0;
list.TemplatedItems.GroupedCollectionChanged += (sender, args) => {
fireCount++;
};
source[0].Add ("Baz");
Assert.AreEqual (1, fireCount);
}
[Test]
public void HeaderAsView()
{
var label = new Label { Text = "header" };
var lv = new ListView {
Header = label
};
IListViewController controller = lv;
Assert.That (controller.HeaderElement, Is.SameAs (label));
}
[Test]
public void HeaderTemplated()
{
var lv = new ListView {
Header = "header",
HeaderTemplate = new DataTemplate(typeof(Label)) {
Bindings = {
{ Label.TextProperty, new Binding (".") }
}
}
};
IListViewController controller = lv;
Assert.That (controller.HeaderElement, Is.Not.Null);
Assert.That (controller.HeaderElement, Is.InstanceOf<Label>());
Assert.That (((Label) controller.HeaderElement).Text, Is.EqualTo (lv.Header));
}
[Test]
public void HeaderTemplateThrowsIfCell ()
{
var lv = new ListView ();
Assert.Throws<ArgumentException> (() => lv.HeaderTemplate = new DataTemplate (typeof (TextCell)));
}
[Test]
public void FooterTemplateThrowsIfCell ()
{
var lv = new ListView ();
Assert.Throws<ArgumentException> (() => lv.FooterTemplate = new DataTemplate (typeof (TextCell)));
}
[Test]
public void HeaderObjectTemplatedChanged()
{
var lv = new ListView {
Header = "header",
HeaderTemplate = new DataTemplate (typeof (Label)) {
Bindings = {
{ Label.TextProperty, new Binding (".") }
}
}
};
bool changed = false, changing = false;
lv.PropertyChanging += (sender, args) => {
if (args.PropertyName == "HeaderElement")
changing = true;
};
lv.PropertyChanged += (sender, args) => {
if (args.PropertyName == "HeaderElement")
changed = true;
};
lv.Header = "newheader";
Assert.That (changing, Is.False);
Assert.That (changed, Is.False);
IListViewController controller = lv;
Assert.That (controller.HeaderElement, Is.Not.Null);
Assert.That (controller.HeaderElement, Is.InstanceOf<Label>());
Assert.That (((Label) controller.HeaderElement).Text, Is.EqualTo (lv.Header));
}
[Test]
public void HeaderViewChanged()
{
var lv = new ListView {
Header = new Label { Text = "header" }
};
bool changed = false, changing = false;
lv.PropertyChanging += (sender, args) => {
if (args.PropertyName == "HeaderElement")
changing = true;
};
lv.PropertyChanged += (sender, args) => {
if (args.PropertyName == "HeaderElement")
changed = true;
};
Label label = new Label { Text = "header" };
lv.Header = label;
Assert.That (changing, Is.True);
Assert.That (changed, Is.True);
IListViewController controller = lv;
Assert.That (controller.HeaderElement, Is.SameAs (label));
}
[Test]
public void HeaderTemplateChanged()
{
var lv = new ListView {
Header = "header",
HeaderTemplate = new DataTemplate(typeof(Label)) {
Bindings = {
{ Label.TextProperty, new Binding (".") }
}
}
};
bool changed = false, changing = false;
lv.PropertyChanging += (sender, args) => {
if (args.PropertyName == "HeaderElement")
changing = true;
};
lv.PropertyChanged += (sender, args) => {
if (args.PropertyName == "HeaderElement")
changed = true;
};
lv.HeaderTemplate = new DataTemplate (typeof (Entry)) {
Bindings = {
{ Entry.TextProperty, new Binding (".") }
}
};
Assert.That (changing, Is.True);
Assert.That (changed, Is.True);
IListViewController controller = lv;
Assert.That (controller.HeaderElement, Is.Not.Null);
Assert.That (controller.HeaderElement, Is.InstanceOf<Entry>());
Assert.That (((Entry) controller.HeaderElement).Text, Is.EqualTo (lv.Header));
}
[Test]
public void HeaderTemplateChangedNoObject()
{
var lv = new ListView {
HeaderTemplate = new DataTemplate(typeof(Label)) {
Bindings = {
{ Label.TextProperty, new Binding (".") }
}
}
};
bool changed = false, changing = false;
lv.PropertyChanging += (sender, args) => {
if (args.PropertyName == "HeaderElement")
changing = true;
};
lv.PropertyChanged += (sender, args) => {
if (args.PropertyName == "HeaderElement")
changed = true;
};
lv.HeaderTemplate = new DataTemplate (typeof (Entry)) {
Bindings = {
{ Entry.TextProperty, new Binding (".") }
}
};
Assert.That (changing, Is.False);
Assert.That (changed, Is.False);
IListViewController controller = lv;
Assert.That (controller.HeaderElement, Is.Null);
}
[Test]
public void HeaderNoTemplate()
{
var lv = new ListView {
Header = "foo"
};
IListViewController controller = lv;
Assert.That (controller.HeaderElement, Is.Not.Null);
Assert.That (controller.HeaderElement, Is.InstanceOf<Label>());
Assert.That (((Label) controller.HeaderElement).Text, Is.EqualTo (lv.Header));
}
[Test]
public void HeaderChangedNoTemplate()
{
var lv = new ListView {
Header = "foo"
};
bool changed = false, changing = false;
lv.PropertyChanging += (sender, args) => {
if (args.PropertyName == "HeaderElement")
changing = true;
};
lv.PropertyChanged += (sender, args) => {
if (args.PropertyName == "HeaderElement")
changed = true;
};
lv.Header = "bar";
Assert.That (changing, Is.True);
Assert.That (changed, Is.True);
IListViewController controller = lv;
Assert.That (controller.HeaderElement, Is.Not.Null);
Assert.That (controller.HeaderElement, Is.InstanceOf<Label>());
Assert.That (((Label) controller.HeaderElement).Text, Is.EqualTo (lv.Header));
}
[Test]
public void HeaderViewButTemplated()
{
var lv = new ListView {
Header = new Entry { Text = "foo" },
HeaderTemplate = new DataTemplate (typeof(Label)) {
Bindings = {
{ Label.TextProperty, new Binding ("Text") }
}
}
};
IListViewController controller = lv;
Assert.That (controller.HeaderElement, Is.Not.Null);
Assert.That (controller.HeaderElement, Is.InstanceOf<Label>());
Assert.That (((Label) controller.HeaderElement).Text, Is.EqualTo (((Entry)lv.Header).Text));
}
[Test]
public void HeaderTemplatedChangedToView()
{
var lv = new ListView {
Header = new Entry { Text = "foo" },
HeaderTemplate = new DataTemplate (typeof(Label)) {
Bindings = {
{ Label.TextProperty, new Binding ("Text") }
}
}
};
bool changed = false, changing = false;
lv.PropertyChanging += (sender, args) => {
if (args.PropertyName == "HeaderElement")
changing = true;
};
lv.PropertyChanged += (sender, args) => {
if (args.PropertyName == "HeaderElement")
changed = true;
};
lv.HeaderTemplate = null;
Assert.That (changing, Is.True);
Assert.That (changed, Is.True);
IListViewController controller = lv;
Assert.That (controller.HeaderElement, Is.Not.Null);
Assert.That (controller.HeaderElement, Is.InstanceOf<Entry>());
Assert.That (((Entry) controller.HeaderElement).Text, Is.EqualTo (((Entry)lv.Header).Text));
}
[Test]
public void HeaderTemplatedSetToNull()
{
var lv = new ListView {
Header = "header",
HeaderTemplate = new DataTemplate(typeof(Label)) {
Bindings = {
{ Label.TextProperty, new Binding (".") }
}
}
};
bool changed = false, changing = false;
lv.PropertyChanging += (sender, args) => {
if (args.PropertyName == "HeaderElement")
changing = true;
};
lv.PropertyChanged += (sender, args) => {
if (args.PropertyName == "HeaderElement")
changed = true;
};
lv.Header = null;
Assert.That (changing, Is.True);
Assert.That (changed, Is.True);
IListViewController controller = lv;
Assert.That (controller.HeaderElement, Is.Null);
}
[Test]
public void FooterAsView()
{
var label = new Label { Text = "footer" };
var lv = new ListView {
Footer = label
};
IListViewController controller = lv;
Assert.That (controller.FooterElement, Is.SameAs (label));
}
[Test]
public void FooterTemplated()
{
var lv = new ListView {
Footer = "footer",
FooterTemplate = new DataTemplate(typeof(Label)) {
Bindings = {
{ Label.TextProperty, new Binding (".") }
}
}
};
IListViewController controller = lv;
Assert.That (controller.FooterElement, Is.Not.Null);
Assert.That (controller.FooterElement, Is.InstanceOf<Label>());
Assert.That (((Label) controller.FooterElement).Text, Is.EqualTo (lv.Footer));
}
[Test]
public void FooterObjectTemplatedChanged()
{
var lv = new ListView {
Footer = "footer",
FooterTemplate = new DataTemplate (typeof (Label)) {
Bindings = {
{ Label.TextProperty, new Binding (".") }
}
}
};
bool changed = false, changing = false;
lv.PropertyChanging += (sender, args) => {
if (args.PropertyName == "FooterElement")
changing = true;
};
lv.PropertyChanged += (sender, args) => {
if (args.PropertyName == "FooterElement")
changed = true;
};
lv.Footer = "newfooter";
Assert.That (changing, Is.False);
Assert.That (changed, Is.False);
IListViewController controller = lv;
Assert.That (controller.FooterElement, Is.Not.Null);
Assert.That (controller.FooterElement, Is.InstanceOf<Label>());
Assert.That (((Label) controller.FooterElement).Text, Is.EqualTo (lv.Footer));
}
[Test]
public void FooterViewChanged()
{
var lv = new ListView {
Footer = new Label { Text = "footer" }
};
bool changed = false, changing = false;
lv.PropertyChanging += (sender, args) => {
if (args.PropertyName == "FooterElement")
changing = true;
};
lv.PropertyChanged += (sender, args) => {
if (args.PropertyName == "FooterElement")
changed = true;
};
Label label = new Label { Text = "footer" };
lv.Footer = label;
Assert.That (changing, Is.True);
Assert.That (changed, Is.True);
IListViewController controller = lv;
Assert.That (controller.FooterElement, Is.SameAs (label));
}
[Test]
public void FooterTemplateChanged()
{
var lv = new ListView {
Footer = "footer",
FooterTemplate = new DataTemplate(typeof(Label)) {
Bindings = {
{ Label.TextProperty, new Binding (".") }
}
}
};
bool changed = false, changing = false;
lv.PropertyChanging += (sender, args) => {
if (args.PropertyName == "FooterElement")
changing = true;
};
lv.PropertyChanged += (sender, args) => {
if (args.PropertyName == "FooterElement")
changed = true;
};
lv.FooterTemplate = new DataTemplate (typeof (Entry)) {
Bindings = {
{ Entry.TextProperty, new Binding (".") }
}
};
Assert.That (changing, Is.True);
Assert.That (changed, Is.True);
IListViewController controller = lv;
Assert.That (controller.FooterElement, Is.Not.Null);
Assert.That (controller.FooterElement, Is.InstanceOf<Entry>());
Assert.That (((Entry) controller.FooterElement).Text, Is.EqualTo (lv.Footer));
}
[Test]
public void FooterTemplateChangedNoObject()
{
var lv = new ListView {
FooterTemplate = new DataTemplate(typeof(Label)) {
Bindings = {
{ Label.TextProperty, new Binding (".") }
}
}
};
bool changed = false, changing = false;
lv.PropertyChanging += (sender, args) => {
if (args.PropertyName == "FooterElement")
changing = true;
};
lv.PropertyChanged += (sender, args) => {
if (args.PropertyName == "FooterElement")
changed = true;
};
lv.FooterTemplate = new DataTemplate (typeof (Entry)) {
Bindings = {
{ Entry.TextProperty, new Binding (".") }
}
};
Assert.That (changing, Is.False);
Assert.That (changed, Is.False);
IListViewController controller = lv;
Assert.That (controller.FooterElement, Is.Null);
}
[Test]
public void FooterNoTemplate()
{
var lv = new ListView {
Footer = "foo"
};
IListViewController controller = lv;
Assert.That (controller.FooterElement, Is.Not.Null);
Assert.That (controller.FooterElement, Is.InstanceOf<Label>());
Assert.That (((Label) controller.FooterElement).Text, Is.EqualTo (lv.Footer));
}
[Test]
public void FooterChangedNoTemplate()
{
var lv = new ListView {
Footer = "foo"
};
bool changed = false, changing = false;
lv.PropertyChanging += (sender, args) => {
if (args.PropertyName == "FooterElement")
changing = true;
};
lv.PropertyChanged += (sender, args) => {
if (args.PropertyName == "FooterElement")
changed = true;
};
lv.Footer = "bar";
Assert.That (changing, Is.True);
Assert.That (changed, Is.True);
IListViewController controller = lv;
Assert.That (controller.FooterElement, Is.Not.Null);
Assert.That (controller.FooterElement, Is.InstanceOf<Label>());
Assert.That (((Label) controller.FooterElement).Text, Is.EqualTo (lv.Footer));
}
[Test]
public void FooterViewButTemplated()
{
var lv = new ListView {
Footer = new Entry { Text = "foo" },
FooterTemplate = new DataTemplate (typeof(Label)) {
Bindings = {
{ Label.TextProperty, new Binding ("Text") }
}
}
};
IListViewController controller = lv;
Assert.That (controller.FooterElement, Is.Not.Null);
Assert.That (controller.FooterElement, Is.InstanceOf<Label>());
Assert.That (((Label) controller.FooterElement).Text, Is.EqualTo (((Entry)lv.Footer).Text));
}
[Test]
public void FooterTemplatedChangedToView()
{
var lv = new ListView {
Footer = new Entry { Text = "foo" },
FooterTemplate = new DataTemplate (typeof(Label)) {
Bindings = {
{ Label.TextProperty, new Binding ("Text") }
}
}
};
bool changed = false, changing = false;
lv.PropertyChanging += (sender, args) => {
if (args.PropertyName == "FooterElement")
changing = true;
};
lv.PropertyChanged += (sender, args) => {
if (args.PropertyName == "FooterElement")
changed = true;
};
lv.FooterTemplate = null;
Assert.That (changing, Is.True);
Assert.That (changed, Is.True);
IListViewController controller = lv;
Assert.That (controller.FooterElement, Is.Not.Null);
Assert.That (controller.FooterElement, Is.InstanceOf<Entry>());
Assert.That (((Entry) controller.FooterElement).Text, Is.EqualTo (((Entry)lv.Footer).Text));
}
[Test]
public void FooterTemplatedSetToNull()
{
var lv = new ListView {
Footer = "footer",
FooterTemplate = new DataTemplate(typeof(Label)) {
Bindings = {
{ Label.TextProperty, new Binding (".") }
}
}
};
bool changed = false, changing = false;
lv.PropertyChanging += (sender, args) => {
if (args.PropertyName == "FooterElement")
changing = true;
};
lv.PropertyChanged += (sender, args) => {
if (args.PropertyName == "FooterElement")
changed = true;
};
lv.Footer = null;
Assert.That (changing, Is.True);
Assert.That (changed, Is.True);
IListViewController controller = lv;
Assert.That (controller.FooterElement, Is.Null);
}
[Test]
public void BeginRefresh()
{
var lv = new ListView();
bool refreshing = false;
lv.Refreshing += (sender, args) => {
refreshing = true;
};
lv.BeginRefresh();
Assert.That (refreshing, Is.True);
Assert.That (lv.IsRefreshing, Is.True);
}
[Test]
public void SendRefreshing()
{
var lv = new ListView();
bool refreshing = false;
lv.Refreshing += (sender, args) => {
refreshing = true;
};
IListViewController controller = lv;
controller.SendRefreshing();
Assert.That (refreshing, Is.True);
Assert.That (lv.IsRefreshing, Is.True);
}
[Test]
public void RefreshCommand()
{
var lv = new ListView();
bool commandExecuted = false;
Command refresh = new Command (() => commandExecuted = true);
lv.RefreshCommand = refresh;
IListViewController controller = lv;
controller.SendRefreshing();
Assert.That (commandExecuted, Is.True);
}
[TestCase (true)]
[TestCase (false)]
public void RefreshCommandCanExecute (bool initial)
{
var lv = new ListView { IsPullToRefreshEnabled = initial };
bool commandExecuted = false;
Command refresh = new Command (() => commandExecuted = true,
() => !initial);
lv.RefreshCommand = refresh;
Assert.That ((lv as IListViewController).RefreshAllowed, Is.EqualTo (!initial));
}
[TestCase (true)]
[TestCase (false)]
public void RefreshCommandCanExecuteChanges (bool initial)
{
var lv = new ListView { IsPullToRefreshEnabled = initial };
bool commandExecuted = false;
Command refresh = new Command (() => commandExecuted = true,
() => initial);
lv.RefreshCommand = refresh;
Assert.That ((lv as IListViewController).RefreshAllowed, Is.EqualTo (initial));
initial = !initial;
refresh.ChangeCanExecute();
Assert.That ((lv as IListViewController).RefreshAllowed, Is.EqualTo (initial));
}
[Test]
public void BeginRefreshDoesNothingWhenCannotExecute()
{
var lv = new ListView();
bool commandExecuted = false, eventFired = false;
lv.Refreshing += (sender, args) => eventFired = true;
Command refresh = new Command (() => commandExecuted = true,
() => false);
lv.RefreshCommand = refresh;
lv.BeginRefresh();
Assert.That (lv.IsRefreshing, Is.False);
Assert.That (eventFired, Is.False);
Assert.That (commandExecuted, Is.False);
}
[Test]
public void SendRefreshingDoesNothingWhenCannotExecute()
{
var lv = new ListView();
bool commandExecuted = false, eventFired = false;
lv.Refreshing += (sender, args) => eventFired = true;
Command refresh = new Command (() => commandExecuted = true,
() => false);
lv.RefreshCommand = refresh;
((IListViewController)lv).SendRefreshing();
Assert.That (lv.IsRefreshing, Is.False);
Assert.That (eventFired, Is.False);
Assert.That (commandExecuted, Is.False);
}
[Test]
public void SettingIsRefreshingDoesntFireEvent()
{
var lv = new ListView();
bool refreshing = false;
lv.Refreshing += (sender, args) => {
refreshing = true;
};
lv.IsRefreshing = true;
Assert.That (refreshing, Is.False);
}
[Test]
public void EndRefresh()
{
var lv = new ListView { IsRefreshing = true };
Assert.That (lv.IsRefreshing, Is.True);
lv.EndRefresh();
Assert.That (lv.IsRefreshing, Is.False);
}
[Test]
public void CanRefreshAfterCantExecuteCommand()
{
var lv = new ListView();
bool commandExecuted = false, eventFired = false;
lv.Refreshing += (sender, args) => eventFired = true;
Command refresh = new Command (() => commandExecuted = true,
() => false);
lv.RefreshCommand = refresh;
lv.RefreshCommand = null;
((IListViewController)lv).SendRefreshing();
Assert.That (lv.IsRefreshing, Is.True);
Assert.That (eventFired, Is.True);
Assert.That (commandExecuted, Is.False);
}
[Test]
public void StopsListeningToCommandAfterCleared()
{
var lv = new ListView();
bool commandExecuted = false, canExecuteRequested = false;
Command refresh = new Command (() => commandExecuted = true,
() => canExecuteRequested = true);
lv.RefreshCommand = refresh;
canExecuteRequested = false;
lv.RefreshCommand = null;
Assert.That (() => refresh.ChangeCanExecute(), Throws.Nothing);
Assert.That (canExecuteRequested, Is.False);
lv.BeginRefresh();
Assert.That (commandExecuted, Is.False);
}
[Test]
[Description ("We should be able to set selected item when using ReadOnlyList")]
public void SetItemSelectedOnReadOnlyList()
{
var source = new ReadOnlySource ();
var listView = new ListView {
ItemsSource = source
};
bool raised = false;
listView.ItemSelected += (sender, arg) => raised = true;
listView.SelectedItem = source [0];
Assert.That (raised, Is.True, "ItemSelected was raised on ReadOnlySource");
}
internal class ReadOnlySource : IReadOnlyList<ListItem>
{
List<ListItem> items;
public ReadOnlySource ()
{
items = new List<ListItem> ();
for (int i = 0; i < 100; i++) {
items.Add (new ListItem { Name="person " + i } );
}
}
#region IEnumerable implementation
public IEnumerator<ListItem> GetEnumerator ()
{
return items.GetEnumerator ();
}
#endregion
#region IEnumerable implementation
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
{
return items.GetEnumerator ();
}
#endregion
#region IReadOnlyList implementation
public ListItem this [int index] {
get {
return items [index];
}
}
#endregion
#region IReadOnlyCollection implementation
public int Count {
get {
return items.Count;
}
}
#endregion
}
[Test]
public void ChildElementsParentIsNulledWhenReset()
{
var list = new ListView();
list.ItemsSource = new[] { "Hi", "Bye" };
var cell = list.TemplatedItems[0];
Assume.That (cell.Parent, Is.SameAs (list));
list.ItemsSource = null;
Assert.That (cell.Parent, Is.Null);
}
[Test]
public void ChildElementsParentIsNulledWhenRemoved()
{
var collection = new ObservableCollection<string> {
"Hi", "Bye"
};
var list = new ListView();
list.ItemsSource = collection;
var cell = list.TemplatedItems[0];
Assume.That (cell.Parent, Is.SameAs (list));
collection.Remove (collection[0]);
Assert.That (cell.Parent, Is.Null);
}
[Test]
public void ChildElementsParentIsNulledWhenCleared()
{
var collection = new ObservableCollection<string> {
"Hi", "Bye"
};
var list = new ListView();
list.ItemsSource = collection;
var cell = list.TemplatedItems[0];
Assume.That (cell.Parent, Is.SameAs (list));
collection.Clear();
Assert.That (cell.Parent, Is.Null);
}
[TestCase (Device.Android, ListViewCachingStrategy.RecycleElement)]
[TestCase (Device.iOS, ListViewCachingStrategy.RecycleElement)]
[TestCase(Device.UWP, ListViewCachingStrategy.RetainElement)]
[TestCase ("Other", ListViewCachingStrategy.RetainElement)]
public void EnforcesCachingStrategy (string platform, ListViewCachingStrategy expected)
{
var oldOS = Device.RuntimePlatform;
// we need to do this because otherwise we cant set the caching strategy
((MockPlatformServices)Device.PlatformServices).RuntimePlatform = platform;
var listView = new ListView (ListViewCachingStrategy.RecycleElement);
Assert.AreEqual (expected, listView.CachingStrategy);
((MockPlatformServices)Device.PlatformServices).RuntimePlatform = oldOS;
}
[Test]
public void DefaultCacheStrategy ()
{
var listView = new ListView ();
Assert.AreEqual (ListViewCachingStrategy.RetainElement, listView.CachingStrategy);
}
[Test]
public void DoesNotRetainInRecycleMode ()
{
var items = new ObservableCollection<string> {
"Foo",
"Bar"
};
var oldOS = Device.RuntimePlatform;
// we need to do this because otherwise we cant set the caching strategy
((MockPlatformServices)Device.PlatformServices).RuntimePlatform = Device.Android;
var bindable = new ListView (ListViewCachingStrategy.RecycleElement);
bindable.ItemTemplate = new DataTemplate (typeof (TextCell)) {
Bindings = {
{ TextCell.TextProperty, new Binding (".") }
}
};
bindable.ItemsSource = items;
var item1 = bindable.TemplatedItems[0];
var item2 = bindable.TemplatedItems[0];
Assert.False(ReferenceEquals (item1, item2));
((MockPlatformServices)Device.PlatformServices).RuntimePlatform = oldOS;
}
}
}