Skip to content
This repository was archived by the owner on May 1, 2024. It is now read-only.

Commit 4d270b6

Browse files
samhoutsrmarinho
authored andcommitted
[All] Crash fixes for ListViews (#243)
* [Controls] Add repro for 42277 * [Android] No crash if GroupHeaderTemplate=null * [Android] Fix DataTemplateSelector crash * [Core] Expose ListProxy on TIL * [iOS] Fix DataTemplateSelector crash * [Win] Fix DataTemplateSelector crash * [Docs] Update docs * [Core] Implement ListProxy explicitly Allows ListProxy property to stay internal. * [Controls] Revert unnecessary change to shproj
1 parent 6e3e218 commit 4d270b6

File tree

8 files changed

+154
-9
lines changed

8 files changed

+154
-9
lines changed
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
using System;
2+
using System.Linq;
3+
using Xamarin.Forms.CustomAttributes;
4+
using Xamarin.Forms.Internals;
5+
using System.Collections.Generic;
6+
7+
#if UITEST
8+
using Xamarin.UITest;
9+
using NUnit.Framework;
10+
#endif
11+
12+
namespace Xamarin.Forms.Controls
13+
{
14+
[Preserve(AllMembers = true)]
15+
[Issue(IssueTracker.Bugzilla, 42277, "DataTemplate System.InvalidCastException crash in 2.3.1-pre1")]
16+
public class Bugzilla42277 : TestContentPage
17+
{
18+
const string Success1 = "Success1";
19+
const string Success2 = "Success2";
20+
const string Success3 = "GroupedSuccess3";
21+
const string Success4 = "GroupedSuccess4";
22+
const string Success5 = "GroupedSuccess5";
23+
const string Success6 = "GroupedSuccess6";
24+
25+
class MyDataTemplateSelector : DataTemplateSelector
26+
{
27+
DataTemplate _1Template;
28+
DataTemplate _2Template;
29+
30+
DataTemplate _3Template;
31+
DataTemplate _4Template;
32+
DataTemplate _5Template;
33+
DataTemplate _6Template;
34+
35+
public MyDataTemplateSelector()
36+
{
37+
_1Template = new DataTemplate(() =>
38+
{
39+
return new TextCell { Text = Success1 };
40+
});
41+
42+
_2Template = new DataTemplate(() =>
43+
{
44+
return new TextCell { Text = Success2 };
45+
});
46+
47+
_3Template = new DataTemplate(() =>
48+
{
49+
return new TextCell { Text = Success3 };
50+
});
51+
52+
_4Template = new DataTemplate(() =>
53+
{
54+
return new TextCell { Text = Success4 };
55+
});
56+
57+
_5Template = new DataTemplate(() =>
58+
{
59+
return new TextCell { Text = Success5 };
60+
});
61+
62+
_6Template = new DataTemplate(() =>
63+
{
64+
return new TextCell { Text = Success6 };
65+
});
66+
}
67+
68+
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
69+
{
70+
int number = (int)item;
71+
switch (number)
72+
{
73+
default:
74+
case 0: return _1Template;
75+
case 1: return _2Template;
76+
case 2: return _3Template;
77+
case 3: return _4Template;
78+
case 4: return _5Template;
79+
case 5: return _6Template;
80+
}
81+
}
82+
}
83+
84+
protected override void Init()
85+
{
86+
//test non-grouped DTS
87+
ListView listView = new ListView(ListViewCachingStrategy.RecycleElement)
88+
{
89+
ItemsSource = Enumerable.Range(0, 2),
90+
ItemTemplate = new MyDataTemplateSelector()
91+
};
92+
93+
//test grouped DTS
94+
ListView groupedListView = new ListView(ListViewCachingStrategy.RecycleElement)
95+
{
96+
ItemsSource = new List<List<int>> { Enumerable.Range(2, 2).ToList(), Enumerable.Range(4, 2).ToList() },
97+
IsGroupingEnabled = true,
98+
ItemTemplate = new MyDataTemplateSelector()
99+
};
100+
101+
Content = new StackLayout { Children = { listView, groupedListView } };
102+
103+
//test collection changed
104+
listView.ItemsSource = Enumerable.Range(0, 2);
105+
groupedListView.ItemsSource = new List<List<int>> { Enumerable.Range(2, 2).ToList(), Enumerable.Range(4, 2).ToList() };
106+
}
107+
108+
#if UITEST
109+
[Test]
110+
public void Bugzilla42277Test()
111+
{
112+
RunningApp.WaitForElement(q => q.Marked(Success1));
113+
RunningApp.WaitForElement(q => q.Marked(Success2));
114+
RunningApp.WaitForElement(q => q.Marked(Success3));
115+
RunningApp.WaitForElement(q => q.Marked(Success4));
116+
RunningApp.WaitForElement(q => q.Marked(Success5));
117+
RunningApp.WaitForElement(q => q.Marked(Success6));
118+
}
119+
#endif
120+
}
121+
}

Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@
156156
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla39853.cs" />
157157
<Compile Include="$(MSBuildThisFileDirectory)TestPages\ScreenshotConditionalApp.cs" />
158158
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla41842.cs" />
159+
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla42277.cs" />
159160
<Compile Include="$(MSBuildThisFileDirectory)_Template.cs" />
160161
<Compile Include="$(MSBuildThisFileDirectory)Issue1028.cs" />
161162
<Compile Include="$(MSBuildThisFileDirectory)Issue1075.cs" />

Xamarin.Forms.Core/ITemplatedItemsList.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ public interface ITemplatedItemsList<TItem> : IReadOnlyList<TItem>, INotifyColle
1717
IEnumerable ItemsSource { get; }
1818
IReadOnlyList<string> ShortNames { get; }
1919

20+
IListProxy ListProxy { get; }
21+
2022
int GetGlobalIndexForGroup(ITemplatedItemsList<TItem> group);
2123
int GetGlobalIndexOfItem(object item);
2224
ITemplatedItemsList<TItem> GetGroup(int index);

Xamarin.Forms.Core/TemplatedItemsList.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,11 @@ internal IListProxy ListProxy
194194
private set { SetValue(ListProxyPropertyKey, value); }
195195
}
196196

