Xamarin Forms - ListView e MVVM
 Neste artigo vamos usar o ListView e os conceitos do padrão MVVM para exibir dados e seleciona um item da lista.

Atualmente o componente CollectionView e uma opção mais otimizada que o ListView mas não é por isso que vamos deixar de usar o ListView.

Neste artigo temos uma exemplo básico de utilização do ListView para exibir uma lista de lanches permitindo a seleção de um lanche com exibição de detalhes.

Neste artigo vamos usar também o controle CircleImage para exibir imagens arredondadas

Recursos usados:

Criando o projeto no Visual Studio 2019 Community

Abra o VS 2019 Community e clique em Create a New Project;

A seguir selecione :

Selecione o template:  Mobile App (Xamarin.Forms) e clique em Next;

A seguir informe o local e o nome do projeto : XF_ListViewDetails

A seguir selecione o template Blank e as plataformas que deseja usar. Eu vou usar somente o Android:

Clique no botão OK.

Pronto, nosso projeto já esta criado.

Inclua uma referência ao componente: Xam.Plugins.Forms.ImageCircle nos projetos da solução.

A seguir no projeto Android inclua a linha de código em azul referente ao componente acima no método OnCreate do arquivo MainActivity:

       protected override void OnCreate(Bundle savedInstanceState)
        {
            TabLayoutResource = Resource.Layout.Tabbar;
            ToolbarResource = Resource.Layout.Toolbar;
            base.OnCreate(savedInstanceState);
            Xamarin.Essentials.Platform.Init(this, savedInstanceState);
            global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
            ImageCircleRenderer.Init();
            LoadApplication(new App());
        }

A seguir vamos criar as pastas : Models , Views e a pasta ViewModels no projeto e remover o arquivo MainPage.xaml e MainPage.xaml.cs do projeto.

Definindo o modelo de domínio

Na pasta Models vamos criar a classse ListModel que presenta o nosso modelo de domínio que é um lanche:

    public class ListModel
    {
        public string Nome { get; set; }
        public string Detalhe { get; set; }
        public string Imagem { get; set; }
        public string Ingredientes { get; set; }
    }

Implementando a ViewModel

Na pasta ViewModels vamos criar a classe ListPageViewModel

using System.Collections.ObjectModel;
using XF_ListViewDetails_MVVM.Models;

namespace XF_ListViewDetails_MVVM.ViewModels
{
    public class ListPageViewModel
    {
        public ObservableCollection<ListModel> Lanches { get; set; }

        public ListPageViewModel()
        {
            Lanches = new ObservableCollection<ListModel>();

            Lanches.Add(new ListModel
            {
                Nome = "Cheese Burger Completo",
                Imagem = "https://image.shutterstock.com/image-photo/fresh-tasty-burger-isolated-on-260nw-705104968.jpg",
                Detalhe = "Chesse Burger irresistível",
                Ingredientes = "Carne de primeira, tomate, queijo, bacon, picles"
            });

            Lanches.Add(new ListModel
            {
                Nome = "Cheese Salada Completo",
                Imagem = "https://thumbs.dreamstime.com/z/bacon-cheese-burger-22349336.jpg",
                Detalhe = "Chesse Salada delicioso ",
                Ingredientes = "Carne de primeira, tomate, salada, queijo, maionese, cebola, picles"
            });
            Lanches.Add(new ListModel
            {
                Nome = "Cheese Burger com Ovo ",
                Imagem = "https://thumbs.dreamstime.com/z/burger-3823314.jpg",
                Detalhe = "Chesse Burger com tempero especial ",
                Ingredientes = "Carne de primeira, tomate, salada, queijo, cebola, ovo, picles"
            });
        }
    }
}

Neste código definimos a propriedade Lanches que é do tipo ObservableCollection e assim qualquer alteração na coleção será notificada à interface ou seja ao ListView.

No construtor da classe atribuimos os dados que iremos usar à coleção Lanches. Estamos utilizando imagens de lanches obtidas da internet.

Aqui não implementamos nenhum comando usando a interface ICommand.

Implementando um layout básico com ListView

