using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Linq; using NUnit.Framework; namespace Xamarin.Forms.Core.UnitTests { [TestFixture] public class TemplatedItemsListTests : BaseTestFixture { class MockItemsView : ItemsView { public MockItemsView() { TemplatedItems.IsGroupingEnabledProperty = IsGroupingEnabledProperty; } public event Action Hooked; public event Action Unhooked; public static readonly BindableProperty IsGroupingEnabledProperty = BindableProperty.Create (lv => lv.IsGroupingEnabled, false); public bool IsGroupingEnabled { get { return (bool)GetValue (IsGroupingEnabledProperty); } set { SetValue (IsGroupingEnabledProperty, value); } } protected override BindableObject CreateDefault (object item) { return new TextCell { Text = item.ToString () }; } public new TemplatedItemsList, BindableObject> TemplatedItems { get { return base.TemplatedItems; } } BindingBase groupShortNameBinding; public BindingBase GroupShortNameBinding { get { return groupShortNameBinding; } set { if (groupShortNameBinding == value) return; OnPropertyChanging (); groupShortNameBinding = value; TemplatedItems.GroupShortNameBinding = value; OnPropertyChanged (); } } BindingBase groupDisplayBinding; public BindingBase GroupDisplayBinding { get { return groupDisplayBinding; } set { if (groupDisplayBinding == value) return; OnPropertyChanging (); groupDisplayBinding = value; TemplatedItems.GroupDisplayBinding = value; OnPropertyChanged (); } } protected override void SetupContent (BindableObject content, int index) { base.SetupContent (content, index); if (Hooked != null) Hooked (content); } protected override void UnhookContent (BindableObject content) { base.UnhookContent (content); if (Unhooked != null) Unhooked (content); } } [SetUp] public override void Setup() { base.Setup (); bindable = new MockItemsView(); Device.PlatformServices = new MockPlatformServices (); } [TearDown] public override void TearDown() { base.TearDown (); Device.PlatformServices = null; } MockItemsView bindable; [Test] public void ListProxyNotNullWithNullItemsSource() { Assert.IsNotNull (bindable.TemplatedItems.ListProxy); } [Test] public void ResetOnItemsSourceChanged() { bool raised = false; NotifyCollectionChangedAction action = default(NotifyCollectionChangedAction); bindable.TemplatedItems.CollectionChanged += (sender, args) => { raised = true; action = args.Action; }; bindable.SetValue (ItemsView.ItemsSourceProperty, Enumerable.Empty()); Assert.IsTrue (raised, "CollectionChanged was not raised"); Assert.AreEqual (NotifyCollectionChangedAction.Reset, action); } /* [Test] public void ResetOnInfiniteScrollingChanged() { bool raised = false; NotifyCollectionChangedAction action = default(NotifyCollectionChangedAction); bindable.TemplatedItems.CollectionChanged += (sender, args) => { raised = true; action = args.Action; }; bindable.SetValue (ItemsView.InfiniteScrollingProperty, true); Assert.IsTrue (raised, "CollectionChanged was not raised"); Assert.AreEqual (NotifyCollectionChangedAction.Reset, action); }*/ [Test] public void ResetOnTemplateChanged() { // Template changes won't trigger a reset if there's no items. bindable.SetValue (ItemsView.ItemsSourceProperty, new[] { "Foo" }); bool raised = false; NotifyCollectionChangedAction action = default(NotifyCollectionChangedAction); bindable.TemplatedItems.CollectionChanged += (sender, args) => { raised = true; action = args.Action; }; bindable.SetValue (ItemsView.ItemTemplateProperty, new DataTemplate()); Assert.IsTrue (raised, "CollectionChanged was not raised"); Assert.AreEqual (NotifyCollectionChangedAction.Reset, action); } [Test] public void PassThroughChanges() { var collection = new ObservableCollection(); bindable.SetValue (ItemsView.ItemsSourceProperty, collection); bool raised = false; NotifyCollectionChangedEventArgs args = null; bindable.TemplatedItems.CollectionChanged += (sender, eventArgs) => { raised = true; args = eventArgs; }; string str = "foo bar"; collection.Add (str); Assert.IsTrue (raised, "CollectionChanged was not raised"); Assert.AreEqual (NotifyCollectionChangedAction.Add, args.Action); Assert.AreEqual (0, args.NewStartingIndex); Assert.IsNotNull (args.NewItems); Assert.AreEqual (1, args.NewItems.Count); Assert.AreSame (str, ((Cell)args.NewItems[0]).BindingContext); } [Test] public void ListProxyUpdatesWithItemsSource() { var collection = new List { "foo bar" }; bindable.SetValue (ItemsView.ItemsSourceProperty, collection); Assert.IsNotNull (bindable.TemplatedItems.ListProxy); Assert.AreEqual (collection.Count, bindable.TemplatedItems.ListProxy.Count); } [Test] public void GetOrCreateContent ([Values (0, 1, 2)] int index) { var collection = new List { "foo", "bar", "baz" }; bindable.SetValue (ItemsView.ItemsSourceProperty, collection); DataTemplate template = new DataTemplate (typeof (TextCell)); template.SetBinding (TextCell.TextProperty, new Binding (".")); bindable.SetValue (ItemsView.ItemTemplateProperty, template); BindableObject content = bindable.TemplatedItems.GetOrCreateContent (index, collection[index]); Assert.IsNotNull (content); TextCell textCell = content as TextCell; Assert.IsNotNull (textCell, "Content was did not match the template type, expected {0} but got {1}", typeof(TextCell), content.GetType()); Assert.AreSame (collection[index], textCell.BindingContext); Assert.AreSame (collection[index], textCell.Text); BindableObject content2 = bindable.TemplatedItems.GetOrCreateContent (index, collection[index]); Assert.AreSame (content, content2); } [Test] public void GetOrCreateContentDefault() { Assert.IsNull (bindable.GetValue (ItemsView.ItemTemplateProperty)); var collection = new List { "foo", "bar", "baz" }; bindable.SetValue (ItemsView.ItemsSourceProperty, collection); const int index = 0; BindableObject content = bindable.TemplatedItems.GetOrCreateContent (index, collection[index]); Assert.IsNotNull (content); TextCell textCell = content as TextCell; Assert.IsNotNull (textCell, "Content was did not match the template type, expected {0} but got {1}", typeof(TextCell), content.GetType()); Assert.AreSame (collection[index], textCell.BindingContext); Assert.AreSame (collection[index], textCell.Text); BindableObject content2 = bindable.TemplatedItems.GetOrCreateContent (index, collection[index]); Assert.AreSame (content, content2); } [Test] public void GetOrCreateContentAfterTemplateChange() { var collection = new List { "foo", "bar", "baz" }; bindable.SetValue (ItemsView.ItemsSourceProperty, collection); const int index = 0; DataTemplate template = new DataTemplate (typeof (TextCell)); template.SetBinding (TextCell.TextProperty, new Binding (".")); bindable.SetValue (ItemsView.ItemTemplateProperty, template); BindableObject content = bindable.TemplatedItems.GetOrCreateContent (index, collection[index]); Assert.That (content, Is.InstanceOf()); template = new DataTemplate (typeof (SwitchCell)); template.SetBinding (SwitchCell.TextProperty, new Binding (".")); bindable.SetValue (ItemsView.ItemTemplateProperty, template); BindableObject content2 = bindable.TemplatedItems.GetOrCreateContent (index, collection[index]); Assert.IsNotNull (content2); Assert.That (content2, Is.InstanceOf()); var switchCell = (SwitchCell) content2; Assert.AreSame (collection[index], switchCell.BindingContext); } [Test] public void GetOrCreateContentAfterItemsSourceChanged() { var collection = new List { "foo", "bar", "baz" }; bindable.SetValue (ItemsView.ItemsSourceProperty, collection); const int index = 0; DataTemplate template = new DataTemplate (typeof (TextCell)); template.SetBinding (TextCell.TextProperty, new Binding (".")); bindable.SetValue (ItemsView.ItemTemplateProperty, template); BindableObject content = bindable.TemplatedItems.GetOrCreateContent (index, collection[index]); Assert.IsNotNull (content); collection = new List { "we", "wee", "weee" }; bindable.SetValue (ItemsView.ItemsSourceProperty, collection); var content2 = (TextCell)bindable.TemplatedItems.GetOrCreateContent (index, collection[index]); Assert.AreNotSame (content, content2); Assert.AreSame (collection[index], content2.BindingContext); Assert.AreSame (collection[index], content2.Text); } /*[Test] public void GetOrCreateContentAfterInfiniteScrollingChanged() { var collection = new List { "foo", "bar", "baz" }; bindable.SetValue (ItemsView.ItemsSourceProperty, collection); const int index = 0; DataTemplate template = new DataTemplate (typeof (TextCell)); template.SetBinding (TextCell.TextProperty, new Binding (".")); bindable.SetValue (ItemsView.ItemTemplateProperty, template); BindableObject content = bindable.TemplatedItems.GetOrCreateContent (index, collection[index], o => new TextCell (o.ToString())); Assert.IsNotNull (content); bindable.SetValue (ItemsView.InfiniteScrollingProperty, true); var content2 = (TextCell)bindable.TemplatedItems.GetOrCreateContent (index, collection[index], o => new TextCell (o.ToString())); Assert.AreNotSame (content, content2); Assert.AreSame (collection[index], content2.BindingContext); Assert.AreSame (collection[index], content2.Text); }*/ [Test] [Description ("Make sure we're not duplicate cell instances for an equal item if it's a different index")] public void GetOrCreateContentEqualItemDifferentItemDifferentIndex() { Assert.IsNull (bindable.GetValue (ItemsView.ItemTemplateProperty)); var collection = new List { "foo", "foo" }; bindable.SetValue (ItemsView.ItemsSourceProperty, collection); BindableObject content = bindable.TemplatedItems.GetOrCreateContent (0, collection[0]); Assert.IsNotNull (content); TextCell textCell = content as TextCell; Assert.IsNotNull (textCell, "Content was did not match the template type, expected {0} but got {1}", typeof(TextCell), content.GetType()); Assert.AreSame (collection[0], textCell.BindingContext); Assert.AreSame (collection[0], textCell.Text); BindableObject content2 = bindable.TemplatedItems.GetOrCreateContent (1, collection[1]); Assert.AreNotSame (content, content2); Assert.AreSame (collection[1], textCell.BindingContext); Assert.AreSame (collection[1], textCell.Text); } [Test] [Description ("Make sure we're not duplicate cell instances for the same item if it's a different index")] public void GetOrCreateContentEqualItemSameItemDifferentIndex() { Assert.IsNull (bindable.GetValue (ItemsView.ItemTemplateProperty)); string item = "foo"; var collection = new List { item, item }; bindable.SetValue (ItemsView.ItemsSourceProperty, collection); BindableObject content = bindable.TemplatedItems.GetOrCreateContent (0, item); Assert.IsNotNull (content); TextCell textCell = content as TextCell; Assert.IsNotNull (textCell, "Content was did not match the template type, expected {0} but got {1}", typeof(TextCell), content.GetType()); Assert.AreSame (item, textCell.BindingContext); Assert.AreSame (item, textCell.Text); BindableObject content2 = bindable.TemplatedItems.GetOrCreateContent (1, item); Assert.AreNotSame (content, content2); Assert.AreSame (item, textCell.BindingContext); Assert.AreSame (item, textCell.Text); } [Test] public void ItemsSourceInsertPreRealzied() { var collection = new ObservableCollection { "foo", "bar" }; bindable.SetValue (ItemsView.ItemsSourceProperty, collection); collection.Insert (1, "baz"); Assert.That (bindable.TemplatedItems.Count, Is.EqualTo (3)); Assert.That (bindable.TemplatedItems.GetOrCreateContent (0, collection[0]).BindingContext, Is.SameAs (collection[0])); Assert.That (bindable.TemplatedItems.GetOrCreateContent (1, collection[1]).BindingContext, Is.SameAs (collection[1])); Assert.That (bindable.TemplatedItems.GetOrCreateContent (2, collection[2]).BindingContext, Is.SameAs (collection[2])); } [Test] public void ItemsSourceInsertPostRealized() { var collection = new ObservableCollection { "foo", "bar" }; bindable.SetValue (ItemsView.ItemsSourceProperty, collection); // Force the handler to realize/create the content bindable.TemplatedItems.GetOrCreateContent (0, collection[0]); bindable.TemplatedItems.GetOrCreateContent (1, collection[1]); collection.Insert (1, "baz"); Assert.That (bindable.TemplatedItems.Count, Is.EqualTo (3)); Assert.That (bindable.TemplatedItems.GetOrCreateContent (0, collection[0]).BindingContext, Is.SameAs (collection[0])); Assert.That (bindable.TemplatedItems.GetOrCreateContent (1, collection[1]).BindingContext, Is.SameAs (collection[1])); Assert.That (bindable.TemplatedItems.GetOrCreateContent (2, collection[2]).BindingContext, Is.SameAs (collection[2])); } [TestCase (0, 0, 0)] [TestCase (3, 1, 0)] public void GetGroupIndexFromGlobalGroupIndex (int globalIndex, int expectedIndex, int expectedLeftOver) { var collection = new[] { new[] { "foo", "fad" }, new[] { "bar", "baz" } }; bindable.ItemsSource = collection; bindable.IsGroupingEnabled = true; int leftOver; int index = bindable.TemplatedItems.GetGroupIndexFromGlobal (globalIndex, out leftOver); Assert.That (index, Is.EqualTo (expectedIndex)); Assert.That (leftOver, Is.EqualTo (expectedLeftOver)); } [TestCase (1, 0, 1)] [TestCase (2, 0, 2)] [TestCase (4, 1, 1)] [TestCase (5, 1, 2)] public void GetGroupIndexFromGlobalItemIndex (int globalIndex, int expectedIndex, int expectedLeftOver) { var collection = new[] { new[] { "foo", "fad" }, new[] { "bar", "baz" } }; bindable.ItemsSource = collection; bindable.IsGroupingEnabled = true; int leftOver; int index = bindable.TemplatedItems.GetGroupIndexFromGlobal (globalIndex, out leftOver); Assert.That (index, Is.EqualTo (expectedIndex)); Assert.That (leftOver, Is.EqualTo (expectedLeftOver)); } [Test] public void GetGroupAndIndexOfItem ([Values (0, 1, 2)] int group, [Values (0, 1, 2)] int index) { var collection = new[] { new[] { "foo", "fad" }, new[] { "bar", "baz" } }; bindable.ItemsSource = collection; bindable.IsGroupingEnabled = true; object item = null; if (group < collection.Length) { if (index < collection[group].Length) item = collection[group][index]; } if (item == null) { item = "not in here"; group = index = -1; } var location = bindable.TemplatedItems.GetGroupAndIndexOfItem (item); Assert.That (location.Item1, Is.EqualTo (group), "Group index was incorrect"); Assert.That (location.Item2, Is.EqualTo (index), "Item index was incorrect"); } [Test] public void GetGroupAndIndexOfItemNotGrouped () { var items = Enumerable.Range (0, 10).ToList (); bindable.ItemsSource = items; var location = bindable.TemplatedItems.GetGroupAndIndexOfItem (null, items[2]); Assert.That (location.Item1, Is.EqualTo (0)); Assert.That (location.Item2, Is.EqualTo (2)); } [Test] public void ItemsSourcePropertyChangedWithBindable() { bool raised = false; bindable.TemplatedItems.PropertyChanged += (s, e) => { if (e.PropertyName == "ItemsSource") raised = true; }; bindable.ItemsSource = new object[0]; Assert.That (raised, Is.True, "INPC not raised for ItemsSource"); } [Test] public void IndexCorrectAfterMovingGroups() { var items = new ObservableCollection> { new ObservableCollection { "foo", "faz" }, new ObservableCollection { "bar", "baz" } }; bindable.ItemsSource = items; bindable.IsGroupingEnabled = true; items.Move (0, 1); var til = bindable.TemplatedItems.GetGroup (1); int index = GetIndex (til.HeaderContent); Assert.That (index, Is.EqualTo (1)); } [Test] public void ShortNameSetBeforeGrouping() { var items = new ObservableCollection> { new ObservableCollection { "foo", "faz" }, new ObservableCollection { "bar", "baz" } }; bindable.ItemsSource = items; bindable.GroupDisplayBinding = new Binding (".[0]"); bindable.GroupShortNameBinding = new Binding (".[0]"); bindable.IsGroupingEnabled = true; Assert.That (bindable.TemplatedItems.ShortNames[0], Is.EqualTo ("foo")); } [Test] public void ItemAddedWithShortNameSetButUngrouped() { var items = new ObservableCollection { "foo", "bar" }; bindable.ItemsSource = items; bindable.GroupShortNameBinding = new Binding ("."); Assert.That (() => items.Add ("baz"), Throws.Nothing); } [Test] public void ItemAddedWithShortNameSetButGroupingDisabled() { var items = new ObservableCollection> { new ObservableCollection { "foo", "faz" }, new ObservableCollection { "bar", "baz" } }; bindable.ItemsSource = items; bindable.GroupShortNameBinding = new Binding ("."); bindable.IsGroupingEnabled = true; bindable.IsGroupingEnabled = false; Assert.That (() => items.Add (new ObservableCollection()), Throws.Nothing); } int GetIndex (BindableObject item) { return TemplatedItemsList, BindableObject>.GetIndex (item); } [Test] public void GetIndex() { var items = new List { "foo", "bar", "baz" }; bindable.ItemsSource = items; BindableObject item = bindable.TemplatedItems.GetOrCreateContent (1, items[1]); int index = GetIndex (item); Assert.That (index, Is.EqualTo (1)); } [Test] public void GetIndexAfterInsert() { var items = new ObservableCollection { "foo", "bar", "baz" }; bindable.ItemsSource = items; BindableObject originalItem = bindable.TemplatedItems.GetOrCreateContent (1, items[1]); items.Insert (1, "fad"); BindableObject item = bindable.TemplatedItems.GetOrCreateContent (1, items[1]); int index = GetIndex (item); Assert.That (index, Is.EqualTo (1)); index = GetIndex (originalItem); Assert.That (index, Is.EqualTo (2)); } [Test] public void GetIndexAfterMove() { var items = new ObservableCollection { "foo", "bar", "baz" }; bindable.ItemsSource = items; BindableObject item0 = bindable.TemplatedItems.GetOrCreateContent (0, items[0]); BindableObject item1 = bindable.TemplatedItems.GetOrCreateContent (1, items[1]); BindableObject item2 = bindable.TemplatedItems.GetOrCreateContent (2, items[2]); items.Move (0, 2); // foo, bar, baz becomes bar (1), baz (2), foo (0) Assert.That (GetIndex (item0), Is.EqualTo (2)); Assert.That (GetIndex (item1), Is.EqualTo (0)); Assert.That (GetIndex (item2), Is.EqualTo (1)); } [Test] public void GetIndexAfterRemove() { var items = new ObservableCollection { "foo", "bar", "baz" }; bindable.ItemsSource = items; BindableObject item1 = bindable.TemplatedItems.GetOrCreateContent (1, items[1]); BindableObject item2 = bindable.TemplatedItems.GetOrCreateContent (2, items[2]); items.RemoveAt (0); Assert.That (GetIndex (item1), Is.EqualTo (0)); Assert.That (GetIndex (item2), Is.EqualTo (1)); } [Test] public void GetGroup() { var items = new ObservableCollection> { new ObservableCollection { "foo", "faz" }, new ObservableCollection { "bar", "baz" } }; bindable.ItemsSource = items; bindable.GroupShortNameBinding = new Binding ("."); bindable.IsGroupingEnabled = true; var til = bindable.TemplatedItems.GetGroup (1); var item = til[1]; var group = TemplatedItemsList, BindableObject>.GetGroup (item); Assert.That (group, Is.SameAs (til)); } [Test] public void GetIndexGrouped() { var items = new ObservableCollection> { new ObservableCollection { "foo", "faz" }, new ObservableCollection { "bar", "baz" } }; bindable.ItemsSource = items; bindable.GroupShortNameBinding = new Binding ("."); bindable.IsGroupingEnabled = true; var til = bindable.TemplatedItems.GetGroup (1); var item = til[1]; int index = GetIndex (item); Assert.That (index, Is.EqualTo (1)); } [Test] public void GetGroupAndIndexOfItem() { var items = new ObservableCollection> { new ObservableCollection { "foo", "faz" }, new ObservableCollection { "bar", "baz" } }; bindable.ItemsSource = items; bindable.GroupShortNameBinding = new Binding ("."); bindable.IsGroupingEnabled = true; var result = bindable.TemplatedItems.GetGroupAndIndexOfItem (items[1], items[1][1]); Assert.That (result.Item1, Is.EqualTo (1)); Assert.That (result.Item2, Is.EqualTo (1)); } [Test] public void GetGroupAndIndexOfItemNoGroup() { var items = new ObservableCollection> { new ObservableCollection { "foo", "faz" }, new ObservableCollection { "bar", "baz" } }; bindable.ItemsSource = items; bindable.GroupShortNameBinding = new Binding ("."); bindable.IsGroupingEnabled = true; var result = bindable.TemplatedItems.GetGroupAndIndexOfItem (null, items[1][1]); Assert.That (result.Item1, Is.EqualTo (1)); Assert.That (result.Item2, Is.EqualTo (1)); } [Test] public void GetGroupAndIndexOfItemNotFound() { var items = new ObservableCollection> { new ObservableCollection { "foo", "faz" }, new ObservableCollection { "bar", "baz" } }; bindable.ItemsSource = items; bindable.GroupShortNameBinding = new Binding ("."); bindable.IsGroupingEnabled = true; var group = new ObservableCollection { "bam" }; var result = bindable.TemplatedItems.GetGroupAndIndexOfItem (group, group[0]); Assert.That (result.Item1, Is.EqualTo (-1)); Assert.That (result.Item2, Is.EqualTo (-1)); } [Test] public void GetGroupAndIndexOfItemItemNotFound() { var items = new ObservableCollection> { new ObservableCollection { "foo", "faz" }, new ObservableCollection { "bar", "baz" } }; bindable.ItemsSource = items; bindable.GroupShortNameBinding = new Binding ("."); bindable.IsGroupingEnabled = true; var result = bindable.TemplatedItems.GetGroupAndIndexOfItem (items[1], "bam"); Assert.That (result.Item1, Is.EqualTo (1)); Assert.That (result.Item2, Is.EqualTo (-1)); } [Test] [Description ("Issue #2464: ANE thrown when moving items in a ListView")] public void MovingPastRealizedWindowAndBackDoesntThrow() { var items = new ObservableCollection (Enumerable.Range (0, 100).Select (i => i.ToString())); bindable.ItemsSource = items; bindable.TemplatedItems.GetOrCreateContent (0, items[0]); bindable.TemplatedItems.GetOrCreateContent (1, items[1]); items.Move (0, 3); Assert.That (() => items.Move (3, 2), Throws.Nothing); Assert.That (GetIndex (bindable.TemplatedItems[0]), Is.EqualTo (0)); Assert.That (GetIndex (bindable.TemplatedItems[1]), Is.EqualTo (1)); Assert.That (GetIndex (bindable.TemplatedItems[2]), Is.EqualTo (2)); Assert.That (GetIndex (bindable.TemplatedItems[3]), Is.EqualTo (3)); } [Test] public void GetGlobalIndexOfItem () { var items = new ObservableCollection (Enumerable.Range (0, 100).Select (i => i.ToString())); bindable.ItemsSource = items; int global = bindable.TemplatedItems.GetGlobalIndexOfItem ("50"); Assert.That (global, Is.EqualTo (50)); } [Test] public void GetGlobalIndexOfItemNotFound () { var items = new ObservableCollection (Enumerable.Range (0, 100).Select (i => i.ToString())); bindable.ItemsSource = items; int global = bindable.TemplatedItems.GetGlobalIndexOfItem ("101"); Assert.That (global, Is.EqualTo (-1)); } [Test] public void GetGlobalIndexOfItemGrouped () { var items = new ObservableCollection> { new ObservableCollection { "foo", "faz" }, new ObservableCollection { "bar", "baz" } }; bindable.ItemsSource = items; bindable.GroupShortNameBinding = new Binding ("."); bindable.IsGroupingEnabled = true; int global = bindable.TemplatedItems.GetGlobalIndexOfItem ("baz"); Assert.That (global, Is.EqualTo (5)); } [Test] public void GetGlobalIndexOfItemGroupedNotFound () { var items = new ObservableCollection> { new ObservableCollection { "foo", "faz" }, new ObservableCollection { "bar", "baz" } }; bindable.ItemsSource = items; bindable.GroupShortNameBinding = new Binding ("."); bindable.IsGroupingEnabled = true; int global = bindable.TemplatedItems.GetGlobalIndexOfItem ("101"); Assert.That (global, Is.EqualTo (-1)); } [Test] public void GetGlobalIndexOfGroupItemGrouped () { var items = new ObservableCollection> { new ObservableCollection { "foo", "baz" }, new ObservableCollection { "bar", "baz" } }; bindable.ItemsSource = items; bindable.GroupShortNameBinding = new Binding ("."); bindable.IsGroupingEnabled = true; int global = bindable.TemplatedItems.GetGlobalIndexOfItem (items[1], "baz"); Assert.That (global, Is.EqualTo (5)); } [Test] public void GetGlobalIndexOfGroupItemGroupedNotFound () { var items = new ObservableCollection> { new ObservableCollection { "foo", "faz" }, new ObservableCollection { "foo", "faz" } }; bindable.ItemsSource = items; bindable.GroupShortNameBinding = new Binding ("."); bindable.IsGroupingEnabled = true; int global = bindable.TemplatedItems.GetGlobalIndexOfItem (items[1], "bar"); Assert.That (global, Is.EqualTo (-1)); } [Test] public void GetGlobalIndexOfGroupItemGroupedGroupNotFound () { var items = new ObservableCollection> { new ObservableCollection { "foo", "faz" }, new ObservableCollection { "foo", "faz" } }; bindable.ItemsSource = items; bindable.GroupShortNameBinding = new Binding ("."); bindable.IsGroupingEnabled = true; int global = bindable.TemplatedItems.GetGlobalIndexOfItem (new object(), "foo"); Assert.That (global, Is.EqualTo (-1)); } [Test] public void SetupContentOnCreation() { var items = new ObservableCollection { "Foo", "Bar" }; bindable.ItemTemplate = new DataTemplate (typeof (TextCell)) { Bindings = { { TextCell.TextProperty, new Binding (".") } } }; int count = 0; bindable.Hooked += obj => { count++; Assert.That (obj, Is.InstanceOf (typeof (TextCell))); Assert.That (items, Contains.Item (obj.BindingContext)); }; bindable.ItemsSource = items; bindable.TemplatedItems.GetOrCreateContent (0, items[0]); bindable.TemplatedItems.GetOrCreateContent (1, items[1]); Assert.That (count, Is.EqualTo (2)); } [Test] public void UnhookGroupOnRemoval() { var inner = new ObservableCollection { "Foo", }; var items = new ObservableCollection> { inner }; bindable.IsGroupingEnabled = true; bindable.GroupDisplayBinding = new Binding (".[0]"); bindable.ItemTemplate = new DataTemplate (typeof (TextCell)) { Bindings = { { TextCell.TextProperty, new Binding (".") } } }; int count = 0; bindable.Unhooked += obj => { if (count == 0) { Assert.That (obj.BindingContext, Is.InstanceOf (typeof (TemplatedItemsList, BindableObject>))); Assert.That (((TemplatedItemsList, BindableObject>) obj.BindingContext).ListProxy.ProxiedEnumerable, Is.SameAs (inner)); } else { Assert.That (obj.BindingContext, Is.SameAs (inner[0])); } count++; }; bindable.ItemsSource = items; var til = bindable.TemplatedItems.GetGroup (0); til.GetOrCreateContent (0, inner[0]); Assume.That (til, Is.Not.Null); Assume.That (til.HeaderContent, Is.Not.Null); Assume.That (count, Is.EqualTo (0)); items.RemoveAt (0); Assert.That (count, Is.EqualTo (2)); } [Test] public void HookAndUnhookGroupOnReplace() { var items = new ObservableCollection> { new ObservableCollection { "Foo", } }; bindable.IsGroupingEnabled = true; bindable.GroupDisplayBinding = new Binding (".[0]"); bindable.ItemTemplate = new DataTemplate (typeof (TextCell)) { Bindings = { { TextCell.TextProperty, new Binding (".") } } }; bindable.ItemsSource = items; var til = bindable.TemplatedItems.GetGroup (0); til.GetOrCreateContent (0, items[0][0]); Assume.That (til, Is.Not.Null); Assume.That (til.HeaderContent, Is.Not.Null); int hcount = 0; bindable.Hooked += obj => { Assert.That (obj.BindingContext, Is.InstanceOf (typeof (TemplatedItemsList, BindableObject>))); hcount++; }; int ucount = 0; bindable.Unhooked += obj => { Assert.That (obj.BindingContext, Is.InstanceOf (typeof (TemplatedItemsList, BindableObject>)) .Or.EqualTo ("Foo")); ucount++; }; items[0] = new ObservableCollection { "Baz" }; Assert.That (hcount, Is.EqualTo (1)); Assert.That (ucount, Is.EqualTo (2)); } [Test] public void UnhookContentOnRemoval() { var items = new ObservableCollection { "Foo", "Bar" }; bindable.ItemTemplate = new DataTemplate (typeof (TextCell)) { Bindings = { { TextCell.TextProperty, new Binding (".") } } }; int count = 0; bindable.Unhooked += obj => { count++; Assert.That (obj, Is.InstanceOf (typeof (TextCell))); Assert.That (obj.BindingContext, Is.EqualTo ("Foo")); }; bindable.ItemsSource = items; bindable.TemplatedItems.GetOrCreateContent (0, items[0]); bindable.TemplatedItems.GetOrCreateContent (1, items[1]); Assume.That (count, Is.EqualTo (0)); items.RemoveAt (0); Assert.That (count, Is.EqualTo (1)); } [Test] public void HookAndUnhookContentOnReplace() { var items = new ObservableCollection { "Foo", "Bar" }; bindable.ItemTemplate = new DataTemplate (typeof (TextCell)) { Bindings = { { TextCell.TextProperty, new Binding (".") } } }; bindable.ItemsSource = items; bindable.TemplatedItems.GetOrCreateContent (0, items[0]); bindable.TemplatedItems.GetOrCreateContent (1, items[1]); int hcount = 0; bindable.Hooked += obj => { hcount++; Assert.That (obj, Is.InstanceOf (typeof (TextCell))); Assert.That (obj.BindingContext, Is.EqualTo ("Baz")); }; int ucount = 0; bindable.Unhooked += obj => { ucount++; Assert.That (obj, Is.InstanceOf (typeof (TextCell))); Assert.That (obj.BindingContext, Is.EqualTo ("Foo")); }; items[0] = "Baz"; Assert.That (hcount, Is.EqualTo (1)); Assert.That (ucount, Is.EqualTo (1)); } [Test (Description = "If the cell exists and has an index, we still need to check if it's in the group asked for")] public void IndexOfFailsForCellInAnotherGroup () { var items = new ObservableCollection> { new ObservableCollection { "foo", "faz" }, new ObservableCollection { "bar", "baz" } }; bindable.ItemsSource = items; bindable.GroupShortNameBinding = new Binding ("."); bindable.IsGroupingEnabled = true; var group1 = bindable.TemplatedItems.GetGroup (0); var cell = group1[1]; Assume.That (group1.IndexOf (cell), Is.EqualTo (1)); var group2 = bindable.TemplatedItems.GetGroup (1); Assert.That (group2.IndexOf (cell), Is.EqualTo (-1)); } } }