From: E.Z. Hart Date: Wed, 9 Oct 2019 17:56:18 +0000 (-0600) Subject: Implement grouping for UWP CollectionView (#7697) X-Git-Tag: accepted/tizen/5.5/unified/20200421.150457~155^2~13 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=fd9644f3f2c40e0d738fb8573dc56e896560042b;p=platform%2Fcore%2Fcsapi%2Fxsf.git Implement grouping for UWP CollectionView (#7697) * Implement grouping for UWP CollectionView * Clean up CollectionViewSource on teardown --- diff --git a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/EmptyViewGalleries/EmptyViewStringGallery.xaml b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/EmptyViewGalleries/EmptyViewStringGallery.xaml index b851a41..143b6c6 100644 --- a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/EmptyViewGalleries/EmptyViewStringGallery.xaml +++ b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/EmptyViewGalleries/EmptyViewStringGallery.xaml @@ -13,7 +13,8 @@ - + + No items match your filter. diff --git a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/GroupingGalleries/ViewModel.cs b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/GroupingGalleries/ViewModel.cs index 59b2184..c835e75 100644 --- a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/GroupingGalleries/ViewModel.cs +++ b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/GroupingGalleries/ViewModel.cs @@ -56,7 +56,7 @@ namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.GroupingGa } )); - Add(new Team("Fantastic Four", + Add(new Team("Fantastic Four", new List { new Member("The Thing"), @@ -66,7 +66,7 @@ namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.GroupingGa } )); - Add(new Team("Defenders", + Add(new Team("Defenders", new List { new Member("Doctor Strange"), @@ -78,8 +78,8 @@ namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.GroupingGa new Member("Yellowjacket"), } )); - - Add(new Team("Heroes for Hire", + + Add(new Team("Heroes for Hire", new List { new Member("Luke Cage"), @@ -90,7 +90,7 @@ namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.GroupingGa } )); - Add(new Team("West Coast Avengers", + Add(new Team("West Coast Avengers", new List { new Member("Hawkeye"), @@ -101,7 +101,7 @@ namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.GroupingGa } )); - Add(new Team("Great Lakes Avengers", + Add(new Team("Great Lakes Avengers", new List { new Member("Squirrel Girl"), diff --git a/Xamarin.Forms.Platform.UAP/CollectionView/CollectionViewRenderer.cs b/Xamarin.Forms.Platform.UAP/CollectionView/CollectionViewRenderer.cs index be2899b..544ded3 100644 --- a/Xamarin.Forms.Platform.UAP/CollectionView/CollectionViewRenderer.cs +++ b/Xamarin.Forms.Platform.UAP/CollectionView/CollectionViewRenderer.cs @@ -14,7 +14,7 @@ using Xamarin.Forms.Platform.UAP; namespace Xamarin.Forms.Platform.UWP { - public class CollectionViewRenderer : SelectableItemsViewRenderer + public class CollectionViewRenderer : GroupableItemsViewRenderer { } } \ No newline at end of file diff --git a/Xamarin.Forms.Platform.UAP/CollectionView/FormsGridView.cs b/Xamarin.Forms.Platform.UAP/CollectionView/FormsGridView.cs index 7621375..5532099 100644 --- a/Xamarin.Forms.Platform.UAP/CollectionView/FormsGridView.cs +++ b/Xamarin.Forms.Platform.UAP/CollectionView/FormsGridView.cs @@ -1,60 +1,68 @@ using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using UWPApp = Windows.UI.Xaml.Application; -using UWPControlTemplate = Windows.UI.Xaml.Controls.ControlTemplate; +using UWPControls = Windows.UI.Xaml.Controls; namespace Xamarin.Forms.Platform.UWP { internal class FormsGridView : GridView, IEmptyView { - int _maximumRowsOrColumns; + int _span; ItemsWrapGrid _wrapGrid; ContentControl _emptyViewContentControl; FrameworkElement _emptyView; + Orientation _orientation; public FormsGridView() { - Template = (UWPControlTemplate)UWPApp.Current.Resources["FormsListViewTemplate"]; + // Using the full style for this control, because for some reason on 16299 we can't set the ControlTemplate + // (it just fails silently saying it can't find the resource key) + DefaultStyleKey = typeof(FormsGridView); - // TODO hartez 2018/06/06 09:52:16 Do we need to clean this up? If so, where? RegisterPropertyChangedCallback(ItemsPanelProperty, ItemsPanelChanged); Loaded += OnLoaded; } - public int MaximumRowsOrColumns + public int Span { - get => _maximumRowsOrColumns; + get => _span; set { - _maximumRowsOrColumns = value; + _span = value; if (_wrapGrid != null) { - _wrapGrid.MaximumRowsOrColumns = MaximumRowsOrColumns; + UpdateItemSize(); } } } - public Visibility EmptyViewVisibility - { - get { return (Visibility)GetValue(EmptyViewVisibilityProperty); } - set { SetValue(EmptyViewVisibilityProperty, value); } - } - public static readonly DependencyProperty EmptyViewVisibilityProperty = - DependencyProperty.Register(nameof(EmptyViewVisibility), typeof(Visibility), + DependencyProperty.Register(nameof(EmptyViewVisibility), typeof(Visibility), typeof(FormsGridView), new PropertyMetadata(Visibility.Collapsed)); - // TODO hartez 2018/06/06 10:01:32 Probably should just create a local enum for this? - public void UseHorizontalItemsPanel() + public Visibility EmptyViewVisibility { - ItemsPanel = - (ItemsPanelTemplate)UWPApp.Current.Resources["HorizontalGridItemsPanel"]; + get { return (Visibility)GetValue(EmptyViewVisibilityProperty); } + set { SetValue(EmptyViewVisibilityProperty, value); } } - public void UseVerticalItemsPanel() + public Orientation Orientation { - ItemsPanel = - (ItemsPanelTemplate)UWPApp.Current.Resources["VerticalGridItemsPanel"]; + get => _orientation; + set + { + _orientation = value; + if (_orientation == Orientation.Horizontal) + { + ItemsPanel = (ItemsPanelTemplate)UWPApp.Current.Resources["HorizontalGridItemsPanel"]; + ScrollViewer.SetHorizontalScrollMode(this, ScrollMode.Auto); + ScrollViewer.SetHorizontalScrollBarVisibility(this, UWPControls.ScrollBarVisibility.Auto); + } + else + { + ItemsPanel = (ItemsPanelTemplate)UWPApp.Current.Resources["VerticalGridItemsPanel"]; + } + } } void FindItemsWrapGrid() @@ -66,7 +74,25 @@ namespace Xamarin.Forms.Platform.UWP return; } - _wrapGrid.MaximumRowsOrColumns = MaximumRowsOrColumns; + _wrapGrid.SizeChanged -= WrapGridSizeChanged; + _wrapGrid.SizeChanged += WrapGridSizeChanged; + } + + void WrapGridSizeChanged(object sender, SizeChangedEventArgs e) + { + UpdateItemSize(); + } + + void UpdateItemSize() + { + if (_orientation == Orientation.Horizontal) + { + _wrapGrid.ItemHeight = _wrapGrid.ActualHeight / Span; + } + else + { + _wrapGrid.ItemWidth = _wrapGrid.ActualWidth / Span; + } } void ItemsPanelChanged(DependencyObject sender, DependencyProperty dp) @@ -100,5 +126,11 @@ namespace Xamarin.Forms.Platform.UWP _emptyViewContentControl.Content = _emptyView; } } + + protected override void PrepareContainerForItemOverride(DependencyObject element, object item) + { + GroupFooterItemTemplateContext.EnsureSelectionDisabled(element, item); + base.PrepareContainerForItemOverride(element, item); + } } -} \ No newline at end of file +} diff --git a/Xamarin.Forms.Platform.UAP/CollectionView/FormsListView.cs b/Xamarin.Forms.Platform.UAP/CollectionView/FormsListView.cs index 95a8e97..cf36d40 100644 --- a/Xamarin.Forms.Platform.UAP/CollectionView/FormsListView.cs +++ b/Xamarin.Forms.Platform.UAP/CollectionView/FormsListView.cs @@ -15,15 +15,16 @@ namespace Xamarin.Forms.Platform.UWP Template = (UWPControlTemplate)UWPApp.Current.Resources["FormsListViewTemplate"]; } + public static readonly DependencyProperty EmptyViewVisibilityProperty = + DependencyProperty.Register(nameof(EmptyViewVisibility), typeof(Visibility), + typeof(FormsListView), new PropertyMetadata(Visibility.Collapsed)); + public Visibility EmptyViewVisibility { get { return (Visibility)GetValue(EmptyViewVisibilityProperty); } set { SetValue(EmptyViewVisibilityProperty, value); } } - public static readonly DependencyProperty EmptyViewVisibilityProperty = - DependencyProperty.Register(nameof(EmptyViewVisibility), typeof(Visibility), typeof(FormsListView), new PropertyMetadata(Visibility.Collapsed)); - public void SetEmptyView(FrameworkElement emptyView) { _emptyView = emptyView; @@ -45,5 +46,11 @@ namespace Xamarin.Forms.Platform.UWP _emptyViewContentControl.Content = _emptyView; } } + + protected override void PrepareContainerForItemOverride(DependencyObject element, object item) + { + GroupFooterItemTemplateContext.EnsureSelectionDisabled(element, item); + base.PrepareContainerForItemOverride(element, item); + } } } diff --git a/Xamarin.Forms.Platform.UAP/CollectionView/GroupFooterItemTemplateContext.cs b/Xamarin.Forms.Platform.UAP/CollectionView/GroupFooterItemTemplateContext.cs new file mode 100644 index 0000000..c5b2382 --- /dev/null +++ b/Xamarin.Forms.Platform.UAP/CollectionView/GroupFooterItemTemplateContext.cs @@ -0,0 +1,23 @@ +using Windows.UI.Xaml; + +namespace Xamarin.Forms.Platform.UWP +{ + internal class GroupFooterItemTemplateContext : ItemTemplateContext + { + public GroupFooterItemTemplateContext(DataTemplate formsDataTemplate, object item, + BindableObject container, double? height = null, double? width = null, Thickness? itemSpacing = null) + : base(formsDataTemplate, item, container, height, width, itemSpacing) + { + } + + public static void EnsureSelectionDisabled(DependencyObject element, object item) + { + if (item is GroupFooterItemTemplateContext) + { + // Prevent the group footer from being selectable + (element as FrameworkElement).IsHitTestVisible = false; + } + + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Platform.UAP/CollectionView/GroupHeaderStyleSelector.cs b/Xamarin.Forms.Platform.UAP/CollectionView/GroupHeaderStyleSelector.cs new file mode 100644 index 0000000..f25f01d --- /dev/null +++ b/Xamarin.Forms.Platform.UAP/CollectionView/GroupHeaderStyleSelector.cs @@ -0,0 +1,17 @@ +using Windows.UI.Xaml.Controls; +using UWPApp = Windows.UI.Xaml.Application; +using UWPDataTemplate = Windows.UI.Xaml.DataTemplate; + +namespace Xamarin.Forms.Platform.UWP +{ + internal class GroupHeaderStyleSelector : GroupStyleSelector + { + protected override GroupStyle SelectGroupStyleCore(object group, uint level) + { + return new GroupStyle + { + HeaderTemplate = (UWPDataTemplate)UWPApp.Current.Resources["GroupHeaderTemplate"] + }; + } + } +} diff --git a/Xamarin.Forms.Platform.UAP/CollectionView/GroupTemplateContext.cs b/Xamarin.Forms.Platform.UAP/CollectionView/GroupTemplateContext.cs new file mode 100644 index 0000000..3120314 --- /dev/null +++ b/Xamarin.Forms.Platform.UAP/CollectionView/GroupTemplateContext.cs @@ -0,0 +1,50 @@ +using System.Collections; +using System.Collections.Generic; + +namespace Xamarin.Forms.Platform.UWP +{ + internal class GroupTemplateContext + { + public ItemTemplateContext HeaderItemTemplateContext { get; } + public ItemTemplateContext FooterItemTemplateContext { get; } + public object Items { get; } + + public GroupTemplateContext(ItemTemplateContext headerItemTemplateContext, + ItemTemplateContext footerItemTemplateContext, object items) + { + HeaderItemTemplateContext = headerItemTemplateContext; + FooterItemTemplateContext = footerItemTemplateContext; + + if (footerItemTemplateContext == null) + { + Items = items; + } + else + { + // UWP ListViewBase does not support group footers. So we're going to fake the footer by adding an + // extra item to the ItemsSource so the footer shows up at the end of the group. + + if (items is IList itemsList) + { + // If it's already an IList, we want to make sure to keep it that way + itemsList.Add(footerItemTemplateContext); + Items = itemsList; + return; + } + + // If the group items are not an IList, then we'll have to append the footer the hard way + + var listPlusFooter = new List(); + + foreach (var item in (items as IEnumerable)) + { + listPlusFooter.Add(item); + } + + listPlusFooter.Add(footerItemTemplateContext); + + Items = listPlusFooter; + } + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Platform.UAP/CollectionView/GroupableItemsViewRenderer.cs b/Xamarin.Forms.Platform.UAP/CollectionView/GroupableItemsViewRenderer.cs new file mode 100644 index 0000000..f44a582 --- /dev/null +++ b/Xamarin.Forms.Platform.UAP/CollectionView/GroupableItemsViewRenderer.cs @@ -0,0 +1,62 @@ +using System.ComponentModel; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Data; + +namespace Xamarin.Forms.Platform.UWP +{ + public class GroupableItemsViewRenderer : SelectableItemsViewRenderer + { + GroupableItemsView _groupableItemsView; + + protected override void SetUpNewElement(ItemsView newElement) + { + _groupableItemsView = Element as GroupableItemsView; + base.SetUpNewElement(newElement); + } + + protected override void TearDownOldElement(ItemsView oldElement) + { + base.TearDownOldElement(oldElement); + _groupableItemsView = null; + } + + protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs changedProperty) + { + base.OnElementPropertyChanged(sender, changedProperty); + + if (changedProperty.IsOneOf(GroupableItemsView.IsGroupedProperty, + GroupableItemsView.GroupFooterTemplateProperty, GroupableItemsView.GroupHeaderTemplateProperty)) + { + UpdateItemsSource(); + } + } + + protected override CollectionViewSource CreateCollectionViewSource() + { + if (_groupableItemsView != null && _groupableItemsView.IsGrouped) + { + var itemTemplate = Element.ItemTemplate; + var itemsSource = Element.ItemsSource; + + return new CollectionViewSource + { + Source = TemplatedItemSourceFactory.CreateGrouped(itemsSource, itemTemplate, + _groupableItemsView.GroupHeaderTemplate, _groupableItemsView.GroupFooterTemplate, Element), + IsSourceGrouped = true, + ItemsPath = new Windows.UI.Xaml.PropertyPath(nameof(GroupTemplateContext.Items)) + }; + } + else + { + return base.CreateCollectionViewSource(); + } + } + + protected override void UpdateItemTemplate() + { + base.UpdateItemTemplate(); + + ListViewBase.GroupStyleSelector = new GroupHeaderStyleSelector(); + } + } +} diff --git a/Xamarin.Forms.Platform.UAP/CollectionView/GroupedItemTemplateCollection.cs b/Xamarin.Forms.Platform.UAP/CollectionView/GroupedItemTemplateCollection.cs new file mode 100644 index 0000000..59ae036 --- /dev/null +++ b/Xamarin.Forms.Platform.UAP/CollectionView/GroupedItemTemplateCollection.cs @@ -0,0 +1,166 @@ +using System.Collections; +using System.Collections.ObjectModel; +using System.Collections.Specialized; + +namespace Xamarin.Forms.Platform.UWP +{ + internal class GroupedItemTemplateCollection : ObservableCollection + { + readonly IEnumerable _itemsSource; + readonly DataTemplate _itemTemplate; + readonly DataTemplate _groupHeaderTemplate; + readonly DataTemplate _groupFooterTemplate; + readonly BindableObject _container; + readonly IList _groupList; + + public GroupedItemTemplateCollection(IEnumerable itemsSource, DataTemplate itemTemplate, + DataTemplate groupHeaderTemplate, DataTemplate groupFooterTemplate, BindableObject container) + { + _itemsSource = itemsSource; + _itemTemplate = itemTemplate; + _groupHeaderTemplate = groupHeaderTemplate; + _groupFooterTemplate = groupFooterTemplate; + _container = container; + + foreach (var group in _itemsSource) + { + var groupTemplateContext = CreateGroupTemplateContext(group); + Add(groupTemplateContext); + } + + if (_itemsSource is IList groupList && _itemsSource is INotifyCollectionChanged incc) + { + _groupList = groupList; + incc.CollectionChanged += GroupsChanged; + } + } + + GroupTemplateContext CreateGroupTemplateContext(object group) + { + var groupHeaderTemplateContext = _groupHeaderTemplate != null + ? new ItemTemplateContext(_groupHeaderTemplate, group, _container) : null; + + var groupFooterTemplateContext = _groupFooterTemplate != null + ? new GroupFooterItemTemplateContext(_groupFooterTemplate, group, _container) : null; + + // This is where we'll eventually look at GroupItemPropertyName + var groupItemsList = TemplatedItemSourceFactory.Create(group as IEnumerable, _itemTemplate, _container); + + return new GroupTemplateContext(groupHeaderTemplateContext, groupFooterTemplateContext, groupItemsList); + } + + void GroupsChanged(object sender, NotifyCollectionChangedEventArgs args) + { + switch (args.Action) + { + case NotifyCollectionChangedAction.Add: + Add(args); + break; + case NotifyCollectionChangedAction.Move: + Move(args); + break; + case NotifyCollectionChangedAction.Remove: + Remove(args); + break; + case NotifyCollectionChangedAction.Replace: + Replace(args); + break; + case NotifyCollectionChangedAction.Reset: + Reset(); + break; + } + } + + void Add(NotifyCollectionChangedEventArgs args) + { + var startIndex = args.NewStartingIndex > -1 ? args.NewStartingIndex : _groupList.IndexOf(args.NewItems[0]); + + var count = args.NewItems.Count; + + for (int n = 0; n < count; n++) + { + Insert(startIndex, CreateGroupTemplateContext(args.NewItems[n])); + } + } + + void Move(NotifyCollectionChangedEventArgs args) + { + var count = args.NewItems.Count; + + if (args.OldStartingIndex > args.NewStartingIndex) + { + for (int n = 0; n < count; n++) + { + Move(args.OldStartingIndex + n, args.NewStartingIndex + n); + } + + return; + } + + for (int n = count - 1; n >= 0; n--) + { + Move(args.OldStartingIndex + n, args.NewStartingIndex + n); + } + } + + void Remove(NotifyCollectionChangedEventArgs args) + { + var startIndex = args.OldStartingIndex; + + if (startIndex < 0) + { + // INCC implementation isn't giving us enough information to know where the removed items were in the + // collection. So the best we can do is a full Reset. + Reset(); + return; + } + + var count = args.OldItems.Count; + + for (int n = startIndex + count - 1; n >= startIndex; n--) + { + RemoveAt(n); + } + } + + void Replace(NotifyCollectionChangedEventArgs args) + { + var newItemCount = args.NewItems.Count; + + if (newItemCount == args.OldItems.Count) + { + for (int n = 0; n < newItemCount; n++) + { + var index = args.OldStartingIndex + n; + var oldItem = this[index]; + var newItem = CreateGroupTemplateContext(args.NewItems[0]); + Items[index] = newItem; + var update = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, newItem, oldItem, index); + OnCollectionChanged(update); + } + } + else + { + // If we're replacing one set with an equal size set, we can do a soft reset; if not, we have to completely + // rebuild the collection + Reset(); + } + } + + void Reset() + { + Items.Clear(); + _groupList.Clear(); + + foreach (var group in _itemsSource) + { + var groupTemplateContext = CreateGroupTemplateContext(group); + _groupList.Add(group); + Items.Add(groupTemplateContext); + } + + var reset = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset); + OnCollectionChanged(reset); + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Platform.UAP/CollectionView/ItemContentControl.cs b/Xamarin.Forms.Platform.UAP/CollectionView/ItemContentControl.cs index 6533dd7..1a03930 100644 --- a/Xamarin.Forms.Platform.UAP/CollectionView/ItemContentControl.cs +++ b/Xamarin.Forms.Platform.UAP/CollectionView/ItemContentControl.cs @@ -1,7 +1,9 @@ -using Windows.UI.Xaml; +using System; +using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Xamarin.Forms.Internals; using WThickness = Windows.UI.Xaml.Thickness; +using WSize = Windows.Foundation.Size; namespace Xamarin.Forms.Platform.UWP { @@ -148,39 +150,54 @@ namespace Xamarin.Forms.Platform.UWP InvalidateMeasure(); } - protected override Windows.Foundation.Size MeasureOverride(Windows.Foundation.Size availableSize) + protected override WSize MeasureOverride(WSize availableSize) { if (_renderer == null) { return base.MeasureOverride(availableSize); } + var frameworkElement = Content as FrameworkElement; + var formsElement = _renderer.Element; if (ItemHeight != default || ItemWidth != default) { formsElement.Layout(new Rectangle(0, 0, ItemWidth, ItemHeight)); - var wsize = new Windows.Foundation.Size(ItemWidth, ItemHeight); + var wsize = new WSize(ItemWidth, ItemHeight); - (Content as FrameworkElement).Margin = new WThickness(ItemSpacing.Left, ItemSpacing.Top, ItemSpacing.Right, ItemSpacing.Bottom); + frameworkElement.Margin = new WThickness(ItemSpacing.Left, ItemSpacing.Top, ItemSpacing.Right, ItemSpacing.Bottom); - (Content as FrameworkElement).Measure(wsize); + frameworkElement.Measure(wsize); return base.MeasureOverride(wsize); } else { - Size request = formsElement.Measure(availableSize.Width, availableSize.Height, - MeasureFlags.IncludeMargins).Request; + var (width, height) = formsElement.Measure(availableSize.Width, availableSize.Height, + MeasureFlags.IncludeMargins).Request; + + width = Max(width, availableSize.Width); + height = Max(height, availableSize.Height); - formsElement.Layout(new Rectangle(0, 0, request.Width, request.Height)); + formsElement.Layout(new Rectangle(0, 0, width, height)); - var wsize = new Windows.Foundation.Size(request.Width, request.Height); + var wsize = new WSize(width, height); - (Content as FrameworkElement).Measure(wsize); + frameworkElement.Measure(wsize); return base.MeasureOverride(wsize); } } + + double Max(double requested, double available) + { + return Math.Max(requested, ClampInfinity(available)); + } + + double ClampInfinity(double value) + { + return double.IsInfinity(value) ? 0 : value; + } } } \ No newline at end of file diff --git a/Xamarin.Forms.Platform.UAP/CollectionView/ItemTemplateContext.cs b/Xamarin.Forms.Platform.UAP/CollectionView/ItemTemplateContext.cs index 255e64b..925d69c 100644 --- a/Xamarin.Forms.Platform.UAP/CollectionView/ItemTemplateContext.cs +++ b/Xamarin.Forms.Platform.UAP/CollectionView/ItemTemplateContext.cs @@ -2,6 +2,13 @@ { internal class ItemTemplateContext { + public DataTemplate FormsDataTemplate { get; } + public object Item { get; } + public BindableObject Container { get; } + public double ItemHeight { get; } + public double ItemWidth { get; } + public Thickness ItemSpacing { get; } + public ItemTemplateContext(DataTemplate formsDataTemplate, object item, BindableObject container, double? height = null, double? width = null, Thickness? itemSpacing = null) { @@ -18,12 +25,5 @@ if (itemSpacing.HasValue) ItemSpacing = itemSpacing.Value; } - - public DataTemplate FormsDataTemplate { get; } - public object Item { get; } - public BindableObject Container { get; } - public double ItemHeight { get; } - public double ItemWidth { get; } - public Thickness ItemSpacing { get; } } } \ No newline at end of file diff --git a/Xamarin.Forms.Platform.UAP/CollectionView/ItemTemplateContextList.cs b/Xamarin.Forms.Platform.UAP/CollectionView/ItemTemplateContextList.cs index 760b9c8..f745ebf 100644 --- a/Xamarin.Forms.Platform.UAP/CollectionView/ItemTemplateContextList.cs +++ b/Xamarin.Forms.Platform.UAP/CollectionView/ItemTemplateContextList.cs @@ -67,7 +67,7 @@ namespace Xamarin.Forms.Platform.UWP internal class ItemTemplateContextListEnumerator : IEnumerator { public ItemTemplateContext Current { get; private set; } - object IEnumerator.Current { get; } + object IEnumerator.Current => Current; int _currentIndex = -1; private ItemTemplateContextList _itemTemplateContextList; diff --git a/Xamarin.Forms.Platform.UAP/CollectionView/ItemsViewRenderer.cs b/Xamarin.Forms.Platform.UAP/CollectionView/ItemsViewRenderer.cs index 91977b7..ff9c83f 100644 --- a/Xamarin.Forms.Platform.UAP/CollectionView/ItemsViewRenderer.cs +++ b/Xamarin.Forms.Platform.UAP/CollectionView/ItemsViewRenderer.cs @@ -1,16 +1,9 @@ -using System; -using System.ComponentModel; -using System.Diagnostics; -using System.Linq; -using System.Runtime.CompilerServices; +using System.ComponentModel; using System.Threading.Tasks; -using Windows.Foundation; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; -using Windows.UI.Xaml.Controls.Primitives; using Windows.UI.Xaml.Data; using Xamarin.Forms.Internals; -using Xamarin.Forms.Platform.UAP; using UwpScrollBarVisibility = Windows.UI.Xaml.Controls.ScrollBarVisibility; using UWPApp = Windows.UI.Xaml.Application; using UWPDataTemplate = Windows.UI.Xaml.DataTemplate; @@ -78,7 +71,6 @@ namespace Xamarin.Forms.Platform.UWP return; } - // TODO hartez 2018-05-22 12:59 PM Handle grouping CleanUpCollectionViewSource(); @@ -109,7 +101,7 @@ namespace Xamarin.Forms.Platform.UWP } } - if (Element.ItemsSource == null) + if (Element?.ItemsSource == null) { if (CollectionViewSource?.Source is INotifyCollectionChanged incc) { @@ -213,16 +205,15 @@ namespace Xamarin.Forms.Platform.UWP // Stop listening for ScrollTo requests oldElement.ScrollToRequested -= ScrollToRequested; - if (ListViewBase != null) + if (CollectionViewSource != null) { - ListViewBase.ItemsSource = null; + CleanUpCollectionViewSource(); } - if (CollectionViewSource != null) + if (ListViewBase != null) { - CollectionViewSource.Source = null; + ListViewBase.ItemsSource = null; } - } void UpdateVerticalScrollBarVisibility() diff --git a/Xamarin.Forms.Platform.UAP/CollectionView/ItemsViewStyles.xaml b/Xamarin.Forms.Platform.UAP/CollectionView/ItemsViewStyles.xaml index ebfe707..7c3bd31 100644 --- a/Xamarin.Forms.Platform.UAP/CollectionView/ItemsViewStyles.xaml +++ b/Xamarin.Forms.Platform.UAP/CollectionView/ItemsViewStyles.xaml @@ -2,10 +2,10 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:Xamarin.Forms.Platform.UWP"> - - - - + + + + + + + + + + + diff --git a/Xamarin.Forms.Platform.UAP/CollectionView/StructuredItemsViewRenderer.cs b/Xamarin.Forms.Platform.UAP/CollectionView/StructuredItemsViewRenderer.cs index 8ede34c..8dfed02 100644 --- a/Xamarin.Forms.Platform.UAP/CollectionView/StructuredItemsViewRenderer.cs +++ b/Xamarin.Forms.Platform.UAP/CollectionView/StructuredItemsViewRenderer.cs @@ -1,6 +1,6 @@ using System.ComponentModel; using Windows.UI.Xaml.Controls; -using Xamarin.Forms.Platform.UAP; +using UWPApp = Windows.UI.Xaml.Application; namespace Xamarin.Forms.Platform.UWP { @@ -160,42 +160,29 @@ namespace Xamarin.Forms.Platform.UWP { if (ListViewBase is FormsGridView formsGridView) { - formsGridView.MaximumRowsOrColumns = ((GridItemsLayout)Layout).Span; + formsGridView.Span = ((GridItemsLayout)Layout).Span; } } } static ListViewBase CreateGridView(GridItemsLayout gridItemsLayout) { - var gridView = new FormsGridView(); - - if (gridItemsLayout.Orientation == ItemsLayoutOrientation.Horizontal) + return new FormsGridView { - gridView.UseHorizontalItemsPanel(); + Orientation = gridItemsLayout.Orientation == ItemsLayoutOrientation.Horizontal + ? Orientation.Horizontal + : Orientation.Vertical, - // TODO hartez 2018/06/06 12:13:38 Should this logic just be built into FormsGridView? - ScrollViewer.SetHorizontalScrollMode(gridView, ScrollMode.Auto); - ScrollViewer.SetHorizontalScrollBarVisibility(gridView, - Windows.UI.Xaml.Controls.ScrollBarVisibility.Auto); - } - else - { - gridView.UseVerticalItemsPanel(); - } - - gridView.MaximumRowsOrColumns = gridItemsLayout.Span; - - return gridView; + Span = gridItemsLayout.Span + }; } static ListViewBase CreateHorizontalListView() { - // TODO hartez 2018/06/05 16:18:57 Is there any performance benefit to caching the ItemsPanelTemplate lookup? - // TODO hartez 2018/05/29 15:38:04 Make sure the ItemsViewStyles.xaml xbf gets into the nuspec var horizontalListView = new Windows.UI.Xaml.Controls.ListView() { ItemsPanel = - (ItemsPanelTemplate)Windows.UI.Xaml.Application.Current.Resources["HorizontalListItemsPanel"] + (ItemsPanelTemplate)UWPApp.Current.Resources["HorizontalListItemsPanel"] }; ScrollViewer.SetHorizontalScrollMode(horizontalListView, ScrollMode.Auto); diff --git a/Xamarin.Forms.Platform.UAP/CollectionView/TemplatedItemSourceFactory.cs b/Xamarin.Forms.Platform.UAP/CollectionView/TemplatedItemSourceFactory.cs index 9009fc1..090bc6b 100644 --- a/Xamarin.Forms.Platform.UAP/CollectionView/TemplatedItemSourceFactory.cs +++ b/Xamarin.Forms.Platform.UAP/CollectionView/TemplatedItemSourceFactory.cs @@ -5,7 +5,8 @@ namespace Xamarin.Forms.Platform.UWP { internal static class TemplatedItemSourceFactory { - internal static object Create(IEnumerable itemsSource, DataTemplate itemTemplate, BindableObject container, double? itemHeight = null, double? itemWidth = null, Thickness? itemSpacing = null) + internal static object Create(IEnumerable itemsSource, DataTemplate itemTemplate, BindableObject container, + double? itemHeight = null, double? itemWidth = null, Thickness? itemSpacing = null) { switch (itemsSource) { @@ -17,5 +18,11 @@ namespace Xamarin.Forms.Platform.UWP return new ItemTemplateContextEnumerable(itemsSource, itemTemplate, container, itemHeight, itemWidth, itemSpacing); } + + internal static object CreateGrouped(IEnumerable itemsSource, DataTemplate itemTemplate, + DataTemplate groupHeaderTemplate, DataTemplate groupFooterTemplate, BindableObject container) + { + return new GroupedItemTemplateCollection(itemsSource, itemTemplate, groupHeaderTemplate, groupFooterTemplate, container); + } } } \ No newline at end of file diff --git a/Xamarin.Forms.Platform.UAP/Xamarin.Forms.Platform.UAP.csproj b/Xamarin.Forms.Platform.UAP/Xamarin.Forms.Platform.UAP.csproj index ceb5d53..0e16d97 100644 --- a/Xamarin.Forms.Platform.UAP/Xamarin.Forms.Platform.UAP.csproj +++ b/Xamarin.Forms.Platform.UAP/Xamarin.Forms.Platform.UAP.csproj @@ -13,7 +13,7 @@ UAP 10.0.16299.0 10.0.16299.0 - true + true 14 512 {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} @@ -47,6 +47,11 @@ + + + + + @@ -213,6 +218,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + MSBuild:Compile Designer @@ -234,10 +243,6 @@ Designer MSBuild:Compile - - Designer - MSBuild:Compile - Designer MSBuild:Compile