Xamarin Forms - Protótipo para aplicativo de Lanches

 Neste artigo eu vou apresentar um protótipo de uma aplicação para lanches que mostra um exemplo de utilização da interface INotifyPropertyChanged em uma aplicação Xamarin Forms.

Vamos criar uma aplicação protótipo para venda de lanches em uma app usando alguns recursos do Xamarin Forms e a interface INotifyPropertyChanaged usada para notificar a interface quando ocorrer uma alteração no valor de uma propriedade do modelo.

Abaixo podemos ver a App em funcionamento:

A aplicação é composta por 4 páginas exibidas a seguir:

Veremos a seguir uma explicação resumida de cada página da aplicação.

Recursos Usados

Criando o projeto Xamarin Forms

Abra o  VS 2017 Community update 15.5 e clique em New Project e a seguir escolha Cross Platform -> Cross Platform App (Xamarin.Forms) e informe o nome XF_Lanches.

Ao criar um projeto Xamarin Forms em uma versão anterior à atualização 15.5, você tinha duas opções para compartilhar o código entre as plataformas:

  1. Shared Project
  2. Portable Class Library (PCL)

Pois a partir da versão 15.5 do Visual Studio(lançada em dezembro/2017) a opção Portable Class Library (PCL) foi substituida pela .NET Standard:

Marque as opções Android e/ou iOS, marque Xamarin Forms e a seguir marque .NET Standard e clique no botão OK.

Pronto nosso projeto já esta criado.

Definindo o modelo de domínio

Vamos criar uma pasta Models no projeto e a seguir criar as seguintes classes que vão representa o nosso modelo de domínio:

1- Usuario

namespace XF_Lanches.Models
{
    public class Usuario
    {
        public string Nome { get; set; }
        public string Email { get; set; }
        public string Telefone { get; set; }
    }
}

2- Lanche

using System;
using System.ComponentModel;
namespace XF_Lanches.Models
{
    public class Lanche : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        private void RaisePropertyChanged(string prop)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(prop));
        }
        public string Nome { get; set; }
        public string Descricao { get; set; }
        public string Status { get; set; }
        public decimal Preco { get; set; }
        public string ImagemUrl { get; set; }
        private const decimal OVO = 1.50M;
        private const decimal BACON = 2.00M;
        private const decimal CATUPIRY = 2.50M;
        private const decimal CHEDDAR = 2.00M;
        private const decimal MAIONESE = 1.00M;
        public string TextoOvo
        {
            get { return String.Format("Ovo - R$ {0}", OVO); }
        }
        public string TextoBacon
        {
            get { return String.Format("Bacon - R$ {0}", BACON); }
        }
        public string TextoCatupiry
        {
            get { return String.Format("Catupri - R$ {0}", CATUPIRY); }
        }
        public string TextoCheddar
        {
            get { return String.Format("Cheddar - R$ {0}", CHEDDAR); }
        }
        public string TextoMaionese
        {
            get { return String.Format("Maionese - R$ {0}", MAIONESE); }
        }
        public string ValorTotal
        {
            get
            {
                return string.Format("Valor Total: R$ {0}",Preco
                    + (TemOvo ? OVO : 0) + (TemBacon ? BACON : 0) 
                    + (TemMaionese ? MAIONESE : 0) + (TemCheddar ? CHEDDAR : 0) + (TemCatupiry ? CATUPIRY : 0));
            }
        }
        private bool temOvo;
        public bool TemOvo
        {
            get{return temOvo;}
            set{
                temOvo = value;
                RaisePropertyChanged(nameof(ValorTotal));
            }
        }
        private bool temMaionese;
        public bool TemMaionese
        {
            get
            {return temMaionese;}
            set
            {
                temMaionese = value;
                RaisePropertyChanged(nameof(ValorTotal));
            }
        }
        private bool temBacon;
        public bool TemBacon
        {
            get
            {return temBacon;}
            set
            {
                temBacon = value;
                RaisePropertyChanged(nameof(ValorTotal));
            }
        }
        private bool temCheddar;
        public bool TemCheddar
        {
            get
            {return temCheddar;}
            set
            {
                temCheddar = value;
                RaisePropertyChanged(nameof(ValorTotal));
            }
        }
        private bool temCatupiry;
        public bool TemCatupiry
        {
            get
            {return temCatupiry;}
            set
            {
                temCatupiry = value;
                RaisePropertyChanged(nameof(ValorTotal));
            }
        }
    }
}

3- Acrescimo

namespace XF_Lanches.Models
{
    public class Acrescimo
    {
        public int AcrescimoId { get; set; }
        public string Nome { get; set; }
        public string Valor { get; set; }
        //
        public decimal Maionese { get; } = 1.00M;
        public decimal Ovo { get; }
        public decimal Cheddar { get; }
        public decimal Catupiry { get; }
        public decimal Bacon { get; }
    }
}

Instale o pacote em todos os projetos clicando em Install.

Exibindo os lanches na página inicial : MainPage.xaml

