<CollectionView x:Name="CollectionView" Grid.Row="1">
<CollectionView.ItemsLayout>
- <GridItemsLayout Span="3" Orientation="Vertical"></GridItemsLayout>
+ <!--GridItemsLayout Span="3" Orientation="Vertical"></GridItemsLayout>-->
+ <LinearItemsLayout Orientation="Vertical"></LinearItemsLayout>
</CollectionView.ItemsLayout>
<CollectionView.EmptyView>
No items match your filter.
}
));
- Add(new Team("Fantastic Four",
+ Add(new Team("Fantastic Four",
new List<Member>
{
new Member("The Thing"),
}
));
- Add(new Team("Defenders",
+ Add(new Team("Defenders",
new List<Member>
{
new Member("Doctor Strange"),
new Member("Yellowjacket"),
}
));
-
- Add(new Team("Heroes for Hire",
+
+ Add(new Team("Heroes for Hire",
new List<Member>
{
new Member("Luke Cage"),
}
));
- Add(new Team("West Coast Avengers",
+ Add(new Team("West Coast Avengers",
new List<Member>
{
new Member("Hawkeye"),
}
));
- Add(new Team("Great Lakes Avengers",
+ Add(new Team("Great Lakes Avengers",
new List<Member>
{
new Member("Squirrel Girl"),
namespace Xamarin.Forms.Platform.UWP
{
- public class CollectionViewRenderer : SelectableItemsViewRenderer
+ public class CollectionViewRenderer : GroupableItemsViewRenderer
{
}
}
\ No newline at end of file
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()
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)
_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
+}
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;
_emptyViewContentControl.Content = _emptyView;
}
}
+
+ protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
+ {
+ GroupFooterItemTemplateContext.EnsureSelectionDisabled(element, item);
+ base.PrepareContainerForItemOverride(element, item);
+ }
}
}
--- /dev/null
+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
--- /dev/null
+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"]
+ };
+ }
+ }
+}
--- /dev/null
+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<object>();
+
+ foreach (var item in (items as IEnumerable))
+ {
+ listPlusFooter.Add(item);
+ }
+
+ listPlusFooter.Add(footerItemTemplateContext);
+
+ Items = listPlusFooter;
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+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();
+ }
+ }
+}
--- /dev/null
+using System.Collections;
+using System.Collections.ObjectModel;
+using System.Collections.Specialized;
+
+namespace Xamarin.Forms.Platform.UWP
+{
+ internal class GroupedItemTemplateCollection : ObservableCollection<GroupTemplateContext>
+ {
+ 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
-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
{
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
{
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)
{
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
internal class ItemTemplateContextListEnumerator : IEnumerator<ItemTemplateContext>
{
public ItemTemplateContext Current { get; private set; }
- object IEnumerator.Current { get; }
+ object IEnumerator.Current => Current;
int _currentIndex = -1;
private ItemTemplateContextList _itemTemplateContextList;
-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;
return;
}
- // TODO hartez 2018-05-22 12:59 PM Handle grouping
CleanUpCollectionViewSource();
}
}
- if (Element.ItemsSource == null)
+ if (Element?.ItemsSource == null)
{
if (CollectionViewSource?.Source is INotifyCollectionChanged incc)
{
// 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()
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">
-
- <ItemsPanelTemplate x:Key="HorizontalListItemsPanel">
- <ItemsStackPanel Orientation="Horizontal" />
- </ItemsPanelTemplate>
+
+ <ItemsPanelTemplate x:Key="HorizontalListItemsPanel">
+ <ItemsStackPanel Orientation="Horizontal" />
+ </ItemsPanelTemplate>
<ItemsPanelTemplate x:Key="HorizontalGridItemsPanel">
<!-- Yes, this is counterintuitive. Orientation here means "direction we lay out the items until we hit the
</local:ItemContentControl>
</DataTemplate>
+ <DataTemplate x:Key="GroupHeaderTemplate">
+ <local:ItemContentControl
+ x:Name="ItemContentControl" DataContext="{Binding HeaderItemTemplateContext}"
+ FormsDataTemplate="{Binding FormsDataTemplate}" FormsDataContext="{Binding Item}"
+ FormsContainer="{Binding Container}">
+ </local:ItemContentControl>
+ </DataTemplate>
+
<DataTemplate x:Key="CarouselItemsViewDefaultTemplate">
<local:ItemContentControl
x:Name="ItemContentControl"
</Border>
</ControlTemplate>
- <ControlTemplate x:Key="FormsGridViewTemplate" TargetType="local:FormsGridView">
- <Border BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}">
- <Grid>
- <ContentControl x:Name="EmptyViewContentControl" Visibility="{TemplateBinding EmptyViewVisibility}"></ContentControl>
- <ScrollViewer x:Name="ScrollViewer"
- TabNavigation="{TemplateBinding TabNavigation}"
- HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}"
- HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
- IsHorizontalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsHorizontalScrollChainingEnabled}"
- VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}"
- VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"
- IsVerticalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsVerticalScrollChainingEnabled}"
- IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}"
- IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}"
- ZoomMode="{TemplateBinding ScrollViewer.ZoomMode}"
- IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}"
- BringIntoViewOnFocusChange="{TemplateBinding ScrollViewer.BringIntoViewOnFocusChange}"
- AutomationProperties.AccessibilityView="Raw">
- <ItemsPresenter Header="{TemplateBinding Header}"
- HeaderTemplate="{TemplateBinding HeaderTemplate}"
- HeaderTransitions="{TemplateBinding HeaderTransitions}"
- Footer="{TemplateBinding Footer}"
- FooterTemplate="{TemplateBinding FooterTemplate}"
- FooterTransitions="{TemplateBinding FooterTransitions}"
- Padding="{TemplateBinding Padding}" />
- </ScrollViewer>
- </Grid>
- </Border>
- </ControlTemplate>
+ <!-- We much rather just use a ControlTemplate for this the way we do with FormsListView, but unfortunately
+ 16299 (and presumably lower) can't find and set the control template. So we use the entire style instead. If we
+ get to a point where we don't have to support these earlier versions, we can replace this style with just the
+ template. (See also FormsGridView.cs) -->
+ <Style TargetType="local:FormsGridView">
+ <Setter Property="Padding" Value="0,0,0,10" />
+ <Setter Property="IsTabStop" Value="False" />
+ <Setter Property="TabNavigation" Value="Once" />
+ <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
+ <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
+ <Setter Property="ScrollViewer.HorizontalScrollMode" Value="Disabled" />
+ <Setter Property="ScrollViewer.IsHorizontalRailEnabled" Value="False" />
+ <Setter Property="ScrollViewer.VerticalScrollMode" Value="Enabled" />
+ <Setter Property="ScrollViewer.IsVerticalRailEnabled" Value="True" />
+ <Setter Property="ScrollViewer.ZoomMode" Value="Disabled" />
+ <Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="False" />
+ <Setter Property="ScrollViewer.BringIntoViewOnFocusChange" Value="True" />
+ <Setter Property="IsSwipeEnabled" Value="True" />
+ <Setter Property="UseSystemFocusVisuals" Value="True" />
+ <Setter Property="FocusVisualMargin" Value="-2" />
+ <Setter Property="ItemContainerTransitions">
+ <Setter.Value>
+ <TransitionCollection>
+ <AddDeleteThemeTransition />
+ <ContentThemeTransition />
+ <ReorderThemeTransition />
+ <EntranceThemeTransition IsStaggeringEnabled="False" />
+ </TransitionCollection>
+ </Setter.Value>
+ </Setter>
+ <Setter Property="ItemsPanel">
+ <Setter.Value>
+ <ItemsPanelTemplate>
+ <ItemsWrapGrid Orientation="Horizontal" />
+ </ItemsPanelTemplate>
+ </Setter.Value>
+ </Setter>
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="local:FormsGridView">
+ <Border BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}">
+ <Grid>
+ <ContentControl x:Name="EmptyViewContentControl" Visibility="{TemplateBinding EmptyViewVisibility}"></ContentControl>
+ <ScrollViewer x:Name="ScrollViewer"
+ TabNavigation="{TemplateBinding TabNavigation}"
+ HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}"
+ HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
+ IsHorizontalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsHorizontalScrollChainingEnabled}"
+ VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}"
+ VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"
+ IsVerticalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsVerticalScrollChainingEnabled}"
+ IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}"
+ IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}"
+ ZoomMode="{TemplateBinding ScrollViewer.ZoomMode}"
+ IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}"
+ BringIntoViewOnFocusChange="{TemplateBinding ScrollViewer.BringIntoViewOnFocusChange}"
+ AutomationProperties.AccessibilityView="Raw">
+ <ItemsPresenter Header="{TemplateBinding Header}"
+ HeaderTemplate="{TemplateBinding HeaderTemplate}"
+ HeaderTransitions="{TemplateBinding HeaderTransitions}"
+ Footer="{TemplateBinding Footer}"
+ FooterTemplate="{TemplateBinding FooterTemplate}"
+ FooterTransitions="{TemplateBinding FooterTransitions}"
+ Padding="{TemplateBinding Padding}" />
+ </ScrollViewer>
+ </Grid>
+ </Border>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
<Style x:Key="HorizontalCarouselListStyle" TargetType="local:FormsListView">
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Hidden" />
</Setter>
</Style>
+ <!-- Custom version of the style which removes the horizontal rule below the header -->
+ <Style TargetType="ListViewHeaderItem">
+ <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
+ <Setter Property="FontSize" Value="{ThemeResource ListViewHeaderItemThemeFontSize}" />
+ <Setter Property="Background" Value="{ThemeResource ListViewHeaderItemBackground}" />
+ <Setter Property="Margin" Value="0,0,0,4" />
+ <Setter Property="Padding" Value="12,8,12,0" />
+ <Setter Property="HorizontalContentAlignment" Value="Left" />
+ <Setter Property="VerticalContentAlignment" Value="Top" />
+ <Setter Property="MinHeight" Value="{ThemeResource ListViewHeaderItemMinHeight}" />
+ <Setter Property="UseSystemFocusVisuals" Value="True" />
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="ListViewHeaderItem">
+ <StackPanel Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
+ <ContentPresenter x:Name="ContentPresenter"
+ Margin="{TemplateBinding Padding}"
+ Content="{TemplateBinding Content}"
+ ContentTemplate="{TemplateBinding ContentTemplate}"
+ ContentTransitions="{TemplateBinding ContentTransitions}"
+ HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
+ VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />
+ </StackPanel>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <!-- Custom version of the style which removes the horizontal rule below the header -->
+ <Style TargetType="GridViewHeaderItem">
+ <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
+ <Setter Property="FontSize" Value="{ThemeResource GridViewHeaderItemThemeFontSize}" />
+ <Setter Property="Background" Value="{ThemeResource GridViewHeaderItemBackground}" />
+ <Setter Property="Margin" Value="0,0,0,4" />
+ <Setter Property="Padding" Value="12,8,12,0" />
+ <Setter Property="HorizontalContentAlignment" Value="Left" />
+ <Setter Property="VerticalContentAlignment" Value="Top" />
+ <Setter Property="MinHeight" Value="{ThemeResource GridViewHeaderItemMinHeight}" />
+ <Setter Property="UseSystemFocusVisuals" Value="True" />
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="GridViewHeaderItem">
+ <StackPanel Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
+ <ContentPresenter x:Name="ContentPresenter"
+ Margin="{TemplateBinding Padding}"
+ Content="{TemplateBinding Content}"
+ ContentTemplate="{TemplateBinding ContentTemplate}"
+ ContentTransitions="{TemplateBinding ContentTransitions}"
+ HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
+ VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />
+ </StackPanel>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
</ResourceDictionary>
using System.ComponentModel;
using Windows.UI.Xaml.Controls;
-using Xamarin.Forms.Platform.UAP;
+using UWPApp = Windows.UI.Xaml.Application;
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);
{
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)
{
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
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion>10.0.16299.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.16299.0</TargetPlatformMinVersion>
- <SkipMicrosoftUIXamlCheckTargetPlatformVersion>true</SkipMicrosoftUIXamlCheckTargetPlatformVersion>
+ <SkipMicrosoftUIXamlCheckTargetPlatformVersion>true</SkipMicrosoftUIXamlCheckTargetPlatformVersion>
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<Compile Include="CollectionView\ItemsViewRenderer.cs" />
<Compile Include="CollectionView\ItemTemplateContextList.cs" />
<Compile Include="CollectionView\ScrollHelpers.cs" />
+ <Compile Include="CollectionView\GroupedItemTemplateCollection.cs" />
+ <Compile Include="CollectionView\GroupFooterItemTemplateContext.cs" />
+ <Compile Include="CollectionView\GroupHeaderStyleSelector.cs" />
+ <Compile Include="CollectionView\GroupTemplateContext.cs" />
+ <Compile Include="CollectionView\GroupableItemsViewRenderer.cs" />
<Compile Include="CollectionView\SelectableItemsViewRenderer.cs" />
<Compile Include="CollectionView\StructuredItemsViewRenderer.cs" />
<Compile Include="ColorExtensions.cs" />
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
+ <Page Include="CollectionView\ItemsViewStyles.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
<Page Include="FormsCheckBoxStyle.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
- <Page Include="CollectionView\ItemsViewStyles.xaml">
- <SubType>Designer</SubType>
- <Generator>MSBuild:Compile</Generator>
- </Page>
<Page Include="MasterDetailControlStyle.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>