summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla55745.cs
blob: e83b927e94c04cc5b8fca4839e79b7a0a98c6597 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;
using System.ComponentModel;
using System.Collections.Generic;
using System.Collections.ObjectModel;

#if UITEST
using Xamarin.UITest;
using NUnit.Framework;
#endif

// Apply the default category of "Issues" to all of the tests in this assembly
// We use this as a catch-all for tests which haven't been individually categorized
#if UITEST
[assembly: NUnit.Framework.Category("Issues")]
#endif

namespace Xamarin.Forms.Controls.Issues
{
	[Preserve(AllMembers = true)]
	[Issue(IssueTracker.Bugzilla, 55745, "[iOS] NRE in ListView with HasUnevenRows=true after changing content and rebinding", PlatformAffected.iOS)]
	public class Bugzilla55745 : TestContentPage
	{
		const string ButtonId = "button";
		ViewModel vm;

		protected override void Init()
		{
			vm = new ViewModel();
			BindingContext = vm;

			var listView = new ListView
			{
				HasUnevenRows = true,
				ItemTemplate = new DataTemplate(() =>
				{
					var label1 = new Label();
					label1.SetBinding(Label.TextProperty, nameof(DataViewModel.TextOne));
					var label2 = new Label();
					label2.SetBinding(Label.TextProperty, nameof(DataViewModel.TextTwo));
					return new ViewCell { View = new StackLayout { Children = { label1, label2 } } };
				})
			};

			listView.SetBinding(ListView.ItemsSourceProperty, nameof(vm.MyCollection));

			var button = new Button { Text = "Tap me twice. The app should not crash.", AutomationId = ButtonId };
			button.Clicked += Button_Clicked;

			Content = new StackLayout { Children = { button, listView } };
		}

		void Button_Clicked(object sender, System.EventArgs e)
		{
			vm.ToggleContent();
		}

		[Preserve(AllMembers = true)]
		class DataViewModel : INotifyPropertyChanged
		{
			string mTextOne;

			string mTextTwo;

			public event PropertyChangedEventHandler PropertyChanged;

			public string TextOne
			{
				get { return mTextOne; }
				set
				{
					mTextOne = value;
					OnPropertyChanged(nameof(TextOne));
				}
			}

			public string TextTwo
			{
				get { return mTextTwo; }
				set
				{
					mTextTwo = value;
					OnPropertyChanged(nameof(TextTwo));
				}
			}

			protected virtual void OnPropertyChanged(string propertyName)
			{
				PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
			}
		}

		[Preserve(AllMembers = true)]
		class ViewModel : INotifyPropertyChanged
		{
			public List<DataViewModel> myList = new List<DataViewModel>()
			{
				new DataViewModel() { TextOne = "Super", TextTwo = "Juuu"},
				new DataViewModel() { TextOne = "Michael", TextTwo = "Maier"},
				new DataViewModel() { TextOne = "House", TextTwo = "Cat"},
				new DataViewModel() { TextOne = "Flower", TextTwo = "Rock"},
				new DataViewModel() { TextOne = "Job", TextTwo = "Dog"},
				new DataViewModel() { TextOne = "Super", TextTwo = "Juuu"},
				new DataViewModel() { TextOne = "Michael", TextTwo = "Maier"},
				new DataViewModel() { TextOne = "House", TextTwo = "Cat"},
				new DataViewModel() { TextOne = "Flower", TextTwo = "Rock"},
				new DataViewModel() { TextOne = "Job", TextTwo = "Dog"}
			};

			ObservableCollection<DataViewModel> mMyCollection;

			DataViewModel mSelectedData;

			public ViewModel()
			{
				MyCollection = new ObservableCollection<DataViewModel>(myList);
			}

			public event PropertyChangedEventHandler PropertyChanged;

			public ObservableCollection<DataViewModel> MyCollection
			{
				get
				{
					return mMyCollection;
				}
				set
				{
					mMyCollection = value;
					OnPropertyChanged(nameof(MyCollection));
				}
			}

			public DataViewModel SelectedData
			{
				get { return mSelectedData; }
				set
				{
					mSelectedData = value;
					OnPropertyChanged(nameof(SelectedData));
				}
			}

			public void ToggleContent()
			{
				if (MyCollection.Count < 3)
				{
					MyCollection.Clear();
					MyCollection = new ObservableCollection<DataViewModel>(myList);
				}
				else
				{
					MyCollection.Clear();
					MyCollection.Add(myList[2]);
				}
			}

			protected virtual void OnPropertyChanged(string propertyName)
			{
				PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
			}
		}

#if UITEST
		[Test]
		public void Bugzilla55745Test()
		{
			RunningApp.WaitForElement(q => q.Marked(ButtonId));
			RunningApp.Tap(q => q.Marked(ButtonId));
			RunningApp.Tap(q => q.Marked(ButtonId));
		}
#endif
	}
}