Abra o arquivo MainPage.xaml e inclua no 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:local="clr-namespace:XF_Lanches"
             x:Class="XF_Lanches.MainPage"
             Title="MacLanches - Peça o seu Agora !!!">
    <ListView x:Name="lvLanches" HasUnevenRows="True" ItemSelected="Handle_ItemSelected" SeparatorColor="Blue">
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <StackLayout Orientation="Horizontal" HorizontalOptions="Center" VerticalOptions="Center">
                        <StackLayout HorizontalOptions="CenterAndExpand" Orientation="Horizontal">
                            <Image Source="{Binding ImagemUrl}" HeightRequest="100" WidthRequest="100"/>
                            <Label Text="{Binding Nome}" TextColor="Black" HorizontalOptions="Center" VerticalOptions="Center"/>
                        </StackLayout>
                    </StackLayout>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</ContentPage>
 

No arquivo MainPage.xaml.cs temos o código onde definimos alguns lanches para serem exibidos e tratamos o item selecionado :
 
using System.Collections.Generic;
using Xamarin.Forms;
using XF_Lanches.Models;
namespace XF_Lanches
{
          public partial class MainPage : ContentPage
	{
		public MainPage()
		{
			InitializeComponent();
                                lvLanches.ItemsSource = new List<Lanche>
            {
                new Lanche { Nome="Cheese Burger", Descricao="", Status="Ativo", Preco=12.90M ,ImagemUrl="http://www.macoratti.net/Imagens/lanches/cheeseBurger.jpg" },
                new Lanche { Nome="Cheese Salada", Descricao="", Status="Ativo", Preco=14.50M ,ImagemUrl="http://www.macoratti.net/Imagens/lanches/chesseSalada.jpg" },
                new Lanche { Nome="Cheese Egg", Descricao="", Status="Ativo", Preco=15.50M ,ImagemUrl="http://www.macoratti.net/Imagens/lanches/cheeseEgg.jpg" },
                new Lanche { Nome="Cheese Tudo", Descricao="", Status="Ativo", Preco=18.00M ,ImagemUrl="http://www.macoratti.net/Imagens/lanches/cheeseTudo.jpg" },
                new Lanche { Nome="Lanche de Frango", Descricao="", Status="Ativo", Preco=13.90M ,ImagemUrl="http://www.macoratti.net/Imagens/lanches/lancheFrango.jpg" },
                new Lanche { Nome="Misto Quente", Descricao="", Status="Ativo", Preco=10.50M ,ImagemUrl="http://www.macoratti.net/Imagens/lanches/lancheMistoQuente.jpg" }
            };
        }
        public async void Handle_ItemSelected(object sender, SelectedItemChangedEventArgs e)
        {
            var lanche = e.SelectedItem as Lanche;

            if (lanche == null)
                return;
            await this.Navigation.PushAsync(new LancheDetailsPage(lanche));
        }
    }
}

Incluindo acréscimos ao lanche : LancheDetailsPage.xaml

Esta página exibe o lanche selecionado e as opções de acréscimos que o usuário pode incluir ao lanche. Aqui usamos o two way databinding e aplicamos a notificação via INotifyPropertyChanged:
 
<?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_Lanches.LancheDetailsPage"
             Title="{Binding Nome}">
    <ContentPage.Content>
        <StackLayout Padding="10">
            <Image Source="{Binding ImagemUrl}" HeightRequest="100" WidthRequest="100"/>
            <TableView>
                <TableRoot>
                    <TableSection Title="Acréscimos">
                        <SwitchCell Text="{Binding TextoMaionese}" On="{Binding TemMaionese, Mode=TwoWay}"></SwitchCell>
                        <SwitchCell Text="{Binding TextoBacon}" On="{Binding TemBacon, Mode=TwoWay}"></SwitchCell>
                        <SwitchCell Text="{Binding TextoOvo}" On="{Binding TemOvo, Mode=TwoWay}"></SwitchCell>
                        <SwitchCell Text="{Binding TextoCheddar}" On="{Binding TemCheddar, Mode=TwoWay}"></SwitchCell>
                        <SwitchCell Text="{Binding TextoCatupiry}" On="{Binding TemCatupiry, Mode=TwoWay}"></SwitchCell>
                        <TextCell Text="{Binding ValorTotal}" TextColor="Blue" ></TextCell>
                    </TableSection>
                </TableRoot>
            </TableView>
            <Button x:Name="btnProximo" Text="Próximo" Clicked="btnProximo_Clicked" VerticalOptions="End" 
TextColor="White" BackgroundColor="Green" FontAttributes="Bold"></Button>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

No arquivo LanchesDetailsPage.xaml.cs temos o código que trata o evento Click e avança para próxima página:
 
