diff --git a/src/Controls/tests/TestCases.HostApp/CoreViews/CorePageView.cs b/src/Controls/tests/TestCases.HostApp/CoreViews/CorePageView.cs index 9f2fc6c54f1a..61d2bfa29c0c 100644 --- a/src/Controls/tests/TestCases.HostApp/CoreViews/CorePageView.cs +++ b/src/Controls/tests/TestCases.HostApp/CoreViews/CorePageView.cs @@ -77,6 +77,7 @@ public override string ToString() new GalleryPageFactory(() => new TimePickerCoreGalleryPage(), "Time Picker Gallery"), new GalleryPageFactory(() => new WebViewCoreGalleryPage(), "WebView Gallery"), new GalleryPageFactory(() => new SliderControlPage(), "Slider Feature Matrix"), + new GalleryPageFactory(() => new HeaderFooterMainPage(), "CollectionView Feature Matrix"), }; public CorePageView(Page rootPage) diff --git a/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewControlPage.xaml b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewControlPage.xaml new file mode 100644 index 000000000000..5c49a597e156 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewControlPage.xaml @@ -0,0 +1,28 @@ + + + + + + + + \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewControlPage.xaml.cs b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewControlPage.xaml.cs new file mode 100644 index 000000000000..27e08b4408c5 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewControlPage.xaml.cs @@ -0,0 +1,26 @@ +using System; +using Microsoft.Maui.Controls; +using System.Collections.ObjectModel; + +namespace Maui.Controls.Sample +{ + public partial class CollectionViewControlPage : ContentPage + { + private CollectionViewViewModel _viewModel; + + public CollectionViewControlPage() + { + InitializeComponent(); + _viewModel = new CollectionViewViewModel(); + _viewModel.ItemsSourceType = ItemsSourceType.ObservableCollection5T; + BindingContext = _viewModel; + } + + private async void NavigateToOptionsPage_Clicked(object sender, EventArgs e) + { + BindingContext = _viewModel = new CollectionViewViewModel(); + _viewModel.ItemsSourceType = ItemsSourceType.ObservableCollection5T; + await Navigation.PushAsync(new CollectionViewOptionsPage(_viewModel)); + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewOptionsPage.xaml b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewOptionsPage.xaml new file mode 100644 index 000000000000..7460999f5a1e --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewOptionsPage.xaml @@ -0,0 +1,275 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewOptionsPage.xaml.cs b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewOptionsPage.xaml.cs new file mode 100644 index 000000000000..ccf26c04cc54 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewOptionsPage.xaml.cs @@ -0,0 +1,278 @@ +using System; +using Microsoft.Maui.Controls; +using System.Collections.ObjectModel; +using Maui.Controls.Sample.CollectionViewGalleries; + +namespace Maui.Controls.Sample +{ + public partial class CollectionViewOptionsPage : ContentPage + { + private CollectionViewViewModel _viewModel; + + public CollectionViewOptionsPage(CollectionViewViewModel viewModel) + { + InitializeComponent(); + _viewModel = viewModel; + BindingContext = _viewModel; + } + + private void ApplyButton_Clicked(object sender, EventArgs e) + { + Navigation.PopAsync(); + } + + private void OnEmptyViewChanged(object sender, CheckedChangedEventArgs e) + { + if (EmptyViewNone.IsChecked) + { + _viewModel.EmptyView = null; + } + else if (EmptyViewString.IsChecked) + { + _viewModel.EmptyView = "No Items Available(String)"; + } + } + + private void OnHeaderChanged(object sender, CheckedChangedEventArgs e) + { + if (HeaderNone.IsChecked) + { + _viewModel.Header = null; + } + else if (HeaderString.IsChecked) + { + _viewModel.Header = "CollectionView Header(String)"; + } + else if (HeaderGrid.IsChecked) + { + Grid grid = new Grid + { + BackgroundColor = Colors.LightGray, + Padding = new Thickness(10) + }; + grid.Children.Add(new Label + { + Text = "CollectionView Header(Grid View)", + FontSize = 18, + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center, + TextColor = Colors.Blue, + AutomationId = "HeaderViewLabel" + }); + _viewModel.Header = grid; + } + } + + private void OnFooterChanged(object sender, CheckedChangedEventArgs e) + { + if (FooterNone.IsChecked) + { + _viewModel.Footer = null; + } + else if (FooterString.IsChecked) + { + _viewModel.Footer = "CollectionView Footer(String)"; + } + else if (FooterGrid.IsChecked) + { + Grid grid = new Grid + { + BackgroundColor = Colors.LightGray, + Padding = new Thickness(10) + }; + grid.Children.Add(new Label + { + Text = "CollectionView Footer(Grid View)", + FontSize = 18, + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center, + TextColor = Colors.Red, + AutomationId = "FooterViewLabel" + }); + _viewModel.Footer = grid; + } + } + + private void OnHeaderTemplateChanged(object sender, CheckedChangedEventArgs e) + { + if (HeaderTemplateNone.IsChecked) + { + _viewModel.HeaderTemplate = null; + } + else if (HeaderTemplateGrid.IsChecked) + { + _viewModel.HeaderTemplate = new DataTemplate(() => + { + Grid grid = new Grid + { + BackgroundColor = Colors.LightGray, + Padding = new Thickness(10) + }; + grid.Children.Add(new Label + { + Text = "Header Template(Grid View)", + FontSize = 18, + FontAttributes = FontAttributes.Bold, + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center, + TextColor = Colors.Blue, + AutomationId = "HeaderTemplateLabel" + }); + return grid; + }); + } + } + + private void OnFooterTemplateChanged(object sender, CheckedChangedEventArgs e) + { + if (FooterTemplateNone.IsChecked) + { + _viewModel.FooterTemplate = null; + } + else if (FooterTemplateGrid.IsChecked) + { + _viewModel.FooterTemplate = new DataTemplate(() => + { + Grid grid = new Grid + { + BackgroundColor = Colors.LightGray, + Padding = new Thickness(10) + }; + grid.Children.Add(new Label + { + Text = "Footer Template(Grid View)", + FontSize = 18, + FontAttributes = FontAttributes.Bold, + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center, + TextColor = Colors.Green, + AutomationId = "FooterTemplateLabel" + }); + return grid; + }); + } + } + + private void OnGroupHeaderTemplateChanged(object sender, CheckedChangedEventArgs e) + { + if (GroupHeaderTemplateNone.IsChecked) + { + _viewModel.GroupHeaderTemplate = null; + } + else if (GroupHeaderTemplateGrid.IsChecked) + { + _viewModel.GroupHeaderTemplate = new DataTemplate(() => + { + Grid grid = new Grid + { + BackgroundColor = Colors.LightGray, + Padding = new Thickness(10) + }; + grid.Children.Add(new Label + { + Text = "Group Header Template(Grid View)", + FontSize = 18, + FontAttributes = FontAttributes.Bold, + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center, + TextColor = Colors.Green, + AutomationId = "GroupHeaderTemplateLabel" + }); + return grid; + }); + } + } + private void OnGroupFooterTemplateChanged(object sender, CheckedChangedEventArgs e) + { + if (GroupFooterTemplateNone.IsChecked) + { + _viewModel.GroupFooterTemplate = null; + } + else if (GroupFooterTemplateGrid.IsChecked) + { + _viewModel.GroupFooterTemplate = new DataTemplate(() => + { + Grid grid = new Grid + { + BackgroundColor = Colors.LightGray, + Padding = new Thickness(10) + }; + grid.Children.Add(new Label + { + Text = "Group Footer Template(Grid View)", + FontSize = 18, + FontAttributes = FontAttributes.Bold, + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center, + TextColor = Colors.Red, + AutomationId = "GroupFooterTemplateLabel" + }); + return grid; + }); + } + } + private void OnIsGroupedChanged(object sender, CheckedChangedEventArgs e) + { + if (IsGroupedFalse.IsChecked) + { + _viewModel.IsGrouped = false; + } + else if (IsGroupedTrue.IsChecked) + { + _viewModel.IsGrouped = true; + } + } + + private void OnItemTemplateChanged(object sender, CheckedChangedEventArgs e) + { + if (ItemTemplateNone.IsChecked) + { + _viewModel.ItemTemplate = null; + } + else if (ItemTemplateBasic.IsChecked) + { + _viewModel.ItemTemplate = new DataTemplate(() => + { + var label = new Label(); + label.SetBinding(Label.TextProperty, new Binding("Caption")); + + return label; + }); + } + } + + private void OnItemsLayoutChanged(object sender, CheckedChangedEventArgs e) + { + if (ItemsLayoutVerticalList.IsChecked) + { + _viewModel.ItemsLayout = new LinearItemsLayout(ItemsLayoutOrientation.Vertical); + } + else if (ItemsLayoutHorizontalList.IsChecked) + { + _viewModel.ItemsLayout = new LinearItemsLayout(ItemsLayoutOrientation.Horizontal); + } + else if (ItemsLayoutVerticalGrid.IsChecked) + { + _viewModel.ItemsLayout = new GridItemsLayout(2, ItemsLayoutOrientation.Vertical); // 2 columns + } + else if (ItemsLayoutHorizontalGrid.IsChecked) + { + _viewModel.ItemsLayout = new GridItemsLayout(2, ItemsLayoutOrientation.Horizontal); // 2 rows + } + } + + private void OnItemsSourceChanged(object sender, CheckedChangedEventArgs e) + { + if (!(sender is RadioButton radioButton) || !e.Value) + return; + if (radioButton == ItemsSourceObservableCollection25) + _viewModel.ItemsSourceType = ItemsSourceType.ObservableCollection25T; + else if (radioButton == ItemsSourceObservableCollection5) + _viewModel.ItemsSourceType = ItemsSourceType.ObservableCollection5T; + else if (radioButton == ItemsSourceGroupedList) + _viewModel.ItemsSourceType = ItemsSourceType.GroupedListT; + else if (radioButton == ItemsSourceNone) + _viewModel.ItemsSourceType = ItemsSourceType.None; + } + } +} diff --git a/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewViewModel.cs b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewViewModel.cs new file mode 100644 index 000000000000..76d61f1ed6f3 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewViewModel.cs @@ -0,0 +1,293 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Linq; +using System.Runtime.CompilerServices; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Graphics; +using Maui.Controls.Sample.CollectionViewGalleries; + +namespace Maui.Controls.Sample +{ + public class Grouping : ObservableCollection + { + public TKey Key { get; } + + public Grouping(TKey key, IEnumerable items) : base(items) + { + Key = key; + } + } + + public enum ItemsSourceType + { + None, + ObservableCollection25T, + ObservableCollection5T, + GroupedListT, + EmptyGroupedListT, + EmptyObservableCollectionT + } + public class CollectionViewViewModel : INotifyPropertyChanged + { + private object _emptyView; + private object _header; + private object _footer; + private DataTemplate _emptyViewTemplate; + private DataTemplate _headerTemplate; + private DataTemplate _footerTemplate; + private DataTemplate _groupHeaderTemplate; + private DataTemplate _groupFooterTemplate; + private DataTemplate _itemTemplate; + private IItemsLayout _itemsLayout = new LinearItemsLayout(ItemsLayoutOrientation.Vertical); + private ItemsSourceType _itemsSourceType = ItemsSourceType.None; + private bool _isGrouped = false; + private ObservableCollection _observableCollection25; + private ObservableCollection _observableCollection5; + private ObservableCollection _emptyObservableCollection; + private List> _groupedList; + private List> _emptyGroupedList; + public event PropertyChangedEventHandler PropertyChanged; + + public CollectionViewViewModel() + { + LoadItems(); + ItemTemplate = new DataTemplate(() => + { + var stackLayout = new StackLayout + { + Padding = new Thickness(10), + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center + }; + + var label = new Label + { + VerticalOptions = LayoutOptions.Center, + HorizontalOptions = LayoutOptions.Center + }; + label.SetBinding(Label.TextProperty, "Caption"); + stackLayout.Children.Add(label); + return stackLayout; + }); + + GroupHeaderTemplate = new DataTemplate(() => + { + var stackLayout = new StackLayout + { + BackgroundColor = Colors.LightGray + }; + var label = new Label + { + FontAttributes = FontAttributes.Bold, + FontSize = 18 + }; + label.SetBinding(Label.TextProperty, "Key"); + stackLayout.Children.Add(label); + return stackLayout; + }); + } + + public object EmptyView + { + get => _emptyView; + set { _emptyView = value; OnPropertyChanged(); } + } + + public object Header + { + get => _header; + set { _header = value; OnPropertyChanged(); } + } + + public object Footer + { + get => _footer; + set { _footer = value; OnPropertyChanged(); } + } + + public DataTemplate EmptyViewTemplate + { + get => _emptyViewTemplate; + set { _emptyViewTemplate = value; OnPropertyChanged(); } + } + + public DataTemplate HeaderTemplate + { + get => _headerTemplate; + set { _headerTemplate = value; OnPropertyChanged(); } + } + + public DataTemplate FooterTemplate + { + get => _footerTemplate; + set { _footerTemplate = value; OnPropertyChanged(); } + } + + public DataTemplate GroupHeaderTemplate + { + get => _groupHeaderTemplate; + set { _groupHeaderTemplate = value; OnPropertyChanged(); } + } + + public DataTemplate GroupFooterTemplate + { + get => _groupFooterTemplate; + set { _groupFooterTemplate = value; OnPropertyChanged(); } + } + + public DataTemplate ItemTemplate + { + get => _itemTemplate; + set { _itemTemplate = value; OnPropertyChanged(); } + } + + public IItemsLayout ItemsLayout + { + get => _itemsLayout; + set + { + if (_itemsLayout != value) + { + _itemsLayout = value; + OnPropertyChanged(); + } + } + } + + public ItemsSourceType ItemsSourceType + { + get => _itemsSourceType; + set + { + if (_itemsSourceType != value) + { + _itemsSourceType = value; + OnPropertyChanged(); + OnPropertyChanged(nameof(ItemsSource)); + } + } + } + + public bool IsGrouped + { + get => _isGrouped; + set + { + if (_isGrouped != value) + { + _isGrouped = value; + OnPropertyChanged(); + } + } + } + + public object ItemsSource + { + get + { + return ItemsSourceType switch + { + ItemsSourceType.ObservableCollection25T => _observableCollection25, + ItemsSourceType.ObservableCollection5T => _observableCollection5, + ItemsSourceType.GroupedListT => _groupedList, + ItemsSourceType.EmptyGroupedListT => _emptyGroupedList, + ItemsSourceType.EmptyObservableCollectionT => _emptyObservableCollection, + ItemsSourceType.None => null, + _ => null + }; + } + } + + + private void LoadItems() + { + _observableCollection25 = new ObservableCollection(); + _observableCollection5 = new ObservableCollection(); + AddItems(_observableCollection5, 5, "Fruits"); + AddItems(_observableCollection25, 10, "Fruits"); + AddItems(_observableCollection25, 10, "Vegetables"); + + _emptyObservableCollection = new ObservableCollection(); + + _groupedList = new List> + { + new Grouping("Fruits", new List()), + new Grouping("Vegetables", new List()) + }; + + AddItems(_groupedList[0], 4, "Fruits"); + AddItems(_groupedList[1], 4, "Vegetables"); + + _emptyGroupedList = new List>(); + } + + + private void AddItems(IList list, int count, string category) + { + string[] fruits = + { + "Apple", "Banana", "Orange", "Grapes", "Mango", + "Pineapple", "Strawberry", "Blueberry", "Peach", "Cherry", + "Watermelon", "Papaya", "Kiwi", "Pear", "Plum", + "Avocado", "Fig", "Guava", "Lychee", "Pomegranate", + "Lime", "Lemon", "Coconut", "Apricot", "Blackberry" + }; + + string[] vegetables = + { + "Carrot", "Broccoli", "Spinach", "Potato", "Tomato", + "Cucumber", "Lettuce", "Onion", "Garlic", "Pepper", + "Zucchini", "Pumpkin", "Radish", "Beetroot", "Cabbage", + "Sweet Potato", "Turnip", "Cauliflower", "Celery", "Asparagus", + "Eggplant", "Chili", "Corn", "Peas", "Mushroom" + }; + + string[] items = category == "Fruits" ? fruits : vegetables; + + for (int n = 0; n < count; n++) + { + list.Add(new CollectionViewTestItem(items[n % items.Length], n)); // Pass the index + } + } + + protected void OnPropertyChanged([CallerMemberName] string propertyName = null) + { + if (propertyName == nameof(IsGrouped)) + { + OnPropertyChanged(nameof(ItemsSource)); + } + + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + public class CustomDataTemplateSelector : DataTemplateSelector + { + public DataTemplate Template1 { get; set; } + public DataTemplate Template2 { get; set; } + + protected override DataTemplate OnSelectTemplate(object item, BindableObject container) + { + if (item is CollectionViewTestItem testItem) + { + return testItem.Index % 2 == 0 ? Template1 : Template2; + } + + return Template1; + } + } + + public class CollectionViewTestItem + { + public string Caption { get; set; } + public int Index { get; set; } + + public CollectionViewTestItem(string caption, int index) + { + Caption = caption; + Index = index; + } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/HeaderFooterMainPage.xaml b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/HeaderFooterMainPage.xaml new file mode 100644 index 000000000000..c98e25007ce5 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/HeaderFooterMainPage.xaml @@ -0,0 +1,15 @@ + + + +