Skip to content

Commit

Permalink
[UWP] Make EmptyView work in UWP CarouselView (xamarin#7724)
Browse files Browse the repository at this point in the history
* Make EmptyView work in UWP CarouselView

* Update Xamarin.Forms.Core/Items/CarouselView.cs

Co-Authored-By: Samantha Houts <samhouts@users.noreply.github.com>
  • Loading branch information
2 people authored and rmarinho committed Oct 1, 2019
1 parent dca82ed commit f524502
Show file tree
Hide file tree
Showing 9 changed files with 171 additions and 314 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ public CarouselItemsGallery()
ItemTemplate = itemTemplate,
ItemsSource = viewModel.Items,
IsScrollAnimated = true,
IsBounceEnabled = true
IsBounceEnabled = true,
EmptyView = "This is the empty view"
};

layout.Children.Add(carouselView, 0, 0);
Expand Down
7 changes: 6 additions & 1 deletion Xamarin.Forms.Core/Items/CarouselView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,11 @@ static object GetItemForPosition(CarouselView carouselView, int index)
if (!(carouselView?.ItemsSource is IList itemSource))
return null;

if (index < 0 || index >= itemSource.Count)
{
return null;
}

return itemSource[index];
}

Expand Down Expand Up @@ -255,4 +260,4 @@ public void SetIsDragging(bool value)
SetValue(IsDraggingPropertyKey, value);
}
}
}
}
108 changes: 65 additions & 43 deletions Xamarin.Forms.Platform.UAP/CollectionView/CarouselViewRenderer.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.ComponentModel;
using System;
using System.ComponentModel;
using System.Threading.Tasks;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
Expand All @@ -7,17 +8,12 @@
using WScrollBarVisibility = Windows.UI.Xaml.Controls.ScrollBarVisibility;
using WSnapPointsType = Windows.UI.Xaml.Controls.SnapPointsType;
using WSnapPointsAlignment = Windows.UI.Xaml.Controls.Primitives.SnapPointsAlignment;
using System;

