diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue4314.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue4314.cs
new file mode 100644
index 00000000000..b57526eb2ab
--- /dev/null
+++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue4314.cs
@@ -0,0 +1,57 @@
+using Xamarin.Forms.CustomAttributes;
+using Xamarin.Forms.Internals;
+
+#if UITEST
+using Xamarin.Forms.Core.UITests;
+using Xamarin.UITest;
+using NUnit.Framework;
+#endif
+
+namespace Xamarin.Forms.Controls.Issues
+{
+#if UITEST
+ [Category(UITestCategories.ContextActions)]
+#endif
+ [Preserve(AllMembers = true)]
+ [Issue(IssueTracker.Github, 4314, "When ListView items is removed and it is empty, Xamarin Forms crash", PlatformAffected.iOS)]
+ public class Issue4314 : TestNavigationPage // or TestMasterDetailPage, etc ...
+ {
+ const string Success = "Success";
+#if !UITEST
+ MessagesViewModel viewModel;
+ protected override void Init()
+ {
+ var page = new ContextActionsGallery(false, true, 2) { Title = "Swipe and delete both" };
+ viewModel = page.BindingContext as MessagesViewModel;
+ viewModel.Messages.CollectionChanged += (s, e) =>
+ {
+ if (viewModel.Messages.Count == 0)
+ {
+ Navigation.PushAsync(new ContentPage { Title = "Success", Content = new Label { Text = Success } });
+ }
+ };
+ Navigation.PushAsync(page);
+ }
+#else
+ protected override void Init()
+ {
+ }
+#endif
+#if UITEST && __IOS__
+ [Test]
+ public void Issue4341Test()
+ {
+ RunningApp.WaitForElement(c=> c.Marked("Email"));
+ RunningApp.ActivateContextMenu("Subject Line 0");
+ RunningApp.WaitForElement("Delete");
+ RunningApp.Tap("Delete");
+ RunningApp.ActivateContextMenu("Subject Line 1");
+ RunningApp.Tap("Delete");
+ RunningApp.WaitForElement(c=> c.Marked(Success));
+ RunningApp.Back();
+ RunningApp.WaitForElement(c => c.Marked("Email"));
+ RunningApp.SwipeRightToLeft();
+ }
+#endif
+ }
+}
\ No newline at end of file
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 b53cbe8dd2c..f65145b0e51 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
@@ -820,6 +820,7 @@
+
diff --git a/Xamarin.Forms.Controls/GalleryPages/EditableList.cs b/Xamarin.Forms.Controls/GalleryPages/EditableList.cs
index e2265726bf7..3f98473deaf 100644
--- a/Xamarin.Forms.Controls/GalleryPages/EditableList.cs
+++ b/Xamarin.Forms.Controls/GalleryPages/EditableList.cs
@@ -7,9 +7,9 @@ namespace Xamarin.Forms.Controls
{
internal class MessagesViewModel : ViewModelBase
{
- public MessagesViewModel()
+ public MessagesViewModel(int messagesCount)
{
- Messages = new ObservableCollection (Enumerable.Range (0, 100).Select (i => {
+ Messages = new ObservableCollection (Enumerable.Range (0, messagesCount).Select (i => {
return new MessageViewModel { Subject = "Subject Line " + i, MessagePreview = "Lorem ipsum dolorem monkeys bonkers " + i };
}));
@@ -26,7 +26,7 @@ public ObservableCollection Messages
}
[Preserve (AllMembers = true)]
- internal class MessageViewModel : ViewModelBase
+ public class MessageViewModel : ViewModelBase
{
public MessageViewModel()
{
@@ -86,13 +86,16 @@ public MessageCell()
}
}
- public ContextActionsGallery (bool tableView = false)
+ public ContextActionsGallery (bool tableView = false, bool hasUnevenRows = false, int messagesCount = 100)
{
- BindingContext = new MessagesViewModel();
+ BindingContext = new MessagesViewModel(messagesCount);
View list;
if (!tableView) {
- list = new ListView();
+ list = new ListView
+ {
+ HasUnevenRows = hasUnevenRows
+ };
list.SetBinding (ListView.ItemsSourceProperty, "Messages");
((ListView)list).ItemTemplate = new DataTemplate (typeof (MessageCell));
} else {
diff --git a/Xamarin.Forms.Platform.iOS/ContextActionCell.cs b/Xamarin.Forms.Platform.iOS/ContextActionCell.cs
index 480651a5e2b..6760cc531fc 100644
--- a/Xamarin.Forms.Platform.iOS/ContextActionCell.cs
+++ b/Xamarin.Forms.Platform.iOS/ContextActionCell.cs
@@ -276,6 +276,7 @@ protected override void Dispose(bool disposing)
if (_scroller != null)
{
+ _scroller.Delegate = null;
_scroller.Dispose();
_scroller = null;
}
diff --git a/Xamarin.Forms.Platform.iOS/ContextScrollViewDelegate.cs b/Xamarin.Forms.Platform.iOS/ContextScrollViewDelegate.cs
index 22f57fc3e85..82a674772bd 100644
--- a/Xamarin.Forms.Platform.iOS/ContextScrollViewDelegate.cs
+++ b/Xamarin.Forms.Platform.iOS/ContextScrollViewDelegate.cs
@@ -125,7 +125,7 @@ public override void Scrolled(UIScrollView scrollView)
RestoreHighlight(scrollView);
s_scrollViewBeingScrolled = null;
- ClearCloserRecognizer(scrollView);
+ ClearCloserRecognizer(GetContextCell(scrollView));
ClosedCallback?.Invoke();
}
}
@@ -133,7 +133,7 @@ public override void Scrolled(UIScrollView scrollView)
public void Unhook(UIScrollView scrollView)
{
RestoreHighlight(scrollView);
- ClearCloserRecognizer(scrollView);
+ ClearCloserRecognizer(GetContextCell(scrollView));
}
public override void WillEndDragging(UIScrollView scrollView, PointF velocity, ref PointF targetContentOffset)
@@ -158,36 +158,35 @@ public override void WillEndDragging(UIScrollView scrollView, PointF velocity, r
while (view.Superview != null)
{
view = view.Superview;
-
- NSAction close = () =>
- {
- if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
- RestoreHighlight(scrollView);
-
- IsOpen = false;
- scrollView.SetContentOffset(new PointF(0, 0), true);
-
- ClearCloserRecognizer(scrollView);
- };
-
var table = view as UITableView;
if (table != null)
{
+ ContextActionsCell contentCell = GetContextCell(scrollView);
+ NSAction close = () =>
+ {
+ if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
+ RestoreHighlight(scrollView);
+
+ IsOpen = false;
+ scrollView.SetContentOffset(new PointF(0, 0), true);
+ ClearCloserRecognizer(contentCell);
+ contentCell = null;
+ };
+
_table = table;
_globalCloser = new GlobalCloseContextGestureRecognizer(scrollView, close);
_globalCloser.ShouldRecognizeSimultaneously = (recognizer, r) => r == _table.PanGestureRecognizer;
table.AddGestureRecognizer(_globalCloser);
_closer = new UITapGestureRecognizer(close);
- var cell = GetContextCell(scrollView);
- cell.ContentCell.AddGestureRecognizer(_closer);
+ contentCell.AddGestureRecognizer(_closer);
}
}
}
}
else
{
- ClearCloserRecognizer(scrollView);
+ ClearCloserRecognizer(GetContextCell(scrollView));
IsOpen = false;
targetContentOffset = new PointF(0, 0);
@@ -234,13 +233,12 @@ protected override void Dispose(bool disposing)
base.Dispose(disposing);
}
- void ClearCloserRecognizer(UIScrollView scrollView)
+ void ClearCloserRecognizer(ContextActionsCell cell)
{
if (_globalCloser == null || _globalCloser.State == UIGestureRecognizerState.Cancelled)
return;
- var cell = GetContextCell(scrollView);
- cell.ContentCell.RemoveGestureRecognizer(_closer);
+ cell?.ContentCell?.RemoveGestureRecognizer(_closer);
_closer.Dispose();
_closer = null;
@@ -252,9 +250,9 @@ void ClearCloserRecognizer(UIScrollView scrollView)
ContextActionsCell GetContextCell(UIScrollView scrollView)
{
- var view = scrollView.Superview.Superview;
+ var view = scrollView?.Superview?.Superview;
var cell = view as ContextActionsCell;
- while (view.Superview != null)
+ while (view?.Superview != null)
{
cell = view as ContextActionsCell;
if (cell != null)