Поділитися через


Xamarin.Forms CollectionView Data

CollectionView includes the following properties that define the data to be displayed, and its appearance:

  • ItemsSource, of type IEnumerable, specifies the collection of items to be displayed, and has a default value of null.
  • 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.

Note

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 Xamarin.Forms applications. For more information, see Compiled Bindings.

For information on how to change the CollectionView layout, see Xamarin.Forms 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 Xamarin.Forms 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.Children.Add(image);
    grid.Children.Add(nameLabel, 1, 0);
    grid.Children.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 screenshots show the result of templating each item in the list:

Screenshot of CollectionView where each item is templated, on iOS and Android

For more information about data templates, see Xamarin.Forms 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:

Screenshot of CollectionView runtime item template selection, on iOS and Android

For more information about data template selectors, see Create a Xamarin.Forms 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 = Color.White };
    // ...

    SwipeView swipeView = new SwipeView();
    SwipeItem favoriteSwipeItem = new SwipeItem
    {
        Text = "Favorite",
        IconImageSource = "favorite.png",
        BackgroundColor = Color.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 = Color.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:

Screenshot of CollectionView context menu items, on iOS and Android

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 Xamarin.Forms 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:

Screenshot of CollectionView pull-to-refresh, on iOS and Android

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 Xamarin.Forms 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.

CollectionView defines the following properties to control incremental loading of data:

  • RemainingItemsThreshold, of type int, the threshold of items not yet visible in the list at which the RemainingItemsThresholdReached event will be fired.
  • RemainingItemsThresholdReachedCommand, of type ICommand, which is executed when the RemainingItemsThreshold is reached.
  • RemainingItemsThresholdReachedCommandParameter, of type object, which is the parameter that's passed to the RemainingItemsThresholdReachedCommand.

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.