Xamarin Forms - DataBinding com ListView e MVVM


 Neste artigo vamos recordar os conceitos do DataBinding usando ListView com MVVM em aplicações Xamarin Forms usando o Visual Studio com Xamarin e a linguagem C#.

Este artigo revê conceitos importantes que eu já publiquei no site por isso vou deixar os links sobre os assuntos relacionados com ListView, DataBinding e MVVM que eu já publiquei. Assim se você esta chegando agora e não conheçe o que é o DataBinding, ou, como funciona o ListView, ou, o que é o MVVM; leia os artigos abaixo antes de prosseguir:

Acessando os links acima você terá outros links que completam toda a informação necessária para acompanhar o assunto deste artigo, que na verdade é uma revisão de conceitos.

O que vamos criar neste artigo é apenas uma aplicação de uma única página contendo um ListView onde vamos realizar o databinding usando MVVM.

Então vamos começar...

Recursos usados:

Criando o projeto no Visual Studio 2017 Community

Abra o Visual Studio Community 2017 e clique em New Project;

Selecione Visual C# -> Cross-Platform e o template Cross Plataform App (Xamarin);

Informe o nome XF_ListViewMVVM e clique no botão OK;

A seguir marque o template Blank App e as opções Xamarin.Forms e Portable Class Library(PCL) e clique em OK;

Pronto. O projeto esta criado.

Vamos criar 4 pastas no projeto PCL. As pastas Views, Models, ViewModels e Services. Selecione o projeto e no menu Project clique em New Folder e informe o nome da pasta.

Abaixo vemos como deve ficar a estrutura do projeto:

Definindo o Model - Carro

Para representar um carro vamos criar o nosso modelo de domínio usando uma classe C#.

Vamos criar a classe Carro na pasta Models com o seguinte código:

    public class Carro
    {
        public int CarroId { get; set; }
        public string Modelo { get; set; }
        public int Ano { get; set; }
        public string Foto { get; set; }
    }

Temos a classe POCO Carro onde vamos gerenciar informações representadas pelas propriedades: Modelo, Ano e Foto.

Definindo a ViewModel - CarrosViewModel

Agora vamos definir o nosso ViewModel que será o que vamos exibir no ListView. Vamos exibir uma lista de objetos do tipo Carro, ou seja, uma lista de itens, e não um Carro.

Portanto vamos criar a classe CarrosViewModel na pasta ViewModels com o código abaixo:

using System.Collections.ObjectModel;
using XF_ListViewMVVM.Models;
using XF_ListViewMVVM.Services;
namespace XF_ListViewMVVM.ViewModels
{
    public class CarrosViewModel
    {
        // Estou usando um ObservableCollection porque quando 
        // um objeto é adicoinado ou removido de um uma coleção observável
        // a interface do usuário é atualizada automaticamente
        private ObservableCollection<Carro> items;
        public ObservableCollection<Carro> Items
        {
            get { return items; }
            set
            {
                items = value;
            }
        }
        public CarrosViewModel()
        {
            // Aqui vou vou definir dois objetos do tipo Carro para 
            // ter algum dados para exibir na lista
            Items = new ObservableCollection<Carro>() {
                new Carro()
                {
                    CarroId = 1,
                    Modelo = "Tesla Model S",
                    Ano = 2015,
                    Foto = "http://www.macoratti.net/imagens/carros/tesla1.jpg"
                },
                  new Carro()
                {
                    CarroId = 2,
                    Modelo = "Audi R8",
                    Ano = 2016,
                    Foto = "http://www.macoratti.net/imagens/carros/audir81.jpg"
                },
            };
          // aqui vou incluir a chamada a um serviço que irei criar
          // para obter mais carros para exibir na lista 
        }
    }
}

Ao definir a ViewModel estou usando um ObservableCollection. Sabe Por quê ?

Porque uma ObservableCollection representa uma coleção de dados dinâmicos que fornece notificações quando os itens são adicionados, removidos, ou quando toda a coleção é atualizada. Essa coleção esta disponível no namespace System.Collection.ObjectModel.

Assim, uma ObservableCollection trabalha essencialmente como uma coleção regular, exceto por dois pontos importantes: ela implementa as interfaces :

E isso é que a torna especial, pois além de ser uma coleção dinâmica de objetos de um dado tipo, onde os objetos podem ser adicionados, removidos ou atualizados, ela apresenta o recurso de notificar automaticamente os seus observadores quando um novo objeto foi adicionado, removido ou atualizado.

