Xamarin.Forms - Definindo a interface via código XAML e interagindo via código

 

 No artigo de hoje vou mostrar como criar uma aplicação multiplataforma que pode ser usada no Windows Phone, Android e iOS, usando o Xamarin.Forms. O foco de hoje será como definir a interface com o usuário via código XAML na aplicação Xamarin Forms.

 

A XAML (pronúncia zammel) ou Extensible Application Markup Language é uma linguagem baseada em XML criada pela Microsoft para o desenvolvimento de aplicações WPF - Windows Application Foundation.  com objetivo de criar interfaces com usuário e representar dados em aplicações WPF, sendo também usada para criar workflows em aplicações WF - Windows WorkFlow Foundation. (A XAML também podia ser usada no finado Silverlight).

 

O Xamarin.Forms permite aos desenvolvedores definir interfaces de usuário usando XAML ao invés de código C#. Usar XAML não é quesito obrigatório em um programa Xamarin.Forms, mas muitas vezes é mais sucinto que o código C# equivalente, e, também visualmente mais coerente e adequado para uso com a arquitetura do aplicativo MVVM (Model-View-ViewModel): A XAML define a view que está vinculada ao código ViewModel através de ligações de dados baseada em XAML.
 

Usando XAML o desenvolvedor pode definir interfaces de usuário usando todas as views, layouts e pages, bem como classes customizadas, do Xamarin.Forms. O arquivo XAML é analisado em tempo de compilação para localizar os objetos nomeados e novamente em tempo de execução para instanciar e inicializar objetos e estabelecer as vinculações entre os objetos e o código.


A seguir algumas vantagens e desvantagens em usar XAML:

 

1 - Vantagens
 

- XAML é muitas vezes mais sucinto e legível do que o código equivalente;
- A hierarquia pai-filho inerente no XML permite ao XAML imitar a hierarquia pai-filho de objetos de interface do usuário com maior clareza visual;
- XAML pode ser facilmente escrito por programadores, mas também se presta a ser geradas por ferramentas de design visual;

 

2- Desvantagens


- XAML não pode conter código. Todos os manipuladores de eventos devem ser definidos em um arquivo de código separado;(pode ser contornado)

- XAML não pode conter laços para processamento repetitivo; (pode ser contornado)

- XAML não pode conter processamento condicional; (pode ser contornado)

- XAML geralmente não pode instanciar classes que não definem um construtor sem parâmetros;(pode ser contornado)

 

A XAML é basicamente XML, mas possui algumas características únicas na sintaxe. As mais importantes são:

  1. Propriedades de elementos

<Label Text="Hello, XAML!"  VerticalOptions="Center"  FontAttributes="Bold"  FontSize="Large"  TextColor="Aqua" />
  1. Propriedades Anexadas

  • Grid.Row
  • Grid.Column
  1. Extensões de marcação

Extensões de marcação são uma técnica XAML para obtenção de um valor que não é um primitivo nem um tipo específico de XAML. Uma extensão de marcação pode ser implementada para fornecer os valores de propriedades no uso de um atributo, propriedades no uso de um elemento de propriedade, ou ambos.

Quando usado para fornecer um valor de atributo, a sintaxe que distingue uma extensão de marcação para um processador de XAML é a presença de chaves de abertura e fechamento ({ e }). O tipo de extensão de marcação, é em seguida, identificado pelo token de sequência de caracteres imediatamente após a chave de abertura.  Ex:  ...  BindingContext="{x:Reference Name=slider}"...

O código XAML tende a ser mais claro e mais enxuto em muitos casos. Para se ter uma ideia disso abaixo temos a comparação de um trecho de código em XAML e seu equivalente C# :

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="TesteXaml.StackLayout1" Padding="20">
  <StackLayout Spacing="10">
    <Label Text="Parar" BackgroundColor="Red" Font="20" />
    <Label Text="Devagar" BackgroundColor="Yellow" Font="20" />
    <Label Text="Continuar" BackgroundColor="Green" Font="20" />
  </StackLayout>
</ContentPage>
public class StackLayoutExample : ContentPage
{
    public StackLayoutExample()
    {
        Padding = new Thickness(20);
        var red = new Label
        {
            Text = "Parar", BackgroundColor = Color.Red, FontSize = 20
        };
        var yellow = new Label
        {
            Text = "Devagar", BackgroundColor = Color.Yellow, FontSize = 20
        };
        var green = new Label
        {
            Text = "Continuar", BackgroundColor = Color.Green, FontSize = 20
        };
        Content = new StackLayout
        {
            Spacing = 10,
            Children = { red, yellow, green }
        };
    }
}