197+
IListProxy ITemplatedItemsList<TItem>.ListProxy
198+
{
199+
get { return ListProxy; }
200+
}
201+
197202
DataTemplate ItemTemplate
198203
{
199204
get { return (DataTemplate)_itemsView.GetValue(_itemTemplateProperty); }

Xamarin.Forms.Platform.Android/Renderers/ListViewAdapter.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,9 @@ public override int GetItemViewType(int position)
144144
{
145145
object item = null;
146146
if (_listView.IsGroupingEnabled)
147-
item = ((ITemplatedItemsView<Cell>)TemplatedItemsView.TemplatedItems.GetGroup(group)).ListProxy[row];
147+
item = TemplatedItemsView.TemplatedItems.GetGroup(group).ListProxy[row];
148148
else
149-
item = ((ITemplatedItemsView<Cell>)TemplatedItemsView.TemplatedItems).ListProxy[position];
149+
item = TemplatedItemsView.TemplatedItems.ListProxy[position];
150150
itemTemplate = selector.SelectTemplate(item, _listView);
151151
}
152152
int key;
@@ -405,7 +405,7 @@ List<Cell> GetCellsFromPosition(int position, int take)
405405
{
406406
if (_listView.CachingStrategy == ListViewCachingStrategy.RecycleElement)
407407
{
408-
var groupContent = _listView.TemplatedItems.GroupHeaderTemplate.CreateContent(group.ItemsSource, _listView) as Cell;
408+
var groupContent = _listView.TemplatedItems.GroupHeaderTemplate?.CreateContent(group.ItemsSource, _listView) as Cell;
409409
if (groupContent != null)
410410
{
411411
groupContent.Parent = _listView;

Xamarin.Forms.Platform.WinRT/ListViewRenderer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ async void OnViewChangeCompleted(object sender, SemanticZoomViewChangedEventArgs
287287
if (Device.Idiom == TargetIdiom.Phone)
288288
await Task.Delay(1);
289289

290-
IListProxy listProxy = ((ITemplatedItemsView<Cell>)til).ListProxy;
290+
IListProxy listProxy = til.ListProxy;
291291
ScrollTo(listProxy.ProxiedEnumerable, listProxy[0], ScrollToPosition.Start, true, true);
292292
}
293293

Xamarin.Forms.Platform.iOS/Renderers/ListViewRenderer.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ void OnFooterMeasureInvalidated(object sender, EventArgs eventArgs)
310310

311311
void OnGroupedCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
312312
{
313-
var til = (ITemplatedItemsList<Cell>)sender;
313+
var til = (TemplatedItemsList<ItemsView<Cell>, Cell>)sender;
314314

315315
var templatedItems = TemplatedItemsView.TemplatedItems;
316316
var groupIndex = templatedItems.IndexOf(til.HeaderContent);
@@ -919,7 +919,7 @@ protected Cell GetCellForPath(NSIndexPath indexPath)
919919
{
920920
var templatedItems = TemplatedItemsView.TemplatedItems;
921921
if (List.IsGroupingEnabled)
922-
templatedItems = (ITemplatedItemsList<Cell>)((IList)templatedItems)[indexPath.Section];
922+
templatedItems = (TemplatedItemsList<ItemsView<Cell>, Cell>)((IList)templatedItems)[indexPath.Section];
923923

924924
var cell = templatedItems[indexPath.Row];
925925
return cell;
@@ -934,7 +934,7 @@ void OnSectionPropertyChanged(object sender, PropertyChangedEventArgs e)
934934
{
935935
var currentSelected = _uiTableView.IndexPathForSelectedRow;
936936

937-
var til = (ITemplatedItemsView<Cell>)sender;
937+
var til = (TemplatedItemsList<ItemsView<Cell>, Cell>)sender;
938938
var groupIndex = ((IList)TemplatedItemsView.TemplatedItems).IndexOf(til);
939939
if (groupIndex == -1)
940940
{
@@ -968,9 +968,9 @@ int TemplateIdForPath(NSIndexPath indexPath)
968968

969969
var templatedList = TemplatedItemsView.TemplatedItems;
970970
if (List.IsGroupingEnabled)
971-
templatedList = (ITemplatedItemsList<Cell>)((IList)templatedList)[indexPath.Section];
971+
templatedList = (TemplatedItemsList<ItemsView<Cell>, Cell>)((IList)templatedList)[indexPath.Section];
972972

973-
var item = ((ITemplatedItemsView<Cell>)templatedList).ListProxy[indexPath.Row];
973+
var item = templatedList.ListProxy[indexPath.Row];
974974

975975
itemTemplate = selector.SelectTemplate(item, List);
976976
int key;

docs/Xamarin.Forms.Core/Xamarin.Forms/ITemplatedItemsList`1.xml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,22 @@
239239
<remarks>To be added.</remarks>
240240
</Docs>
241241
</Member>
242+
<Member MemberName="ListProxy">
243+
<MemberSignature Language="C#" Value="public Xamarin.Forms.IListProxy ListProxy { get; }" />
244+
<MemberSignature Language="ILAsm" Value=".property instance class Xamarin.Forms.IListProxy ListProxy" />
245+
<MemberType>Property</MemberType>
246+
<AssemblyInfo>
247+
<AssemblyVersion>2.0.0.0</AssemblyVersion>
248+
</AssemblyInfo>
249+
<ReturnValue>
250+
<ReturnType>Xamarin.Forms.IListProxy</ReturnType>
251+
</ReturnValue>
252+
<Docs>
253+
<summary>To be added.</summary>
254+
<value>To be added.</value>
255+
<remarks>To be added.</remarks>
256+
</Docs>
257+
</Member>
242258
<Member MemberName="Name">
243259
<MemberSignature Language="C#" Value="public string Name { get; set; }" />
244260
<MemberSignature Language="ILAsm" Value=".property instance string Name" />

0 commit comments

Comments
 (0)