Xamarin.Forms Datos de CollectionView

CollectionView incluye las siguientes propiedades que definen los datos que se van a mostrar y su apariencia:

  • ItemsSource, de tipo IEnumerable, especifica la colección de elementos que se mostrarán en el área de sugerencias, y tiene un valor predeterminado de null.
  • ItemTemplate, de tipo DataTemplate, especifica la plantilla que se aplicará a cada elemento de la colección de elementos que se mostrará.

Todas estas propiedades están respaldadas por objetos BindableProperty, lo que significa que las propiedades pueden ser destinos de los enlaces de datos.

Nota:

CollectionView define una propiedad ItemsUpdatingScrollMode que representa el comportamiento de desplazamiento de CollectionView cuando se agregan nuevos elementos. Para obtener más información sobre esta propiedad, consulta Control de la posición de desplazamiento cuando se agregan nuevos elementos.

CollectionView admite la virtualización de datos incremental a medida que se desplaza el usuario. Para obtener más información, consulta Carga incremental de datos.

Rellenar una CollectionView con datos

CollectionView se rellena con datos estableciendo su ItemsSource propiedad en cualquier colección que implemente IEnumerable. De forma predeterminada, CollectionView muestra los elementos de una lista vertical.

Importante

Si es necesario que CollectionView se actualice a medida que se agregan, quitan o cambian elementos en la colección subyacente, la colección subyacente debe ser una IEnumerable colección que envíe notificaciones de cambio de propiedad, como ObservableCollection.

CollectionView se puede rellenar con datos mediante el enlace de datos para enlazar su propiedad ItemsSource a una colección IEnumerable. En XAML, esto se consigue mediante la extensión de marcado Binding.

<CollectionView ItemsSource="{Binding Monkeys}" />

El código de C# equivalente es el siguiente:

CollectionView collectionView = new CollectionView();
collectionView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys");

En este ejemplo, los ItemsSource datos de propiedad se enlazan a la Monkeys propiedad del modelo de vista conectado.

Nota:

Los enlaces compilados pueden habilitarse para mejorar el rendimiento del enlace de datos en aplicaciones de Xamarin.Forms. Para obtener más información, vea Enlaces compilados.

Para obtener información sobre cómo cambiar el diseño de CollectionView, vea Xamarin.Forms Diseño de CollectionView. Para obtener información sobre cómo definir la apariencia de cada elemento en CollectionView, consulta Definir la apariencia del elemento. Para obtener más información sobre el enlace de datos, consulte Enlace de datos de Xamarin.Forms.

Advertencia

CollectionView producirá una excepción si su ItemsSource se actualiza fuera del subproceso de la interfaz de usuario.

Definición de la apariencia de elementos

Se puede personalizar la apariencia de cada elemento de CollectionView mediante el establecimiento de la propiedad CollectionView.ItemTemplate en un 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>

El código de C# equivalente es el siguiente:

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;
});

Los elementos especificados en DataTemplate definen la apariencia de cada elemento de la lista. En este ejemplo, el diseño dentro del DataTemplate se administra mediante un objeto Grid. La Grid contiene un objeto Image y dos objetos Label, que se enlazan a las propiedades de la clase Monkey:

public class Monkey
{
    public string Name { get; set; }
    public string Location { get; set; }
    public string Details { get; set; }
    public string ImageUrl { get; set; }
}

Las capturas de pantalla siguientes muestran el resultado de crear plantillas para cada elemento de la lista:

Captura de pantalla de CollectionView donde se crea una plantilla para cada elemento, en iOS y Android

Para obtener más información sobre las plantillas de datos, consulte Plantillas de datos de Xamarin.Forms.

Elección de la apariencia del elemento en tiempo de ejecución

La apariencia de cada elemento de CollectionView se puede elegir a la hora de ejecutarlo, en función del valor del elemento, estableciendo la propiedad CollectionView.ItemTemplate en un objeto DataTemplateSelector:

<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>

El código de C# equivalente es el siguiente:

CollectionView collectionView = new CollectionView
{
    ItemTemplate = new MonkeyDataTemplateSelector { ... }
};
collectionView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys");

La propiedad ItemTemplate se establece en el objeto MonkeyDataTemplateSelector. En el ejemplo siguiente se muestra la clase MonkeyDataTemplateSelector:

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;
    }
}

La clase MonkeyDataTemplateSelector define propiedades DataTemplate AmericanMonkey y OtherMonkey que se establecen en diferentes plantillas de datos. La invalidación de OnSelectTemplate devuelve la AmericanMonkey plantilla, que muestra el nombre y la ubicación del mono en verde azulado, cuando el nombre del mono contiene "America". Cuando el nombre del mono no contiene "America", la invalidación de OnSelectTemplate devuelve la plantilla OtherMonkey, que muestra el nombre del mono y la ubicación en plata:

Captura de pantalla de la selección de plantilla de elemento en tiempo de ejecución de CollectionView, en iOS y Android

Para más información sobre los selectores de plantillas de datos, consulte Creación de una instancia de Xamarin.Forms DataTemplateSelector.

Importante

Cuando se usa CollectionView, nunca establezcas el elemento raíz de los objetos DataTemplate en un ViewCell. Esto provocará que se produzca una excepción, porque CollectionView no tiene ningún concepto de celdas.

Menús contextuales

CollectionView admite menús contextuales para elementos de datos a través de SwipeView, que revela el menú contextual con un gesto de deslizar el dedo. El SwipeView es un control de contenedor que se ajusta alrededor de un elemento de contenido y proporciona elementos de menú contextual para ese elemento de contenido. Por lo tanto, los menús contextuales se implementan para CollectionView mediante la creación de SwipeView que define el contenido que SwipeView encapsula y los elementos del menú contextual que se muestran mediante el gesto de deslizar el dedo. Esto se logra estableciendo SwipeView como la vista raíz en que DataTemplate define la apariencia de cada elemento de datos en 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>

