Check ItemsSource for null in ListViewRenderer; fixes #2929 (#2934)

This commit is contained in:
E.Z. Hart 2018-06-04 17:10:15 -06:00 коммит произвёл Rui Marinho
Родитель 4185d8d6cc
Коммит 6be203ab2e
3 изменённых файлов: 127 добавлений и 3 удалений

Просмотреть файл

@ -0,0 +1,113 @@
using System.Collections.Generic;
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.ListView)]
#endif
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Github, 2929, "[UWP] ListView with null ItemsSource crashes on 3.0.0.530893",
PlatformAffected.UWP)]
public class Issue2929 : TestContentPage
{
const string Success = "Success";
protected override void Init()
{
var lv = new ListView();
var instructions = new Label { Text = $"If the '{Success}' label is visible, this test has passed." };
Content = new StackLayout
{
Children =
{
instructions,
new Label { Text = Success },
lv
}
};
}
#if UITEST
[Test]
public void NullItemSourceDoesNotCrash()
{
// If we can see the Success label, it means we didn't crash.
RunningApp.WaitForElement(Success);
}
#endif
}
#if UITEST
[Category(UITestCategories.ListView)]
#endif
[Preserve(AllMembers = true)]
[Issue(IssueTracker.None, 99, "Make sure setting ItemSource to null doesn't blow up",
PlatformAffected.UWP)]
public class SetListViewItemSourceToNull : TestContentPage
{
const string Success = "Success";
const string Go = "Go";
protected override void Init()
{
var lv = new ListView();
var itemSource = new List<string>
{
"One",
"Two",
"Three"
};
lv.ItemsSource = itemSource;
var result = new Label();
var button = new Button { Text = Go };
button.Clicked += (sender, args) =>
{
lv.ItemsSource = null;
result.Text = Success;
};
var instructions = new Label
{
Text = $"Tap the '{Go}' button. If the '{Success}' label is visible, this test has passed."
};
Content = new StackLayout
{
Children =
{
instructions,
button,
result,
lv
}
};
}
#if UITEST
[Test]
public void SettingItemsSourceToNullDoesNotCrash()
{
RunningApp.WaitForElement(Go);
RunningApp.Tap(Go);
// If we can see the Success label, it means we didn't crash.
RunningApp.WaitForElement(Success);
}
#endif
}
}

Просмотреть файл

@ -299,6 +299,7 @@
<SubType>Code</SubType>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Issue2681.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue2929.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue2983.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue2963.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue2981.cs" />

Просмотреть файл

@ -25,8 +25,8 @@ namespace Xamarin.Forms.Platform.UWP
public class ListViewRenderer : ViewRenderer<ListView, FrameworkElement>
{
ITemplatedItemsView<Cell> TemplatedItemsView => Element;
ObservableCollection<object> SourceItems => context?.Source as ObservableCollection<object>;
CollectionViewSource context;
ObservableCollection<object> SourceItems => _context?.Source as ObservableCollection<object>;
CollectionViewSource _context;
bool _itemWasClicked;
bool _subscribedToItemClick;
bool _subscribedToTapped;
@ -83,12 +83,17 @@ namespace Xamarin.Forms.Platform.UWP
void ReloadData()
{
if (Element?.ItemsSource == null)
{
return;
}
var allSourceItems = new ObservableCollection<object>();
foreach (var item in Element.ItemsSource)
allSourceItems.Add(item);
// WinRT throws an exception if you set ItemsSource directly to a CVS, so bind it.
List.DataContext = context = new CollectionViewSource
List.DataContext = _context = new CollectionViewSource
{
Source = allSourceItems,
IsSourceGrouped = Element.IsGroupingEnabled
@ -269,6 +274,11 @@ namespace Xamarin.Forms.Platform.UWP
void UpdateGrouping()
{
if (Element?.ItemsSource == null)
{
return;
}
bool grouping = Element.IsGroupingEnabled;
((CollectionViewSource)List.DataContext).IsSourceGrouped = grouping;