namespace Xamarin.Forms.Platform.UWP
{
public class CarouselViewRenderer : ItemsViewRenderer
{
CollectionViewSource _collectionViewSource;
ScrollViewer _scrollViewer;
double _carouselHeight;
double _carouselWidth;

public CarouselViewRenderer()
{
CollectionView.VerifyCollectionViewFlagEnabled(nameof(CarouselView));
Expand All @@ -27,6 +23,9 @@ public CarouselViewRenderer()
protected override IItemsLayout Layout => CarouselView?.ItemsLayout;
UWPDataTemplate CarouselItemsViewTemplate => (UWPDataTemplate)UWPApp.Current.Resources["CarouselItemsViewDefaultTemplate"];

double _itemWidth;
double _itemHeight;

protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs changedProperty)
{
base.OnElementPropertyChanged(sender, changedProperty);
Expand All @@ -53,9 +52,9 @@ protected override void HandleLayoutPropertyChange(PropertyChangedEventArgs prop
UpdateSnapPointsAlignment();
}

protected override void SetUpNewElement(ItemsView newElement, bool setUpProperties)
protected override void SetUpNewElement(ItemsView newElement)
{
base.SetUpNewElement(newElement, false);
base.SetUpNewElement(newElement);

if (newElement != null)
{
Expand Down Expand Up @@ -94,24 +93,38 @@ protected override void UpdateItemsSource()
if (itemTemplate == null)
return;

_collectionViewSource = new CollectionViewSource
base.UpdateItemsSource();
}

protected override CollectionViewSource CreateCollectionViewSource()
{
return new CollectionViewSource
{
Source = TemplatedItemSourceFactory.Create(itemsSource, itemTemplate, Element, GetItemHeight(), GetItemWidth(), GetItemSpacing()),
Source = TemplatedItemSourceFactory.Create(Element.ItemsSource, Element.ItemTemplate, Element,
_itemHeight, _itemWidth, GetItemSpacing()),
IsSourceGrouped = false
};

ListViewBase.ItemsSource = _collectionViewSource.View;
}

protected override ListViewBase SelectListViewBase()
{
ListViewBase listView = null;

switch (Layout)
{
case LinearItemsLayout listItemsLayout:
return CreateCarouselListLayout(listItemsLayout.Orientation);
listView = CreateCarouselListLayout(listItemsLayout.Orientation);
break;
}

return new Windows.UI.Xaml.Controls.ListView();
if (listView == null)
{
listView = new FormsListView();
}

FindScrollViewer(listView);

return listView;
}

protected override void UpdateItemTemplate()
Expand All @@ -134,24 +147,9 @@ protected override Task ScrollTo(ScrollToRequestEventArgs args)

void OnListSizeChanged(object sender, Windows.UI.Xaml.SizeChangedEventArgs e)
{
var newSize = e.NewSize;

_carouselHeight = newSize.Height;
_carouselWidth = newSize.Width;

_scrollViewer = ListViewBase.GetFirstDescendant<ScrollViewer>();

if (_scrollViewer != null)
{
// TODO: jsuarezruiz This breaks the ScrollTo override. Review it.
_scrollViewer.ViewChanging += OnScrollViewChanging;
_scrollViewer.ViewChanged += OnScrollViewChanged;
}

_itemHeight = GetItemHeight();
_itemWidth = GetItemWidth();
UpdateItemsSource();
UpdateItemTemplate();
UpdateIsSwipeEnabled();
UpdateIsBounceEnabled();
}

void OnScrollViewChanging(object sender, ScrollViewerViewChangingEventArgs e)
Expand Down Expand Up @@ -246,15 +244,15 @@ ListViewBase CreateCarouselListLayout(ItemsLayoutOrientation layoutOrientation)

if (layoutOrientation == ItemsLayoutOrientation.Horizontal)
{
listView = new Windows.UI.Xaml.Controls.ListView()
listView = new FormsListView()
{
Style = (Windows.UI.Xaml.Style)UWPApp.Current.Resources["HorizontalCarouselListStyle"],
ItemsPanel = (ItemsPanelTemplate)UWPApp.Current.Resources["HorizontalListItemsPanel"]
};
}
else
{
listView = new Windows.UI.Xaml.Controls.ListView()
listView = new FormsListView()
{
Style = (Windows.UI.Xaml.Style)UWPApp.Current.Resources["VerticalCarouselListStyle"]
};
Expand All @@ -265,28 +263,28 @@ ListViewBase CreateCarouselListLayout(ItemsLayoutOrientation layoutOrientation)

double GetItemWidth()
{
var itemWidth = _carouselWidth;
var itemWidth = ActualWidth;

if (Layout is LinearItemsLayout listItemsLayout && listItemsLayout.Orientation == ItemsLayoutOrientation.Horizontal)
{
var numberOfVisibleItems = CarouselView.NumberOfSideItems * 2 + 1;
itemWidth = (_carouselWidth - CarouselView.PeekAreaInsets.Left - CarouselView.PeekAreaInsets.Right - listItemsLayout.ItemSpacing) / numberOfVisibleItems;
itemWidth = (ActualWidth - CarouselView.PeekAreaInsets.Left - CarouselView.PeekAreaInsets.Right - listItemsLayout.ItemSpacing) / numberOfVisibleItems;
}

return itemWidth;
return Math.Max(itemWidth, 0);
}

double GetItemHeight()
{
var itemHeight = _carouselHeight;
var itemHeight = ActualHeight;

if (Layout is LinearItemsLayout listItemsLayout && listItemsLayout.Orientation == ItemsLayoutOrientation.Vertical)
{
var numberOfVisibleItems = CarouselView.NumberOfSideItems * 2 + 1;
itemHeight = (_carouselHeight - CarouselView.PeekAreaInsets.Top - CarouselView.PeekAreaInsets.Bottom - listItemsLayout.ItemSpacing) / numberOfVisibleItems;
itemHeight = (ActualHeight - CarouselView.PeekAreaInsets.Top - CarouselView.PeekAreaInsets.Bottom - listItemsLayout.ItemSpacing) / numberOfVisibleItems;
}

return itemHeight;
return Math.Max(itemHeight, 0);
}

Thickness GetItemSpacing()
Expand All @@ -308,18 +306,18 @@ Thickness GetItemSpacing()
object FindCarouselItem(ScrollToRequestEventArgs args)
{
if (args.Mode == ScrollToMode.Position)
return _collectionViewSource.View[args.Index];
return CollectionViewSource.View[args.Index];

if (Element.ItemTemplate == null)
return args.Item;

for (int n = 0; n < _collectionViewSource?.View.Count; n++)
for (int n = 0; n < CollectionViewSource?.View.Count; n++)
{
if (_collectionViewSource.View[n] is ItemTemplateContext pair)
if (CollectionViewSource.View[n] is ItemTemplateContext pair)
{
if (pair.Item == args.Item)
{
return _collectionViewSource.View[n];
return CollectionViewSource.View[n];
}
}
}
Expand Down Expand Up @@ -356,5 +354,29 @@ WSnapPointsAlignment GetWindowsSnapPointsAlignment(SnapPointsAlignment snapPoint

return WSnapPointsAlignment.Center;
}

void FindScrollViewer(ListViewBase listView)
{
var scrollViewer = listView.GetFirstDescendant<ScrollViewer>();

if (scrollViewer != null)
{
_scrollViewer = scrollViewer;
// TODO: jsuarezruiz This breaks the ScrollTo override. Review it.
_scrollViewer.ViewChanging += OnScrollViewChanging;
_scrollViewer.ViewChanged += OnScrollViewChanged;

return;
}

void ListViewLoaded(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
var lv = (ListViewBase)sender;
lv.Loaded -= ListViewLoaded;
FindScrollViewer(listView);
}

listView.Loaded += ListViewLoaded;
}
}
}
13 changes: 7 additions & 6 deletions Xamarin.Forms.Platform.UAP/CollectionView/FormsGridView.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
using System;
using System.Globalization;
using Windows.UI.Xaml;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Xamarin.Forms.Platform.UWP;
using UWPApp = Windows.UI.Xaml.Application;
using UWPControlTemplate = Windows.UI.Xaml.Controls.ControlTemplate;

namespace Xamarin.Forms.Platform.UWP
{
Expand All @@ -15,6 +14,8 @@ internal class FormsGridView : GridView, IEmptyView

public FormsGridView()
{
Template = (UWPControlTemplate)UWPApp.Current.Resources["FormsListViewTemplate"];

// TODO hartez 2018/06/06 09:52:16 Do we need to clean this up? If so, where?
RegisterPropertyChangedCallback(ItemsPanelProperty, ItemsPanelChanged);
Loaded += OnLoaded;
Expand Down Expand Up @@ -47,13 +48,13 @@ public Visibility EmptyViewVisibility
public void UseHorizontalItemsPanel()
{
ItemsPanel =
(ItemsPanelTemplate)Windows.UI.Xaml.Application.Current.Resources["HorizontalGridItemsPanel"];
(ItemsPanelTemplate)UWPApp.Current.Resources["HorizontalGridItemsPanel"];
}

public void UseVerticalItemsPanel()
{
ItemsPanel =
(ItemsPanelTemplate)Windows.UI.Xaml.Application.Current.Resources["VerticalGridItemsPanel"];
(ItemsPanelTemplate)UWPApp.Current.Resources["VerticalGridItemsPanel"];
}

void FindItemsWrapGrid()
Expand Down
7 changes: 7 additions & 0 deletions Xamarin.Forms.Platform.UAP/CollectionView/FormsListView.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using UWPApp = Windows.UI.Xaml.Application;
using UWPControlTemplate = Windows.UI.Xaml.Controls.ControlTemplate;

namespace Xamarin.Forms.Platform.UWP
{
Expand All @@ -8,6 +10,11 @@ internal class FormsListView : Windows.UI.Xaml.Controls.ListView, IEmptyView
ContentControl _emptyViewContentControl;
FrameworkElement _emptyView;

public FormsListView()
{
Template = (UWPControlTemplate)UWPApp.Current.Resources["FormsListViewTemplate"];
}

public Visibility EmptyViewVisibility
{
get { return (Visibility)GetValue(EmptyViewVisibilityProperty); }
Expand Down
Loading

0 comments on commit f524502

Please sign in to comment.