El código de C# equivalente es el siguiente:

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;
});

En este ejemplo, el contenido SwipeView es un Grid que define la apariencia de cada elemento en CollectionView. Los elementos de deslizamiento se usan para realizar acciones en el contenido SwipeView y se muestran cuando el control se desliza desde el lado izquierdo:

Captura de pantalla de los elementos del menú contextual CollectionView, en iOS y Android

SwipeView admite cuatro direcciones de deslizamiento diferentes, con la dirección de deslizamiento definida por la colección direccional SwipeItems a la que se agregan los SwipeItems objetos. De forma predeterminada, se ejecuta un elemento de deslizar el dedo cuando el usuario pulsa. Además, una vez que se ha ejecutado un elemento de deslizar el dedo, los elementos de deslizar el dedo se ocultan y se vuelve a mostrar el SwipeView contenido. No obstante, ese comportamiento se puede modificar.

Para obtener más información sobre el control de SwipeView, consulte Xamarin.Forms SwipeView.

Deslizar para actualizar

CollectionView admite la funcionalidad de deslizar para actualizar en RefreshView, que permite actualizar los datos que se muestran al deslizar en la lista de elementos. El RefreshView es un control de contenedor que proporciona extracción para actualizar la funcionalidad a su elemento secundario, siempre que el elemento secundario admita contenido desplazable. Por lo tanto, la funcionalidad de deslizar para actualizar se implementa para CollectionView al establecerla como elemento secundario de RefreshView:

<RefreshView IsRefreshing="{Binding IsRefreshing}"
             Command="{Binding RefreshCommand}">
    <CollectionView ItemsSource="{Binding Animals}">
        ...
    </CollectionView>
</RefreshView>

El código de C# equivalente es el siguiente:

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;
// ...

Cuando el usuario inicia una actualización, se ejecuta el ICommand definido por la Command propiedad, que debe actualizar los elementos que se muestran. Se muestra una visualización de actualización mientras se produce la actualización, que consta de un círculo de progreso animado:

Captura de pantalla de deslizar hacia abajo para actualizar en CollectionView, en iOS y Android

El valor de la propiedad RefreshView.IsRefreshing indica el estado actual del RefreshView. Cuando el usuario desencadena una actualización, esta propiedad pasará automáticamente a true. Una vez completada la actualización, debe restablecer la propiedad a false.

Para obtener más información acerca de RefreshView, consulte Xamarin.FormsRefreshView.

Cargar datos de forma incremental

CollectionView admite la virtualización de datos incremental a medida que se desplaza el usuario. Esto permite escenarios como cargar de forma asincrónica una página de datos desde un servicio web, a medida que el usuario se desplaza. Además, el punto en el que se cargan más datos es configurable para que los usuarios no vean espacio en blanco o se detengan del desplazamiento.

CollectionView define las siguientes propiedades para controlar la carga incremental de datos:

  • RemainingItemsThreshold, de tipo int, el umbral de elementos que aún no están visibles en la lista en la que se desencadenará el RemainingItemsThresholdReached evento.
  • RemainingItemsThresholdReachedCommand, de tipo ICommand, que se ejecuta cuando se pulsa RemainingItemsThreshold.
  • RemainingItemsThresholdReachedCommandParameter, de tipo object, que es el parámetro que se pasa al objeto RemainingItemsThresholdReachedCommand.

CollectionView también define un evento RemainingItemsThresholdReached que se desencadena cuando CollectionView se desplaza lo suficientemente lejos como para que los elementos RemainingItemsThreshold no se muestren. Este evento se puede controlar para cargar más elementos. Además, cuando se desencadena el RemainingItemsThresholdReached evento, RemainingItemsThresholdReachedCommand se ejecuta, lo que permite la carga incremental de datos para que tenga lugar en un modelo de vista.

El valor predeterminado de la RemainingItemsThreshold propiedad es -1, lo que indica que el RemainingItemsThresholdReached evento nunca se desencadenará. Cuando el valor de la propiedad es 0, el RemainingItemsThresholdReached evento se desencadenará cuando se muestre el elemento final de ItemsSource. Para los valores mayores que 0, el RemainingItemsThresholdReached evento se desencadenará cuando ItemsSource contenga ese número de elementos a los que aún no se ha desplazado.

Nota:

CollectionView valida la propiedad RemainingItemsThreshold para que su valor sea siempre mayor o igual que -1.

En el siguiente ejemplo de XAML, se muestra una CollectionView que carga datos de forma incremental:

<CollectionView ItemsSource="{Binding Animals}"
                RemainingItemsThreshold="5"
                RemainingItemsThresholdReached="OnCollectionViewRemainingItemsThresholdReached">
    ...
</CollectionView>

El código de C# equivalente es el siguiente:

CollectionView collectionView = new CollectionView
{
    RemainingItemsThreshold = 5
};
collectionView.RemainingItemsThresholdReached += OnCollectionViewRemainingItemsThresholdReached;
collectionView.SetBinding(ItemsView.ItemsSourceProperty, "Animals");

En este ejemplo de código, el evento RemainingItemsThresholdReached se desencadena cuando todavía hay 5 elementos hasta los que no te has desplazado y, en respuesta, ejecuta el controlador de eventos OnCollectionViewRemainingItemsThresholdReached:

void OnCollectionViewRemainingItemsThresholdReached(object sender, EventArgs e)
{
    // Retrieve more data here and add it to the CollectionView's ItemsSource collection.
}

Nota:

Los datos también se pueden cargar incrementalmente enlazando la RemainingItemsThresholdReachedCommand a una ICommand implementación en el modelo de vista.