Vamos incluir na pasta Views criada no projeto, via opção Add New Item, um novo Content Page com o nome de ListPage que usaremos para exibir uma lista de lanches.

A seguir vamos definir um layout básico usando o ListView e o Grid:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:controls="clr-namespace:ImageCircle.Forms.Plugin.Abstractions;assembly=ImageCircle.Forms.Plugin"
             mc:Ignorable="d"
             x:Class="XF_ListViewDetails_MVVM.Views.ListPage"
             Title="MacLanches"
             BackgroundColor="Maroon">

    <ContentPage.Content>
        <ListView ItemsSource="{Binding Lanches}"
                  HasUnevenRows="True"
                  SeparatorVisibility="None"
                  ItemTapped="OnItemSelected">

            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <Grid Padding="10" RowSpacing="10" ColumnSpacing="10">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto"/>
                                <RowDefinition Height="*"/>
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="*"/>
                            </Grid.ColumnDefinitions>
                            <controls:CircleImage
                                HeightRequest="75"
                                WidthRequest="75"
                                HorizontalOptions="CenterAndExpand"
                                VerticalOptions="CenterAndExpand"
                                Aspect="AspectFill"
                                Grid.RowSpan="2"

                                Source="{Binding Imagem}"/>
                            <Label Grid.Column="1"
                                   Text="{Binding Nome}"
                                   FontSize="Medium"
                                   TextColor="White"
                                   VerticalOptions="End"/>
                            <Label Grid.Column="1"
                                   Grid.Row="1"
                                   TextColor="White"
                                   Text="{Binding Detalhe}"
                                   VerticalOptions="Start"/>
                        </Grid>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </ContentPage.Content>
</ContentPa

Neste código estamos definindo o data binding do ListView com a nossa coleção Lanches que é do tipo ListModel.

Definimos também o evento ItemTapped para tratar a seleção do usuário a um item da lista.

Agora no arquivo ListPage.xaml.cs vamos definir o código a seguir:

using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using XF_ListViewDetails_MVVM.Models;
using XF_ListViewDetails_MVVM.ViewModels;

namespace XF_ListViewDetails_MVVM.Views
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class ListPage : ContentPage
    {
        public ListPage()
        {
            InitializeComponent();
            BindingContext = new ListPageViewModel();
        }

        private async void OnItemSelected(object sender, ItemTappedEventArgs e)
        {
            var detalhes = e.Item as ListModel;
            await Navigation.PushAsync(new ListDetailPage(detalhes.Nome, detalhes.Ingredientes, detalhes.Imagem));
        }
    }
}

Neste código fazemos a vinculação via BindingContext com a nossa viewmodel e no evento OnItemSelected navegamos para a página ListDetailPage passando os dados do lanche.

Agora só falta criar a view ListDetailPage na pasta Views com o código abaixo:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:controls="clr-namespace:ImageCircle.Forms.Plugin.Abstractions;assembly=ImageCircle.Forms.Plugin"
             mc:Ignorable="d"

             x:Class="XF_ListViewDetails_MVVM.Views.ListDetailPage"
             Title="Lanches"
             BackgroundColor="Maroon">

    <ContentPage.Content>

        <StackLayout HorizontalOptions="Center">
            <controls:CircleImage x:Name="LancheImagem" HeightRequest="225" WidthRequest="225"/>
            <Label x:Name="LancheNome" HorizontalTextAlignment="Center" FontSize="Large" TextColor="White"/>
            <Label x:Name="LancheIngredientes" Margin="20,20" FontSize="Medium" Text="Lanches" TextColor="White"/>
        </StackLayout>
    </ContentPage.Content>

</ContentPage>

Neste código usamos o controle CircleImage para exibir a imagem do lanche e duas Labels para exibir o nome e os ingredientes.

Agora é só alegria...

Executando o projeto iremos obter o seguinte resultado:

Pegue o código do projeto compartilhado aqui : XF_ListViewDetails_MVVM.zip  (sem as referências)

"Portanto, agora nenhuma condenação há para os que estão em Cristo Jesus, que não andam segundo a carne, mas segundo o Espírito."
Romanos 8:1

Referências:


José Carlos Macoratti