Populate a CollectionView with data
The .NET Multi-platform App UI (.NET MAUI) CollectionView includes the following properties that define the data to be displayed, and its appearance:
ItemsSource
, of typeIEnumerable
, specifies the collection of items to be displayed, and has a default value ofnull
.ItemTemplate
, of type DataTemplate, specifies the template to apply to each item in the collection of items to be displayed.
These properties are backed by BindableProperty objects, which means that the properties can be targets of data bindings.
CollectionView defines a ItemsUpdatingScrollMode
property that represents the scrolling behavior of the CollectionView when new items are added to it. For more information about this property, see Control scroll position when new items are added.
CollectionView supports incremental data virtualization as the user scrolls. For more information, see Load data incrementally.
Populate a CollectionView with data
A CollectionView is populated with data by setting its ItemsSource
property to any collection that implements IEnumerable
. By default, CollectionView displays items in a vertical list.
Important
If the CollectionView is required to refresh as items are added, removed, or changed in the underlying collection, the underlying collection should be an IEnumerable
collection that sends property change notifications, such as ObservableCollection
.
CollectionView can be populated with data by using data binding to bind its ItemsSource
property to an IEnumerable
collection. In XAML, this is achieved with the Binding
markup extension:
<CollectionView ItemsSource="{Binding Monkeys}" />
The equivalent C# code is:
CollectionView collectionView = new CollectionView();
collectionView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys");
In this example, the ItemsSource
property data binds to the Monkeys
property of the connected viewmodel.
Note
Compiled bindings can be enabled to improve data binding performance in .NET MAUI applications. For more information, see Compiled bindings.
For information on how to change the CollectionView layout, see Specify CollectionView layout. For information on how to define the appearance of each item in the CollectionView, see Define item appearance. For more information about data binding, see Data binding.
Warning
CollectionView will throw an exception if its ItemsSource
is updated off the UI thread.
Define item appearance
The appearance of each item in the CollectionView can be defined by setting the CollectionView.ItemTemplate
property to a DataTemplate:
<CollectionView ItemsSource="{Binding Monkeys}">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Image Grid.RowSpan="2"
Source="{Binding ImageUrl}"
Aspect="AspectFill"
HeightRequest="60"
WidthRequest="60" />
<Label Grid.Column="1"
Text="{Binding Name}"
FontAttributes="Bold" />
<Label Grid.Row="1"
Grid.Column="1"
Text="{Binding Location}"
FontAttributes="Italic"
VerticalOptions="End" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
...
</CollectionView>
The equivalent C# code is:
CollectionView collectionView = new CollectionView();
collectionView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys");
collectionView.ItemTemplate = new DataTemplate(() =>
{
Grid grid = new Grid { Padding = 10 };
grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
Image image = new Image { Aspect = Aspect.AspectFill, HeightRequest = 60, WidthRequest = 60 };
image.SetBinding(Image.SourceProperty, "ImageUrl");
Label nameLabel = new Label { FontAttributes = FontAttributes.Bold };
nameLabel.SetBinding(Label.TextProperty, "Name");
Label locationLabel = new Label { FontAttributes = FontAttributes.Italic, VerticalOptions = LayoutOptions.End };
locationLabel.SetBinding(Label.TextProperty, "Location");
Grid.SetRowSpan(image, 2);
grid.Add(image);
grid.Add(nameLabel, 1, 0);
grid.Add(locationLabel, 1, 1);
return grid;
});
The elements specified in the DataTemplate define the appearance of each item in the list. In the example, layout within the DataTemplate is managed by a Grid. The Grid contains an Image object, and two Label objects, that all bind to properties of the Monkey
class:
public class Monkey
{
public string Name { get; set; }
public string Location { get; set; }
public string Details { get; set; }
public string ImageUrl { get; set; }
}
The following screenshot shows the result of templating each item in the list:
Tip
Placing a CollectionView inside a VerticalStackLayout can stop the CollectionView scrolling, and can limit the number of items that are displayed. In this situation, replace the VerticalStackLayout with a Grid.
For more information about data templates, see Data templates.
Choose item appearance at runtime
The appearance of each item in the CollectionView can be chosen at runtime, based on the item value, by setting the CollectionView.ItemTemplate
property to a DataTemplateSelector object:
<ContentPage ...
xmlns:controls="clr-namespace:CollectionViewDemos.Controls">
<ContentPage.Resources>
<DataTemplate x:Key="AmericanMonkeyTemplate">
...
</DataTemplate>
<DataTemplate x:Key="OtherMonkeyTemplate">
...
</DataTemplate>
<controls:MonkeyDataTemplateSelector x:Key="MonkeySelector"
AmericanMonkey="{StaticResource AmericanMonkeyTemplate}"
OtherMonkey="{StaticResource OtherMonkeyTemplate}" />
</ContentPage.Resources>
<CollectionView ItemsSource="{Binding Monkeys}"
ItemTemplate="{StaticResource MonkeySelector}" />
</ContentPage>
The equivalent C# code is:
CollectionView collectionView = new CollectionView
{
ItemTemplate = new MonkeyDataTemplateSelector { ... }
};
collectionView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys");
The ItemTemplate
property is set to a MonkeyDataTemplateSelector
object. The following example shows the MonkeyDataTemplateSelector
class:
public class MonkeyDataTemplateSelector : DataTemplateSelector
{
public DataTemplate AmericanMonkey { get; set; }
public DataTemplate OtherMonkey { get; set; }
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
return ((Monkey)item).Location.Contains("America") ? AmericanMonkey : OtherMonkey;
}
}
The MonkeyDataTemplateSelector
class defines AmericanMonkey
and OtherMonkey
DataTemplate properties that are set to different data templates. The OnSelectTemplate
override returns the AmericanMonkey
template, which displays the monkey name and location in teal, when the monkey name contains "America". When the monkey name doesn't contain "America", the OnSelectTemplate
override returns the OtherMonkey
template, which displays the monkey name and location in silver:
For more information about data template selectors, see Create a DataTemplateSelector.
Important
When using CollectionView, never set the root element of your DataTemplate objects to a ViewCell. This will result in an exception being thrown because CollectionView has no concept of cells.
Context menus
CollectionView supports context menus for items of data through the SwipeView, which reveals the context menu with a swipe gesture. The SwipeView is a container control that wraps around an item of content, and provides context menu items for that item of content. Therefore, context menus are implemented for a CollectionView by creating a SwipeView that defines the content that the SwipeView wraps around, and the context menu items that are revealed by the swipe gesture. This is achieved by setting the SwipeView as the root view in the DataTemplate that defines the appearance of each item of data in the CollectionView:
<CollectionView x:Name="collectionView"
ItemsSource="{Binding Monkeys}">
<CollectionView.ItemTemplate>
<DataTemplate>
<SwipeView>
<SwipeView.LeftItems>
<SwipeItems>
<SwipeItem Text="Favorite"
IconImageSource="favorite.png"
BackgroundColor="LightGreen"
Command="{Binding Source={x:Reference collectionView}, Path=BindingContext.FavoriteCommand}"
CommandParameter="{Binding}" />
<SwipeItem Text="Delete"
IconImageSource="delete.png"
BackgroundColor="LightPink"
Command="{Binding Source={x:Reference collectionView}, Path=BindingContext.DeleteCommand}"
CommandParameter="{Binding}" />
</SwipeItems>
</SwipeView.LeftItems>
<Grid BackgroundColor="White"
Padding="10">
<!-- Define item appearance -->
</Grid>
</SwipeView>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
The equivalent C# code is:
CollectionView collectionView = new CollectionView();
collectionView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys");
collectionView.ItemTemplate = new DataTemplate(() =>
{
// Define item appearance
Grid grid = new Grid { Padding = 10, BackgroundColor = Colors.White };
// ...
SwipeView swipeView = new SwipeView();
SwipeItem favoriteSwipeItem = new SwipeItem
{
Text = "Favorite",
IconImageSource = "favorite.png",
BackgroundColor = Colors.LightGreen
};
favoriteSwipeItem.SetBinding(MenuItem.CommandProperty, new Binding("BindingContext.FavoriteCommand", source: collectionView));
favoriteSwipeItem.SetBinding(MenuItem.CommandParameterProperty, ".");
SwipeItem deleteSwipeItem = new SwipeItem
{
Text = "Delete",
IconImageSource = "delete.png",
BackgroundColor = Colors.LightPink
};
deleteSwipeItem.SetBinding(MenuItem.CommandProperty, new Binding("BindingContext.DeleteCommand", source: collectionView));
deleteSwipeItem.SetBinding(MenuItem.CommandParameterProperty, ".");
swipeView.LeftItems = new SwipeItems { favoriteSwipeItem, deleteSwipeItem };
swipeView.Content = grid;
return swipeView;
});
In this example, the SwipeView content is a Grid that defines the appearance of each item in the CollectionView. The swipe items are used to perform actions on the SwipeView content, and are revealed when the control is swiped from the left side:
SwipeView supports four different swipe directions, with the swipe direction being defined by the directional SwipeItems
collection the SwipeItems
objects are added to. By default, a swipe item is executed when it's tapped by the user. In addition, once a swipe item has been executed the swipe items are hidden and the SwipeView content is re-displayed. However, these behaviors can be changed.
For more information about the SwipeView control, see SwipeView.
Pull to refresh
CollectionView supports pull to refresh functionality through the RefreshView, which enables the data being displayed to be refreshed by pulling down on the list of items. The RefreshView is a container control that provides pull to refresh functionality to its child, provided that the child supports scrollable content. Therefore, pull to refresh is implemented for a CollectionView by setting it as the child of a RefreshView:
<RefreshView IsRefreshing="{Binding IsRefreshing}"
Command="{Binding RefreshCommand}">
<CollectionView ItemsSource="{Binding Animals}">
...
</CollectionView>
</RefreshView>
The equivalent C# code is:
RefreshView refreshView = new RefreshView();
ICommand refreshCommand = new Command(() =>
{
// IsRefreshing is true
// Refresh data here
refreshView.IsRefreshing = false;
});
refreshView.Command = refreshCommand;
CollectionView collectionView = new CollectionView();
collectionView.SetBinding(ItemsView.ItemsSourceProperty, "Animals");
refreshView.Content = collectionView;
// ...
When the user initiates a refresh, the ICommand defined by the Command
property is executed, which should refresh the items being displayed. A refresh visualization is shown while the refresh occurs, which consists of an animated progress circle:
The value of the RefreshView.IsRefreshing
property indicates the current state of the RefreshView. When a refresh is triggered by the user, this property will automatically transition to true
. Once the refresh completes, you should reset the property to false
.
For more information about RefreshView, see RefreshView.
Load data incrementally
CollectionView supports incremental data virtualization as the user scrolls. This enables scenarios such as asynchronously loading a page of data from a web service, as the user scrolls. In addition, the point at which more data is loaded is configurable so that users don't see blank space, or are stopped from scrolling.
Warning
Don't attempt to load data incrementally in a CollectionView that's in a StackLayout. This scenario will cause an infinite loop to occur where the CollectionView will keep expanding.
CollectionView defines the following properties to control incremental loading of data:
RemainingItemsThreshold
, of typeint
, the threshold of items not yet visible in the list at which theRemainingItemsThresholdReached
event will be fired.RemainingItemsThresholdReachedCommand
, of type ICommand, which is executed when theRemainingItemsThreshold
is reached.RemainingItemsThresholdReachedCommandParameter
, of typeobject
, which is the parameter that's passed to theRemainingItemsThresholdReachedCommand
.
CollectionView also defines a RemainingItemsThresholdReached
event that is fired when the CollectionView is scrolled far enough that RemainingItemsThreshold
items have not been displayed. This event can be handled to load more items. In addition, when the RemainingItemsThresholdReached
event is fired, the RemainingItemsThresholdReachedCommand
is executed, enabling incremental data loading to take place in a viewmodel.
The default value of the RemainingItemsThreshold
property is -1, which indicates that the RemainingItemsThresholdReached
event will never be fired. When the property value is 0, the RemainingItemsThresholdReached
event will be fired when the final item in the ItemsSource
is displayed. For values greater than 0, the RemainingItemsThresholdReached
event will be fired when the ItemsSource
contains that number of items not yet scrolled to.
Note
CollectionView validates the RemainingItemsThreshold
property so that its value is always greater than or equal to -1.
The following XAML example shows a CollectionView that loads data incrementally:
<CollectionView ItemsSource="{Binding Animals}"
RemainingItemsThreshold="5"
RemainingItemsThresholdReached="OnCollectionViewRemainingItemsThresholdReached">
...
</CollectionView>
The equivalent C# code is:
CollectionView collectionView = new CollectionView
{
RemainingItemsThreshold = 5
};
collectionView.RemainingItemsThresholdReached += OnCollectionViewRemainingItemsThresholdReached;
collectionView.SetBinding(ItemsView.ItemsSourceProperty, "Animals");
In this code example, the RemainingItemsThresholdReached
event fires when there are 5 items not yet scrolled to, and in response executes the OnCollectionViewRemainingItemsThresholdReached
event handler:
void OnCollectionViewRemainingItemsThresholdReached(object sender, EventArgs e)
{
// Retrieve more data here and add it to the CollectionView's ItemsSource collection.
}
Note
Data can also be loaded incrementally by binding the RemainingItemsThresholdReachedCommand
to an ICommand implementation in the viewmodel.