.Net Maui Grouping Filtering Sorting Items Complete Guide
Understanding the Core Concepts of .NET MAUI Grouping, Filtering, Sorting Items
.NET MAUI Grouping, Filtering, Sorting Items: Detailed Explanation and Important Info
1. Grouping Items
Grouping is essential for organizing data in a structured format, which can be particularly useful in scenarios where categories or subcategories are involved. In .NET MAUI, grouping can be achieved using ObservableGroupedCollection
or by implementing custom logic.
Key Points:
- ObservableGroupedCollection<TItem, TGroupKey>: This collection type automatically groups items based on a specified key.
- Group Descriptor: Helps define the criteria for grouping data.
Example:
public class Product
{
public string Category { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
// View Model
public class MainViewModel : INotifyPropertyChanged
{
public ObservableGroupedCollection<string, Product> Products { get; private set; }
public MainViewModel()
{
var products = new List<Product>
{
new Product { Name = "Laptop", Category = "Electronics", Price = 999.99m },
new Product { Name = "Coffee Maker", Category = "Kitchen", Price = 99.99m },
new Product { Name = "Smartphone", Category = "Electronics", Price = 499.99m }
};
Products = new ObservableGroupedCollection<string, Product>(
products,
p => p.Category,
(key, items) => new Group<string, Product>(key, items)
);
}
}
XAML:
<CollectionView ItemsSource="{Binding Products}">
<CollectionView.GroupHeaderTemplate>
<DataTemplate>
<Label Text="{Binding Key}" FontSize="Title" FontAttributes="Bold" BackgroundColor="LightGray" Padding="10"/>
</DataTemplate>
</CollectionView.GroupHeaderTemplate>
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="10">
<Label Text="{Binding Name}" FontSize="Medium"/>
<Label Text="{Binding Price, StringFormat='{0:C}'}" FontSize="Medium" TextColor="Gray"/>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
2. Filtering Items
Filtering allows users to view only the data that meets specific criteria, making the application more responsive and user-friendly. In .NET MAUI, filtering can be achieved using CollectionView
's built-in features or by manually filtering the data source.
Key Points:
- SearchBar: Often used in conjunction with
CollectionView
to allow user-driven filtering. - Manual Filtering: Direct manipulation of the data source based on user input.
Example:
public class MainViewModel : INotifyPropertyChanged
{
private List<Product> _allProducts;
private List<Product> _filteredProducts;
public List<Product> FilteredProducts
{
get => _filteredProducts;
set
{
_filteredProducts = value;
OnPropertyChanged(nameof(FilteredProducts));
}
}
public MainViewModel()
{
_allProducts = new List<Product>
{
new Product { Name = "Laptop", Category = "Electronics", Price = 999.99m },
new Product { Name = "Coffee Maker", Category = "Kitchen", Price = 99.99m },
new Product { Name = "Smartphone", Category = "Electronics", Price = 499.99m }
};
FilteredProducts = new List<Product>(_allProducts);
}
public void ApplyFilter(string filterText)
{
FilteredProducts = _allProducts.Where(p => p.Name.Contains(filterText, StringComparison.OrdinalIgnoreCase)).ToList();
}
}
XAML:
<SearchBar TextChanged="SearchBar_TextChanged"/>
<CollectionView ItemsSource="{Binding FilteredProducts}">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="10">
<Label Text="{Binding Name}" FontSize="Medium"/>
<Label Text="{Binding Price, StringFormat='{0:C}'}" FontSize="Medium" TextColor="Gray"/>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Code-Behind:
private void SearchBar_TextChanged(object sender, TextChangedEventArgs e)
{
var viewModel = BindingContext as MainViewModel;
viewModel?.ApplyFilter(e.NewTextValue);
}
3. Sorting Items
Sorting is another critical feature that improves data organization by arranging items based on one or more criteria. In .NET MAUI, sorting can be implemented using various approaches, including LINQ and ICollectionView
.
Key Points:
- LINQ: Enables declarative querying of collections, facilitating easy sorting.
- ICollectionView: Provides a more flexible approach, allowing dynamic sorting without changing the underlying data source.
Example:
public class MainViewModel : INotifyPropertyChanged
{
public List<Product> Products { get; private set; }
public ListSortDirection SortDirection { get; set; } = ListSortDirection.Ascending;
public MainViewModel()
{
Products = new List<Product>
{
new Product { Name = "Laptop", Category = "Electronics", Price = 999.99m },
new Product { Name = "Coffee Maker", Category = "Kitchen", Price = 99.99m },
new Product { Name = "Smartphone", Category = "Electronics", Price = 499.99m }
};
SortProducts();
}
public void SortProducts(string propertyName)
{
SortDirection = SortDirection == ListSortDirection.Ascending ? ListSortDirection.Descending : ListSortDirection.Ascending;
Products = Products.OrderByProperty(propertyName, SortDirection).ToList();
OnPropertyChanged(nameof(Products));
}
}
XAML:
<Button Text="Sort by Name" Clicked="SortByName_Clicked" Margin="10"/>
<Button Text="Sort by Price" Clicked="SortByPrice_Clicked" Margin="10"/>
<CollectionView ItemsSource="{Binding Products}">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="10">
<Label Text="{Binding Name}" FontSize="Medium"/>
<Label Text="{Binding Price, StringFormat='{0:C}'}" FontSize="Medium" TextColor="Gray"/>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Code-Behind:
Online Code run
Step-by-Step Guide: How to Implement .NET MAUI Grouping, Filtering, Sorting Items
Step 1: Create a New .NET MAUI Project
- Open Visual Studio 2022 (ensure you have the .NET MAUI workload installed).
- Create a new project and select "MAUI App (.NET 7)".
- Name your project (e.g., "MauiListGroupFilterSort") and click "Create".
- Wait for the project to be created.
Step 2: Define Data Models
Create data models for Product
and ProductCategory
.
// ProductCategory.cs
public class ProductCategory
{
public string CategoryName { get; set; }
public List<Product> Products { get; set; }
}
// Product.cs
public class Product
{
public string ProductName { get; set; }
public decimal Price { get; set; }
public string Category { get; set; }
}
Step 3: Create a ViewModel
Create a ViewModel to handle data operations and bindings.
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
public class MainViewModel : INotifyPropertyChanged
{
private string filterText = string.Empty;
private bool sortByName = true;
public ObservableCollection<ProductCategory> GroupedProducts { get; set; }
public ObservableCollection<Product> AllProducts { get; set; }
public string FilterText
{
get => filterText;
set
{
filterText = value;
ApplyFilter();
OnPropertyChanged();
}
}
public bool SortByName
{
get => sortByName;
set
{
sortByName = value;
SortProducts();
OnPropertyChanged();
}
}
public MainViewModel()
{
AllProducts = new ObservableCollection<Product>
{
new Product { ProductName = "Apple", Price = 1.2m, Category = "Fruit" },
new Product { ProductName = "Banana", Price = 0.8m, Category = "Fruit" },
new Product { ProductName = "Carrot", Price = 0.5m, Category = "Vegetable" },
new Product { ProductName = "Potato", Price = 0.3m, Category = "Vegetable" },
new Product { ProductName = "Chicken", Price = 5.6m, Category = "Meat" },
new Product { ProductName = "Beef", Price = 8.9m, Category = "Meat" },
};
GroupedProducts = new ObservableCollection<ProductCategory>();
LoadData();
}
private void LoadData()
{
var groupedQuery = from Product product in AllProducts
orderby product.Category, product.ProductName
group product by product.Category into productGroup
select new ProductCategory
{
CategoryName = productGroup.Key,
Products = productGroup.ToList(),
};
GroupedProducts.AddRange(groupedQuery);
}
private void ApplyFilter()
{
var filteredProducts = AllProducts.Where(p => p.ProductName.Contains(FilterText, StringComparison.OrdinalIgnoreCase))
.ToList();
var groupedQuery = from Product product in filteredProducts
orderby product.Category, product.ProductName
group product by product.Category into productGroup
select new ProductCategory
{
CategoryName = productGroup.Key,
Products = productGroup.ToList(),
};
GroupedProducts.Clear();
GroupedProducts.AddRange(groupedQuery);
}
private void SortProducts()
{
var sortedQuery = from Product product in AllProducts
orderby SortByName ? product.ProductName : product.Price ascending, product.Category
group product by product.Category into productGroup
select new ProductCategory
{
CategoryName = productGroup.Key,
Products = productGroup.ToList(),
};
GroupedProducts.Clear();
GroupedProducts.AddRange(sortedQuery);
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Step 4: Set Up the MainPage
Edit MainPage.xaml
to use a CollectionView
for displaying, filtering, sorting, and grouping the products.
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:viewModels="clr-namespace:MauiListGroupFilterSort"
x:Class="MauiListGroupFilterSort.MainPage"
Title="Products">
<ContentPage.BindingContext>
<viewModels:MainViewModel />
</ContentPage.BindingContext>
<StackLayout Padding="10">
<StackLayout Margin="0,0,0,10">
<Entry Placeholder="Filter by name" Text="{Binding FilterText, Mode=TwoWay}" />
<Switch IsToggled="{Binding SortByName, Mode=TwoWay}" />
<Label Text="Sort by Name" IsVisible="{Binding SortByName, Converter={StaticResource BooleanToVisibilityConverter}}" />
<Label Text="Sort by Price" IsVisible="{Binding SortByName, Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter=False}" />
</StackLayout>
<CollectionView ItemsSource="{Binding GroupedProducts}" IsGrouped="True">
<CollectionView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell>
<Label Text="{Binding CategoryName}" FontAttributes="Bold" BackgroundColor="LightGray" />
</ViewCell>
</DataTemplate>
</CollectionView.GroupHeaderTemplate>
<CollectionView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="10">
<Label Text="{Binding ProductName}" FontSize="Medium" />
<Label Text="{Binding Price, StringFormat='${0:N2}'}" FontSize="Small" TextColor="Gray" />
</StackLayout>
</ViewCell>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</ContentPage>
Step 5: Add BooleanToVisibilityConverter (Optional)
To toggle visibility based on a boolean value (in this case, switching labels based on SortByName
), add a converter.
using Microsoft.Maui.Controls;
public class BooleanToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
return false;
bool boolValue = (bool)value;
if (parameter != null)
boolValue = !boolValue;
return boolValue ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Register the converter in App.xaml
:
<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MauiListGroupFilterSort"
x:Class="MauiListGroupFilterSort.App">
<Application.Resources>
<ResourceDictionary>
<local:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</ResourceDictionary>
</Application.Resources>
</Application>
Step 6: Run the Application
- Build and run the application.
- You should see a list of products grouped by categories.
- Enter text in the search box to filter the products.
- Toggle the switch to sort the list by name or price.
Login to post a comment.