Neste artigo vou mostrar como definir uma interface básica via código XAML.

Nota:  Para saber mais sobre a sintaxe XAML veja o meu artigo : Introdução a XAML - Macoratti.net

Requisitos necessários :

Criando a solução Xamarin.Forms no Visual Studio 2015

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

Selecione Visual C#, o template Cross Plataform e a seguir Blank App (Xamarin.Forms Portable);

Nota :  A opção Portable (Portable Class Library - PCL ) - Inclui todo o código comum em uma biblioteca de vínculo dinâmico (DLL) que pode então ser referenciada a partir de outros projetos;

Informe o nome App.XamarinFormsXAML e clique no botão OK;

Ao clicar no botão OK, será criada uma solução contendo 4 projetos. (Dependendo do seu ambiente pode haver alguma variação nos projetos.)

  • 1 Projeto Comum contendo a maior parte do código da aplicação : (Este é o projeto Portable cuja compilação pode ser compartilhada com outras plataformas)
  • 1 Projeto para plataforma Android
  • 1 Projeto para plataforma iOS
  • 1 Projeto para Windows 8.1 ou para Windows 10
  • 1 Projeto para plataforma Windows Phone

O projeto comum possui a classe App.cs que irá conter o código compartilhado e que vamos usar neste artigo.

Incluindo uma nova página XAML

No menu Project clique em Add New Item;

Selecione o template Cross Plataform -> Forms Xaml Page e informe o nome Pagina1.xaml e clique em Add;

Após incluir a nova página XAML no projeto abrindo o arquivo Pagina1.xaml  veremos o seguinte código:

Na primeira linha temos o prólogo XML.

Na segunda linha temos tudo que é preciso para criar uma instância da classe ContentPage dentro no elemento ContentPage.

Os dois primeiros atributos são declaração de namespaces (xmlns) que apontam para URLs, a primeira para o site da Xamarin e a segunda para o site da Microsoft, que são usadas para fornecer o mecanismo para  versionar a funcionalidade disponível nesta classe.

A primeira declaração de namespace XML significa que as tags definidas no arquivo XAML com nenhum prefixo se referem a classes em Xamarin.Forms, por exemplo ContentPage.

A segunda declaração de namespace define um prefixo de x. Isso é usado por vários elementos e atributos que são intrínsecos ao XAML propriamente dito, e que (em teoria) são suportados por todas as implementações de XAML. No entanto, esses elementos e atributos são ligeiramente diferentes dependendo do ano incorporado no URI. O Xamarin.Forms suporta a especificação de XAML de 2009.

Imediatamente após o prefixo x ser declarado, ele é usado para um atributo chamado Class (x:Class) que especifica um nome de classe totalmente qualificado do .NET: a classe Pagina1 no namespace App.XamarinFormsXAML.

Isto significa que este arquivo XAML define uma nova classe chamada Pagina1 no namespace App.XamarinFormsXAML que deriva de ContentPage — a tag em que aparece o atributo x:Class.

O atributo x:Class só pode aparecer no elemento raiz de um arquivo XAML para definir uma classe derivada do C#. Esta é a única nova classe definida no arquivo XAML. Tudo o que aparece no arquivo XAML é em vez disso simplesmente instanciado e inicializado.

Além disso temos o arquivo code-behind Pagina1.xaml.cs que possui neste momento o seguinte conteúdo:

Observe a definição de classe parcial e note que Pagina1 deriva de ContentPage.  É aqui que colocamos o código C# que pode interagir com a página.

Durante o ciclo compilação-deploy-run o arquivo XAML é analisado duas vezes. Ele é analisado primeiro durante o processo de compilação. Todo o arquivo XAML também está vinculado à DLL Portable Code Library, e mais uma vez, ele é analisado em tempo de execução.

Durante a etapa de compilação, um arquivo de código do c# é gerado a partir do arquivo XAML. Se você olhar no diretório \App.XamarinFormsXAML\App.XamarinFormsXAML\App.XamarinFormsXAML\obj\Debug, você encontrará um arquivo chamado App.XamarinFormsXAML.Pagina1.xaml.g.cs.