using System;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using XF_Lanches.Models;
namespace XF_Lanches
{
        [XamlCompilation(XamlCompilationOptions.Compile)]
        public partial class LancheDetailsPage : ContentPage
        {
                 Lanche _lanche;
                   public LancheDetailsPage (Lanche lanche)
	         {
			InitializeComponent ();
                               _lanche = lanche;
                                this.BindingContext = _lanche;
	        }
        async void btnProximo_Clicked(object sender, EventArgs e)
        {
            if (_lanche == null)
                return;
            await this.Navigation.PushAsync(new LanchePedidoPage(_lanche));
        }
    }
}

Apresentando a página de pedido : LanchePedidoPage.xaml

Nesta página apresentamos o pedido feito pelo usuário e solicitamos seu nome, email e telefone antes de confirmar o pedido:
 
<?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_Lanches.LanchePedidoPage"
             Title="{Binding Nome}">
    <ContentPage.Content>
        <StackLayout Padding="10">
        <TableView>
            <TableRoot>
                <TableSection Title="Seu Pedido">
                   <ImageCell ImageSource="{Binding ImagemUrl}" />
                   <TextCell Text="{Binding Nome}" TextColor="Blue"></TextCell>
                   <TextCell Text="{Binding ValorTotal}" TextColor="Blue"></TextCell> 
                </TableSection>
                <TableSection Title="Seu Dados">
                    <EntryCell x:Name="strNome" Label="Nome" Placeholder="Informe o seu nome"></EntryCell>
                    <EntryCell x:Name="strFone" Label="Fone:" Placeholder="Informe o seu telefone" Keyboard="Telephone"></EntryCell>
                    <EntryCell x:Name="strEmail" Label="Email:" Placeholder="Informe o seu email" Keyboard="Email"></EntryCell>
                </TableSection>
            </TableRoot>
        </TableView>
            <Button x:Name="btnPedido" Text="Concluir Pedido" Clicked="btnPedido_Clicked" VerticalOptions="End" 
TextColor="White" BackgroundColor="Blue" FontAttributes="Bold"></Button>
        </StackLayout>       
    </ContentPage.Content>
</ContentPage>

No código do arquivo LanchePedidoPage.xaml.cs obtemos as informações do cliente e após validação navegamos para a página de confirmação do pedido:

using System;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using XF_Lanches.Models;
namespace XF_Lanches
{
           [XamlCompilation(XamlCompilationOptions.Compile)]
	public partial class LanchePedidoPage : ContentPage
	{
       	 	Lanche _lanche;
        		Usuario _usuario;
		public LanchePedidoPage (Lanche lanche)
		{
			InitializeComponent ();
         			this._lanche = lanche;
            			this.BindingContext = _lanche;
		}
        async void btnPedido_Clicked(object sender, EventArgs e)
        {
            if (_lanche == null)
                return;
            if (string.IsNullOrEmpty(strNome.Text))
                return;
            if (string.IsNullOrEmpty(strEmail.Text))
                return;
            if (string.IsNullOrEmpty(strFone.Text))
                return;
            _usuario = new Usuario();
            _usuario.Nome = strNome.Text;
            _usuario.Telefone = strFone.Text;
            _usuario.Email = strEmail.Text;
             await this.Navigation.PushModalAsync(new LanchePedidoConfirmacao(_lanche));
        }
    }
}

Apresentando a página de confirmação do pedido :  LanchePedidoConfirmacao.xaml

Na página  de confirmação do pedido apresentamos a imagem do lanche e o valor total do pedido:
 
<?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_Lanches.LanchePedidoConfirmacao"
             Title="{Binding Nome}"
             BackgroundColor="Cyan">
    <ContentPage.Content>                
        <StackLayout Padding="20" VerticalOptions="Center" HorizontalOptions="Center">
            <Frame>
               <Image Source="{Binding ImagemUrl}" HeightRequest="200" WidthRequest="200" VerticalOptions="Center" HorizontalOptions="Center"/>
            </Frame>
            <Frame>
                <Label Text="{Binding ValorTotal}" FontSize="Large" TextColor="Blue" VerticalOptions="Center" HorizontalOptions="Center"/>
            </Frame>
            <Label Text="Seu pedido foi recebido com sucesso, em poucos minutos estará chegando..." TextColor="Black" FontSize="Medium" 
VerticalOptions="Center" HorizontalOptions="Center"/>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

No código do arquivo LanchePedidoConfirmacao.xaml.cs apenas recebemos o lanche e fazemos a vinculação no BindingContext:
 
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using XF_Lanches.Models;
namespace XF_Lanches
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
	public partial class LanchePedidoConfirmacao : ContentPage
	{
		public LanchePedidoConfirmacao (Lanche lanche)
		{
			InitializeComponent ();
 		            this.BindingContext = lanche;
		}
	}
}

Este exemplo é bem simples e foi feito apenas para mostrar como usar o recurso de notificação da interface INotifyPropertyChanged

Podemos otimizar o código usado no projeto mas o objetivo era mesmo mostrar a interface INotifyPropertyChanged na sua forma nua e crua.

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

"Tomando sobretudo o escudo da fé, com o qual podereis apagar todos os dardos inflamados do maligno. "
Efésios 6:16

 

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

  Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter

Referências:


José Carlos Macoratti