Dessa forma ao usar uma ObservableCollection você pode receber notificações das atualizações feitas na coleção de forma automática através de um evento e assim tratar a respectiva ação.

No construtor da ViewModel estou definindo dois objetos do tipo Carro para poder exibir alguma informação no ListView. Mais adiante irei incluir uma chamada a um web service para obter mais dados.

Definindo a página CarrosPage

A página que irá exibir as informações dos carros vai usar um ListView. Vamos criar a página CarrosPage.xaml na pasta Views usando a opção Content Page do menu Project-> Add New Item;

A seguir inclua o código XAML abaixo n oarquivo CarrosPage.xaml:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XF_ListViewMVVM.Views.CarrosPage"
             Title="Relação de Carros">
    <ContentPage.Content>

        <ListView ItemsSource="{Binding Items}"
              CachingStrategy="RecycleElement"
              RowHeight="60">

            <ListView.ItemTemplate>
               <DataTemplate>
                <ViewCell>
                  <Grid Padding="5">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="25"></RowDefinition>
                                <RowDefinition Height="25"></RowDefinition>
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="*"></ColumnDefinition>
                                <ColumnDefinition Width="150"></ColumnDefinition>
                            </Grid.ColumnDefinitions>

                   <Label Grid.Row="0" Grid.Column="0" Text="{Binding Modelo}" Style="{StaticResource labelStyle}"></Label>
                   <Label Grid.Row="1" Grid.Column="0" Text="{Binding Ano}" Style="{StaticResource labelStyle}"></Label>
                   <Image Grid.Row="0" Grid.RowSpan="2" Grid.Column="1" Source="{Binding Foto}" Aspect="AspectFill"/>
                 </Grid>
               </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>

        </ListView>

    </ContentPage.Content>
</ContentPage>

 

Definimos uma View ListView usando a propriedade ItemsSource para popular a view. Essa propriedade pode aceitar qualquer coleção que implementa a interface IEnumerable.

Para incrementar o desempenho da ListView usamos usar uma estratégia para economizar memória. Para economizar memória, os equivalentes ListView nativos para cada plataforma possuem recursos internos para reutilização de linhas.
 
Somente as células visíveis na tela são carregadas na memória e o conteúdo é carregado nas células existentes. Isso impede que o aplicativo precise instanciar milhares de objetos, economizando tempo e memória.

O Xamarin.Forms permite a reutilização da célula ListView através da enumeração ListViewCachingStrategy, que possui os seguintes valores:

Nossa ListView exibe uma lista de itens e nele usamos um ItemTemplate e DataTemplate que são vinculados para Itens do tipo ObservableCollection e os dados da lista são vinculados com as propriedades da classe Carro: Modelo, Ano e Foto.

Estamos usando uma ViewCell no ListView para formatar a exibição das informações em um Grid com duas linhas e duas colunas.

Além disso estamos aplicando um estilo que foi criado na página App.xaml com o código abaixo:

<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XF_ListViewMVVM.App">
	<Application.Resources>
       <ResourceDictionary>
            <Style x:Key="labelStyle" TargetType="Label">
                <Setter Property="BackgroundColor" Value="White" />
                <Setter Property="FontSize" Value="15" />
                <Setter Property="TextColor" Value="Black" />
            </Style>
        </ResourceDictionary>
    </Application.Resources>
</Application>

Definimos o estilo - labelStyle - para ser aplicado na view Label definindo as propriedades :  BackgroundColor, FontSize e TextColor.

Vinculando a ViewModel

Agora que temos a ViewModel e a ListView definida precisamos conectar a ViewModel com a página via código no arquivo CarrosPage.xaml.cs incluindo o código a seguir:

using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using XF_ListViewMVVM.ViewModels;
namespace XF_ListViewMVVM.Views
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class CarrosPage : ContentPage
    {
        public CarrosPage()
        {
            InitializeComponent();
            BindingContext = new CarrosViewModel();
        }
    }
}

Aqui BindingContext define o objeto que contém as propriedades que serão direcionadas pelas propriedades vinculadas que pertencem a este BindableObject.

Executando o projeto neste momento iremos obter o seguinte resultado:

Como era esperado temos os dois objetos Carros criados no construtor da ViewModel sendo exibidos na página CarrosPage.

Na próxima parte do artigo vamos criar um web service para obter mais carros  para exibir na lista a partir de um serviço remoto.

E a vida eterna é esta: que te conheçam, a ti só, por único Deus verdadeiro, e a Jesus Cristo, a quem enviaste. 
João 17:3

Referências:


José Carlos Macoratti