O 'g' significa gerado. Aqui está o conteúdo deste arquivo :

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace App.XamarinFormsXAML {
    using System;
    using Xamarin.Forms;
    using Xamarin.Forms.Xaml;
        
    public partial class Pagina1 : global::Xamarin.Forms.ContentPage {
        [System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Forms.Build.Tasks.XamlG", "0.0.0.0")]
        private void InitializeComponent() {
            this.LoadFromXaml(typeof(Pagina1));
        }
    }
}

Para poder usar essa página em nossa aplicação temos que alterar o código definido no arquivo App.cs do projeto compartilhado definindo o construtor da classe para atribuir a MainPage uma instância da nossa Pagina1:

using Xamarin.Forms;
namespace App.XamarinFormsXAML
{
    public class App : Application
    {
        public App()
        {
            MainPage = new Pagina1();
        }
        protected override void OnStart()
        {
            // Handle when your app starts
        }
        protected override void OnSleep()
        {
            // Handle when your app sleeps
        }
        protected override void OnResume()
        {
            // Handle when your app resumes
        }
    }
}

Agora podemos definir o código XAML em Pagina1 e compilar o projeto para as 3 plataformas.

A seguir é muito simples incluir conteúdo e elementos na Page Xamarin.Forms.

Neste exemplo vamos usar a ContentPage e iremos tratar a propriedade Content que é mapeada para o XML interno do nó ContentPage. Um dos efeitos colaterais em usar o tipo Page é que ele somente permite uma única view ser adicionada na propriedade Content.

Vamos iniciar usando esta abordagem bem simples definindo algumas propriedades da página e um controle Label conforme mostrado a seguir:

<?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="App.XamarinFormsXAML.Pagina1"
             Title="Usando XAML"
             BackGroundColor = "Green"
             Padding="10, 40, 10, 10"
>
 
 <Label Text="Macoratti .net"
         VerticalOptions="Start"
         HorizontalTextAlignment="Center"
         Rotation="-15"
         IsVisible="true"
         FontSize="Large"
         FontAttributes="Bold"
         TextColor="Yellow" />

</ContentPage>
 

Vamos entender o código :

Uma classe Xamarin.Forms (como ContentPage ou Label) aparece no arquivo XAML como um elemento XML, e propriedades da classe — incluindo Title e Padding em ContentPage, e, sete propriedades da Label — aparecem como atributos XML.

Existem muitos atalhos para definir os valores dessas propriedades. Algumas propriedades são tipos de dados básicos: por exemplo, as propriedades Title e Text são do tipo String, Rotation é do tipo Double e IsVisible (que é true por padrão e é definida aqui apenas para ilustração) é do tipo Boolean.

A propriedade HorizontalTextAlignment é do tipo TextAlignment, que é uma enumeração. Para uma propriedade de qualquer tipo de enumeração, tudo que você precisa fazer é fornecer o nome do membro.

Para propriedades de tipos mais complexos, no entanto, são usados conversores para analisar o XAML.

Existem classes no Xamarin.Forms que derivam de TypeConverter. Muitas são classes públicas, mas algumas não são. Para este arquivo XAML, várias dessas classes desempenham um papel nos bastidores:

- ThicknessTypeConverter para a propriedade Padding
- LayoutOptionsConverter para a propriedade VerticalOptions
- FontSizeConverter para a propriedade FontSize
- ColorTypeConverter para a propriedade TextColor

Esses conversores essencialmente regem a sintaxe permissível das configurações de propriedade.

Como vimos, em XAML as propriedades das classes são normalmente definidas como atributos XML. Exemplo:

<Label Text="Macoratti .net"
       VerticalOptions="Center"
       FontAttributes="Bold"
       FontSize="Large"
       TextColor="Aqua" />

 

Porém existe uma forma alternativa de atribuir uma propriedade usando XAML. Vamos mostrar isso usando a propriedade TextColor:

<Label Text="Macoratti .net"
       VerticalOptions="Center"
       FontAttributes="Bold"
       FontSize="Large">
  <Label.TextColor>
       Aqua
  </Label.TextColor>
</Label>

 

Essas duas formas de especificar a propriedade TextColor são funcionalmente equivalentes mas você deve escolher qual delas vai usar na mesma propriedade.

A seguir estamos usando a sintaxe propriedades-elementos para todas as propriedades :

<Label>
  <Label.Text>
       Macoratti .net
  </Label.Text>
  <Label.FontAttributes>
    Bold
  </Label.FontAttributes>
  <Label.FontSize>
    Large
  </Label.FontSize>
  <Label.TextColor>
    Aqua
  </Label.TextColor>
  <Label.VerticalOptions>
    Center
  </Label.VerticalOptions>
</Label>

Nesta sintaxe também temos um terminologia introduzida:

Usando XAML e interação de código

Até agora Pagina1 contém apenas uma Label na página, mas grande parte das aplicações utilizam algum layout na propriedade Content como um StackLayout.

Vamos incluir um layout do tipo StackLayout e definir 3 novos controles : 1 Label, 1 Slider e 1 Button:

<?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="App.XamarinFormsXAML.Pagina1"
             Title="Usando XAML"    BackgroundColor="Green"  Padding="10, 40, 10, 10" >
  <StackLayout>
     <Label Text="Macoratti .net - quase tudo para .Net"
         VerticalOptions="Start"
         HorizontalTextAlignment="Center"
         Rotation="-15"
         IsVisible="true"
         FontSize="Large"
         FontAttributes="Bold"
         TextColor="Yellow" />  
    <Slider VerticalOptions="CenterAndExpand" />
    <Label Text="Macoratti .net - http://www.macoratti.net"
           Font="Large"
           HorizontalOptions="Center"
           VerticalOptions="CenterAndExpand" />
    <Button Text="Clique Aqui !"
            HorizontalOptions="Center"
            VerticalOptions="CenterAndExpand" />

  </StackLayout>
</ContentPage>

Você vai perceber que podemos interagir com o controle Slider e com o controle Button mas não veremos resultado algum.

Para isso temos que tratar o evento Click do Button e o evento ValueChanged do Slider, e, podemos fazer isso interagindo o código com o XAML.

Devemos alterar o código XAML e incluir os atributos ValueChanged e Clicked nos respectivos controles:

<?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="App.XamarinFormsXAML.Pagina1"
             Title="Usando XAML"    BackgroundColor="Green"  Padding="10, 40, 10, 10" >
  <StackLayout>
     <Label Text="Macoratti .net - quase tudo para .Net"
         VerticalOptions="Start"
         HorizontalTextAlignment="Center"
         Rotation="-15"
         IsVisible="true"
         FontSize="Large"
         FontAttributes="Bold"
         TextColor="Yellow" />  
    <Slider VerticalOptions="CenterAndExpand" ValueChanged = "OnSliderValueChanged"  />
    <Label x:Name="lblValor"
       Text=""
       Font="Large"
       HorizontalOptions="Center"
       VerticalOptions="CenterAndExpand" />
    <Label Text="Macoratti .net - http://www.macoratti.net"
           Font="Large"
           HorizontalOptions="Center"
           VerticalOptions="CenterAndExpand" />
    <Button Text="Clique Aqui !"
            HorizontalOptions="Center"
            VerticalOptions="CenterAndExpand" 
             Clicked ="OnButtonClicked"
            />

  </StackLayout>
</ContentPage>

Agora definimos os eventos OnSliderValueChanged e OnButtonClicked que vamos tratar no código e incluímos um novo controle Label chamado lblValor onde vamos exibir o valor do controle Slider.

Agora abrindo o arquivo Pagina1.xaml.cs podemos definir o código abaixo para tratar esses eventos:

using System;
using Xamarin.Forms;
namespace App.XamarinFormsXAML
{
    public partial class Pagina1 : ContentPage
    {
        public Pagina1()
        {
            InitializeComponent();
        }
        void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
        {
            lblValor.Text = ((Slider)sender).Value.ToString("F3");
        }
        async void OnButtonClicked(object sender, EventArgs args)
        {
            Button button = (Button)sender;
            await DisplayAlert("Clicado!", "O botão '" + button.Text + "' foi clicado", "OK");
        }
    }
}

O método é definido como async porque o método DisplayAlert é assíncrono e deve ser precedido com o operador await, que retorna quando o método completa.

Vemos assim que um objeto definido via XAML pode disparar um evento que é tratado no arquivo code-behind, e que o arquivo code-behind pode acessar um objeto definido no XAML usando o nome atribuído a ele com o atributo x:Name.

Estas são as duas maneiras fundamentais de interagir XAML e código.

Executando o projeto teremos o seguinte resultado:

1- Acionando o Slider

2- Clicando no Botão

Pegue o projeto aqui :  App.XamarinFormsXAML.zip  (sem as referências)

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