From 8d504c452bea77b546a5437b3858712663acba9e Mon Sep 17 00:00:00 2001 From: Daniel Hufnagl Date: Mon, 27 May 2024 17:19:44 +0200 Subject: [PATCH 1/6] remove null checks --- VirtualListView/Apple/CvDataSource.ios.maccatalyst.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VirtualListView/Apple/CvDataSource.ios.maccatalyst.cs b/VirtualListView/Apple/CvDataSource.ios.maccatalyst.cs index 2d2dd99..24afc87 100644 --- a/VirtualListView/Apple/CvDataSource.ios.maccatalyst.cs +++ b/VirtualListView/Apple/CvDataSource.ios.maccatalyst.cs @@ -72,7 +72,7 @@ public override UICollectionViewCell GetCell(UICollectionView collectionView, NS info.IsSelected = Handler?.IsItemSelected(info.SectionIndex, info.ItemIndex) ?? false; } - if (cell.NeedsView && info is not null && data is not null) + if (cell.NeedsView) { var view = Handler?.PositionalViewSelector?.ViewSelector?.CreateView(info, data); if (view is not null) From 90af7a5307eca752ed6d3d655b68bb1d95aa92fd Mon Sep 17 00:00:00 2001 From: Daniel Hufnagl Date: Tue, 28 May 2024 09:40:22 +0200 Subject: [PATCH 2/6] fix null exception in totalcount --- VirtualListView/PositionalViewSelector.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/VirtualListView/PositionalViewSelector.cs b/VirtualListView/PositionalViewSelector.cs index 8b93b4a..8381fb1 100644 --- a/VirtualListView/PositionalViewSelector.cs +++ b/VirtualListView/PositionalViewSelector.cs @@ -30,6 +30,10 @@ int GetTotalCount() var hasAtLeastOneItem = false; var numberOfSections = Adapter.GetNumberOfSections(); + if (Adapter is null) + { + return 0; + } if (HasGlobalHeader && numberOfSections > 0) { From 12b0880bfdf60da880c873291c490b73daf8bcda Mon Sep 17 00:00:00 2001 From: Daniel Hufnagl Date: Fri, 31 May 2024 15:49:28 +0200 Subject: [PATCH 3/6] Fix putting null check earlier --- VirtualListView/PositionalViewSelector.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/VirtualListView/PositionalViewSelector.cs b/VirtualListView/PositionalViewSelector.cs index 8381fb1..198bb9c 100644 --- a/VirtualListView/PositionalViewSelector.cs +++ b/VirtualListView/PositionalViewSelector.cs @@ -26,14 +26,15 @@ public int TotalCount int GetTotalCount() { - var sum = 0; - - var hasAtLeastOneItem = false; - var numberOfSections = Adapter.GetNumberOfSections(); if (Adapter is null) { return 0; } + + var sum = 0; + + var hasAtLeastOneItem = false; + var numberOfSections = Adapter.GetNumberOfSections(); if (HasGlobalHeader && numberOfSections > 0) { From 137e2af5f8ff05dfd9a2a4078e5e40e12ed87096 Mon Sep 17 00:00:00 2001 From: redth Date: Fri, 7 Jun 2024 13:21:27 -0400 Subject: [PATCH 4/6] Still check info, but not data Headers and footers can have null/no data but they should still have info --- .../Apple/CvDataSource.ios.maccatalyst.cs | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/VirtualListView/Apple/CvDataSource.ios.maccatalyst.cs b/VirtualListView/Apple/CvDataSource.ios.maccatalyst.cs index 24afc87..015893b 100644 --- a/VirtualListView/Apple/CvDataSource.ios.maccatalyst.cs +++ b/VirtualListView/Apple/CvDataSource.ios.maccatalyst.cs @@ -70,23 +70,19 @@ public override UICollectionViewCell GetCell(UICollectionView collectionView, NS info.IsSelected = false; else info.IsSelected = Handler?.IsItemSelected(info.SectionIndex, info.ItemIndex) ?? false; - } - - if (cell.NeedsView) - { - var view = Handler?.PositionalViewSelector?.ViewSelector?.CreateView(info, data); - if (view is not null) - cell.SetupView(view); - } + + if (cell.NeedsView) + { + var view = Handler?.PositionalViewSelector?.ViewSelector?.CreateView(info, data); + if (view is not null) + cell.SetupView(view); + } - if (info is not null) - { cell.UpdatePosition(info); - if (data is not null && (cell.VirtualView?.TryGetTarget(out var cellVirtualView) ?? false)) + if (cell.VirtualView?.TryGetTarget(out var cellVirtualView) ?? false) { Handler?.PositionalViewSelector?.ViewSelector?.RecycleView(info, data, cellVirtualView); - Handler?.VirtualView?.ViewSelector?.ViewAttached(info, cellVirtualView); } } From 685b7729ea6a5eac8f57034aa9549d520c1e0ee3 Mon Sep 17 00:00:00 2001 From: redth Date: Fri, 7 Jun 2024 14:01:20 -0400 Subject: [PATCH 5/6] Cleanup --- VirtualListView/Apple/CvCell.ios.maccatalyst.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/VirtualListView/Apple/CvCell.ios.maccatalyst.cs b/VirtualListView/Apple/CvCell.ios.maccatalyst.cs index 517b642..ce8b4fa 100644 --- a/VirtualListView/Apple/CvCell.ios.maccatalyst.cs +++ b/VirtualListView/Apple/CvCell.ios.maccatalyst.cs @@ -1,8 +1,6 @@ using CoreGraphics; using Foundation; using Microsoft.Maui.Platform; -using Microsoft.VisualBasic; -using System.Diagnostics.CodeAnalysis; using UIKit; namespace Microsoft.Maui; From d2485b5f9dd0f681ba34da87a8fcccbeba19d03f Mon Sep 17 00:00:00 2001 From: redth Date: Fri, 7 Jun 2024 14:03:04 -0400 Subject: [PATCH 6/6] Add more nullability The data can be null for global header / footer items, so adding some nullability to try and validate if anything else was expecting this. --- VirtualListView/Controls/VirtualListView.cs | 51 ++++++++++--------- .../VirtualListViewItemTemplateSelector.cs | 8 +-- VirtualListView/IVirtualListViewSelector.cs | 9 ++-- VirtualListView/VirtualListViewExtensions.cs | 5 +- 4 files changed, 39 insertions(+), 34 deletions(-) diff --git a/VirtualListView/Controls/VirtualListView.cs b/VirtualListView/Controls/VirtualListView.cs index a6d0d73..35e917c 100644 --- a/VirtualListView/Controls/VirtualListView.cs +++ b/VirtualListView/Controls/VirtualListView.cs @@ -1,4 +1,5 @@ -using System.Windows.Input; +#nullable enable +using System.Windows.Input; using Microsoft.Maui.Adapters; namespace Microsoft.Maui.Controls; @@ -21,7 +22,7 @@ public IVirtualListViewAdapter Adapter BindableProperty.Create(nameof(Adapter), typeof(IVirtualListViewAdapter), typeof(VirtualListView), default); - public IView GlobalHeader + public IView? GlobalHeader { get => (IView)GetValue(GlobalHeaderProperty); set => SetValue(GlobalHeaderProperty, value); @@ -39,7 +40,7 @@ public bool IsHeaderVisible public static readonly BindableProperty IsHeaderVisibleProperty = BindableProperty.Create(nameof(IsHeaderVisible), typeof(bool), typeof(VirtualListView), true); - public IView GlobalFooter + public IView? GlobalFooter { get => (IView)GetValue(GlobalFooterProperty); set => SetValue(GlobalFooterProperty, value); @@ -59,7 +60,7 @@ public bool IsFooterVisible BindableProperty.Create(nameof(IsFooterVisible), typeof(bool), typeof(VirtualListView), true); - public DataTemplate ItemTemplate + public DataTemplate? ItemTemplate { get => (DataTemplate)GetValue(ItemTemplateProperty); set => SetValue(ItemTemplateProperty, value); @@ -68,7 +69,7 @@ public DataTemplate ItemTemplate public static readonly BindableProperty ItemTemplateProperty = BindableProperty.Create(nameof(ItemTemplate), typeof(DataTemplate), typeof(VirtualListView), default); - public VirtualListViewItemTemplateSelector ItemTemplateSelector + public VirtualListViewItemTemplateSelector? ItemTemplateSelector { get => (VirtualListViewItemTemplateSelector)GetValue(ItemTemplateSelectorProperty); set => SetValue(ItemTemplateSelectorProperty, value); @@ -97,7 +98,7 @@ public ScrollBarVisibility HorizontalScrollbarVisibility public static readonly BindableProperty HorizontalScrollbarVisibilityProperty = BindableProperty.Create(nameof(HorizontalScrollbarVisibility), typeof(ScrollBarVisibility), typeof(VirtualListView), ScrollBarVisibility.Default); - public DataTemplate SectionHeaderTemplate + public DataTemplate? SectionHeaderTemplate { get => (DataTemplate)GetValue(SectionHeaderTemplateProperty); set => SetValue(SectionHeaderTemplateProperty, value); @@ -106,7 +107,7 @@ public DataTemplate SectionHeaderTemplate public static readonly BindableProperty SectionHeaderTemplateProperty = BindableProperty.Create(nameof(SectionHeaderTemplate), typeof(DataTemplate), typeof(VirtualListView), default); - public VirtualListViewSectionTemplateSelector SectionHeaderTemplateSelector + public VirtualListViewSectionTemplateSelector? SectionHeaderTemplateSelector { get => (VirtualListViewSectionTemplateSelector)GetValue(SectionHeaderTemplateSelectorProperty); set => SetValue(SectionHeaderTemplateSelectorProperty, value); @@ -117,7 +118,7 @@ public VirtualListViewSectionTemplateSelector SectionHeaderTemplateSelector - public DataTemplate SectionFooterTemplate + public DataTemplate? SectionFooterTemplate { get => (DataTemplate)GetValue(SectionFooterTemplateProperty); set => SetValue(SectionFooterTemplateProperty, value); @@ -126,7 +127,7 @@ public DataTemplate SectionFooterTemplate public static readonly BindableProperty SectionFooterTemplateProperty = BindableProperty.Create(nameof(SectionFooterTemplate), typeof(DataTemplate), typeof(VirtualListView), default); - public VirtualListViewSectionTemplateSelector SectionFooterTemplateSelector + public VirtualListViewSectionTemplateSelector? SectionFooterTemplateSelector { get => (VirtualListViewSectionTemplateSelector)GetValue(SectionFooterTemplateSelectorProperty); set => SetValue(SectionFooterTemplateSelectorProperty, value); @@ -159,7 +160,7 @@ void IVirtualListView.Refresh(Action completionCallback) OnRefresh?.Invoke(this, new RefreshEventArgs(completionCallback)); } - public ICommand RefreshCommand + public ICommand? RefreshCommand { get => (ICommand)GetValue(RefreshCommandProperty); set => SetValue(RefreshCommandProperty, value); @@ -168,9 +169,9 @@ public ICommand RefreshCommand public static readonly BindableProperty RefreshCommandProperty = BindableProperty.Create(nameof(RefreshCommand), typeof(ICommand), typeof(VirtualListView), default); - public Color RefreshAccentColor + public Color? RefreshAccentColor { - get => (Color)GetValue(RefreshAccentColorProperty); + get => (Color?)GetValue(RefreshAccentColorProperty); set => SetValue(RefreshAccentColorProperty, value); } @@ -196,14 +197,14 @@ public ListOrientation Orientation BindableProperty.Create(nameof(Orientation), typeof(ListOrientation), typeof(VirtualListView), ListOrientation.Vertical); - public View EmptyView + public IView? EmptyView { - get => (View)GetValue(EmptyViewProperty); + get => (IView)GetValue(EmptyViewProperty); set => SetValue(EmptyViewProperty, value); } public static readonly BindableProperty EmptyViewProperty = - BindableProperty.Create(nameof(EmptyView), typeof(View), typeof(VirtualListView), null, + BindableProperty.Create(nameof(EmptyView), typeof(IView), typeof(VirtualListView), null, propertyChanged: (bobj, oldValue, newValue) => { if (bobj is VirtualListView virtualListView) @@ -216,13 +217,13 @@ public View EmptyView } }); - IView IVirtualListView.EmptyView => EmptyView; + IView? IVirtualListView.EmptyView => EmptyView; public IVirtualListViewSelector ViewSelector => this; - public IView Header => GlobalHeader; - public IView Footer => GlobalFooter; + public IView? Header => GlobalHeader; + public IView? Footer => GlobalFooter; public event EventHandler OnScrolled; @@ -239,7 +240,7 @@ public void Scrolled(double x, double y) public static readonly BindableProperty ScrolledCommandProperty = BindableProperty.Create(nameof(ScrolledCommand), typeof(ICommand), typeof(VirtualListView), default); - public ICommand ScrolledCommand + public ICommand? ScrolledCommand { get => (ICommand)GetValue(ScrolledCommandProperty); set => SetValue(ScrolledCommandProperty, value); @@ -256,7 +257,7 @@ public ICommand ScrolledCommand vlv.RaiseSelectedItemsChanged(oldSelection.ToArray(), newSelection.ToArray()); } }); - public IList SelectedItems + public IList? SelectedItems { get => (IList)GetValue(SelectedItemsProperty); set => SetValue(SelectedItemsProperty, value ?? Array.Empty()); @@ -314,9 +315,9 @@ public void SelectItem(ItemPosition itemPosition) else if (SelectionMode == Maui.SelectionMode.Multiple) { var current = SelectedItems; - if (!current.Contains(itemPosition)) + if (current is null || !current.Contains(itemPosition)) { - SelectedItems = current.Append(itemPosition).ToArray(); + SelectedItems = (current ?? []).Append(itemPosition).ToArray(); } } } @@ -338,7 +339,7 @@ public bool SectionHasHeader(int sectionIndex) public bool SectionHasFooter(int sectionIndex) => SectionFooterTemplateSelector != null || SectionFooterTemplate != null; - public IView CreateView(PositionInfo position, object data) + public IView? CreateView(PositionInfo position, object? data) => position.Kind switch { PositionKind.Item => @@ -357,7 +358,7 @@ public IView CreateView(PositionInfo position, object data) _ => default }; - public void RecycleView(PositionInfo position, object data, IView view) + public void RecycleView(PositionInfo position, object? data, IView view) { if (view is View controlsView) { @@ -370,7 +371,7 @@ public void RecycleView(PositionInfo position, object data, IView view) } } - public string GetReuseId(PositionInfo position, object data) + public string GetReuseId(PositionInfo position, object? data) => position.Kind switch { PositionKind.Item => diff --git a/VirtualListView/Controls/VirtualListViewItemTemplateSelector.cs b/VirtualListView/Controls/VirtualListViewItemTemplateSelector.cs index f2c93e6..72e4780 100644 --- a/VirtualListView/Controls/VirtualListViewItemTemplateSelector.cs +++ b/VirtualListView/Controls/VirtualListViewItemTemplateSelector.cs @@ -1,11 +1,13 @@ -namespace Microsoft.Maui.Controls; +#nullable enable + +namespace Microsoft.Maui.Controls; public abstract class VirtualListViewItemTemplateSelector { - public abstract DataTemplate SelectTemplate(object item, int sectionIndex, int itemIndex); + public abstract DataTemplate SelectTemplate(object? item, int sectionIndex, int itemIndex); } public abstract class VirtualListViewSectionTemplateSelector { - public abstract DataTemplate SelectTemplate(object section, int sectionIndex); + public abstract DataTemplate SelectTemplate(object? section, int sectionIndex); } diff --git a/VirtualListView/IVirtualListViewSelector.cs b/VirtualListView/IVirtualListViewSelector.cs index e848eee..824eba6 100644 --- a/VirtualListView/IVirtualListViewSelector.cs +++ b/VirtualListView/IVirtualListViewSelector.cs @@ -1,13 +1,14 @@ -namespace Microsoft.Maui; +#nullable enable +namespace Microsoft.Maui; public interface IVirtualListViewSelector { bool SectionHasHeader(int sectionIndex); bool SectionHasFooter(int sectionIndex); - IView CreateView(PositionInfo position, object data); - void RecycleView(PositionInfo position, object data, IView view); - string GetReuseId(PositionInfo position, object data); + IView? CreateView(PositionInfo position, object? data); + void RecycleView(PositionInfo position, object? data, IView view); + string GetReuseId(PositionInfo position, object? data); void ViewDetached(PositionInfo position, IView view) { } diff --git a/VirtualListView/VirtualListViewExtensions.cs b/VirtualListView/VirtualListViewExtensions.cs index 4142306..951e1e6 100644 --- a/VirtualListView/VirtualListViewExtensions.cs +++ b/VirtualListView/VirtualListViewExtensions.cs @@ -1,10 +1,11 @@ -using Microsoft.Maui.Adapters; +#nullable enable +using Microsoft.Maui.Adapters; namespace Microsoft.Maui; internal static class VirtualListViewExtensions { - public static object DataFor(this IVirtualListViewAdapter vlva, PositionKind kind, int sectionIndex, int itemIndex) + public static object? DataFor(this IVirtualListViewAdapter vlva, PositionKind kind, int sectionIndex, int itemIndex) => kind switch { PositionKind.Item => vlva.GetItem(sectionIndex, itemIndex),