diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla42277.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla42277.cs new file mode 100644 index 00000000000..1a7624aed07 --- /dev/null +++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla42277.cs @@ -0,0 +1,121 @@ +using System; +using System.Linq; +using Xamarin.Forms.CustomAttributes; +using Xamarin.Forms.Internals; +using System.Collections.Generic; + +#if UITEST +using Xamarin.UITest; +using NUnit.Framework; +#endif + +namespace Xamarin.Forms.Controls +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 42277, "DataTemplate System.InvalidCastException crash in 2.3.1-pre1")] + public class Bugzilla42277 : TestContentPage + { + const string Success1 = "Success1"; + const string Success2 = "Success2"; + const string Success3 = "GroupedSuccess3"; + const string Success4 = "GroupedSuccess4"; + const string Success5 = "GroupedSuccess5"; + const string Success6 = "GroupedSuccess6"; + + class MyDataTemplateSelector : DataTemplateSelector + { + DataTemplate _1Template; + DataTemplate _2Template; + + DataTemplate _3Template; + DataTemplate _4Template; + DataTemplate _5Template; + DataTemplate _6Template; + + public MyDataTemplateSelector() + { + _1Template = new DataTemplate(() => + { + return new TextCell { Text = Success1 }; + }); + + _2Template = new DataTemplate(() => + { + return new TextCell { Text = Success2 }; + }); + + _3Template = new DataTemplate(() => + { + return new TextCell { Text = Success3 }; + }); + + _4Template = new DataTemplate(() => + { + return new TextCell { Text = Success4 }; + }); + + _5Template = new DataTemplate(() => + { + return new TextCell { Text = Success5 }; + }); + + _6Template = new DataTemplate(() => + { + return new TextCell { Text = Success6 }; + }); + } + + protected override DataTemplate OnSelectTemplate(object item, BindableObject container) + { + int number = (int)item; + switch (number) + { + default: + case 0: return _1Template; + case 1: return _2Template; + case 2: return _3Template; + case 3: return _4Template; + case 4: return _5Template; + case 5: return _6Template; + } + } + } + + protected override void Init() + { + //test non-grouped DTS + ListView listView = new ListView(ListViewCachingStrategy.RecycleElement) + { + ItemsSource = Enumerable.Range(0, 2), + ItemTemplate = new MyDataTemplateSelector() + }; + + //test grouped DTS + ListView groupedListView = new ListView(ListViewCachingStrategy.RecycleElement) + { + ItemsSource = new List> { Enumerable.Range(2, 2).ToList(), Enumerable.Range(4, 2).ToList() }, + IsGroupingEnabled = true, + ItemTemplate = new MyDataTemplateSelector() + }; + + Content = new StackLayout { Children = { listView, groupedListView } }; + + //test collection changed + listView.ItemsSource = Enumerable.Range(0, 2); + groupedListView.ItemsSource = new List> { Enumerable.Range(2, 2).ToList(), Enumerable.Range(4, 2).ToList() }; + } + +#if UITEST + [Test] + public void Bugzilla42277Test() + { + RunningApp.WaitForElement(q => q.Marked(Success1)); + RunningApp.WaitForElement(q => q.Marked(Success2)); + RunningApp.WaitForElement(q => q.Marked(Success3)); + RunningApp.WaitForElement(q => q.Marked(Success4)); + RunningApp.WaitForElement(q => q.Marked(Success5)); + RunningApp.WaitForElement(q => q.Marked(Success6)); + } +#endif + } +} diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems index 919d5062c0a..10e0800ce20 100644 --- a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems +++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems @@ -156,6 +156,7 @@ + diff --git a/Xamarin.Forms.Core/ITemplatedItemsList.cs b/Xamarin.Forms.Core/ITemplatedItemsList.cs index ae979d71207..be9055af20d 100644 --- a/Xamarin.Forms.Core/ITemplatedItemsList.cs +++ b/Xamarin.Forms.Core/ITemplatedItemsList.cs @@ -17,6 +17,8 @@ public interface ITemplatedItemsList : IReadOnlyList, INotifyColle IEnumerable ItemsSource { get; } IReadOnlyList ShortNames { get; } + IListProxy ListProxy { get; } + int GetGlobalIndexForGroup(ITemplatedItemsList group); int GetGlobalIndexOfItem(object item); ITemplatedItemsList GetGroup(int index); diff --git a/Xamarin.Forms.Core/TemplatedItemsList.cs b/Xamarin.Forms.Core/TemplatedItemsList.cs index 75a0d394bc3..cb64e2e91b4 100644 --- a/Xamarin.Forms.Core/TemplatedItemsList.cs +++ b/Xamarin.Forms.Core/TemplatedItemsList.cs @@ -194,6 +194,11 @@ internal IListProxy ListProxy private set { SetValue(ListProxyPropertyKey, value); } } + IListProxy ITemplatedItemsList.ListProxy + { + get { return ListProxy; } + } + DataTemplate ItemTemplate { get { return (DataTemplate)_itemsView.GetValue(_itemTemplateProperty); } diff --git a/Xamarin.Forms.Platform.Android/Renderers/ListViewAdapter.cs b/Xamarin.Forms.Platform.Android/Renderers/ListViewAdapter.cs index 5ac214cdde1..2230d2b42ea 100644 --- a/Xamarin.Forms.Platform.Android/Renderers/ListViewAdapter.cs +++ b/Xamarin.Forms.Platform.Android/Renderers/ListViewAdapter.cs @@ -144,9 +144,9 @@ public override int GetItemViewType(int position) { object item = null; if (_listView.IsGroupingEnabled) - item = ((ITemplatedItemsView)TemplatedItemsView.TemplatedItems.GetGroup(group)).ListProxy[row]; + item = TemplatedItemsView.TemplatedItems.GetGroup(group).ListProxy[row]; else - item = ((ITemplatedItemsView)TemplatedItemsView.TemplatedItems).ListProxy[position]; + item = TemplatedItemsView.TemplatedItems.ListProxy[position]; itemTemplate = selector.SelectTemplate(item, _listView); } int key; @@ -405,7 +405,7 @@ List GetCellsFromPosition(int position, int take) { if (_listView.CachingStrategy == ListViewCachingStrategy.RecycleElement) { - var groupContent = _listView.TemplatedItems.GroupHeaderTemplate.CreateContent(group.ItemsSource, _listView) as Cell; + var groupContent = _listView.TemplatedItems.GroupHeaderTemplate?.CreateContent(group.ItemsSource, _listView) as Cell; if (groupContent != null) { groupContent.Parent = _listView; diff --git a/Xamarin.Forms.Platform.WinRT/ListViewRenderer.cs b/Xamarin.Forms.Platform.WinRT/ListViewRenderer.cs index c6a9d2db546..d6ec70388bd 100644 --- a/Xamarin.Forms.Platform.WinRT/ListViewRenderer.cs +++ b/Xamarin.Forms.Platform.WinRT/ListViewRenderer.cs @@ -287,7 +287,7 @@ async void OnViewChangeCompleted(object sender, SemanticZoomViewChangedEventArgs if (Device.Idiom == TargetIdiom.Phone) await Task.Delay(1); - IListProxy listProxy = ((ITemplatedItemsView)til).ListProxy; + IListProxy listProxy = til.ListProxy; ScrollTo(listProxy.ProxiedEnumerable, listProxy[0], ScrollToPosition.Start, true, true); } diff --git a/Xamarin.Forms.Platform.iOS/Renderers/ListViewRenderer.cs b/Xamarin.Forms.Platform.iOS/Renderers/ListViewRenderer.cs index 238759e99cc..5483a169454 100644 --- a/Xamarin.Forms.Platform.iOS/Renderers/ListViewRenderer.cs +++ b/Xamarin.Forms.Platform.iOS/Renderers/ListViewRenderer.cs @@ -310,7 +310,7 @@ void OnFooterMeasureInvalidated(object sender, EventArgs eventArgs) void OnGroupedCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { - var til = (ITemplatedItemsList)sender; + var til = (TemplatedItemsList, Cell>)sender; var templatedItems = TemplatedItemsView.TemplatedItems; var groupIndex = templatedItems.IndexOf(til.HeaderContent); @@ -919,7 +919,7 @@ protected Cell GetCellForPath(NSIndexPath indexPath) { var templatedItems = TemplatedItemsView.TemplatedItems; if (List.IsGroupingEnabled) - templatedItems = (ITemplatedItemsList)((IList)templatedItems)[indexPath.Section]; + templatedItems = (TemplatedItemsList, Cell>)((IList)templatedItems)[indexPath.Section]; var cell = templatedItems[indexPath.Row]; return cell; @@ -934,7 +934,7 @@ void OnSectionPropertyChanged(object sender, PropertyChangedEventArgs e) { var currentSelected = _uiTableView.IndexPathForSelectedRow; - var til = (ITemplatedItemsView)sender; + var til = (TemplatedItemsList, Cell>)sender; var groupIndex = ((IList)TemplatedItemsView.TemplatedItems).IndexOf(til); if (groupIndex == -1) { @@ -968,9 +968,9 @@ int TemplateIdForPath(NSIndexPath indexPath) var templatedList = TemplatedItemsView.TemplatedItems; if (List.IsGroupingEnabled) - templatedList = (ITemplatedItemsList)((IList)templatedList)[indexPath.Section]; + templatedList = (TemplatedItemsList, Cell>)((IList)templatedList)[indexPath.Section]; - var item = ((ITemplatedItemsView)templatedList).ListProxy[indexPath.Row]; + var item = templatedList.ListProxy[indexPath.Row]; itemTemplate = selector.SelectTemplate(item, List); int key; diff --git a/docs/Xamarin.Forms.Core/Xamarin.Forms/ITemplatedItemsList`1.xml b/docs/Xamarin.Forms.Core/Xamarin.Forms/ITemplatedItemsList`1.xml index d3e6f449dcd..e526ffab712 100644 --- a/docs/Xamarin.Forms.Core/Xamarin.Forms/ITemplatedItemsList`1.xml +++ b/docs/Xamarin.Forms.Core/Xamarin.Forms/ITemplatedItemsList`1.xml @@ -239,6 +239,22 @@ To be added. + + + + Property + + 2.0.0.0 + + + Xamarin.Forms.IListProxy + + + To be added. + To be added. + To be added. + +