Desenvolvimento - ASP. NET

Windows Presentation Foundation - Introdução ao XAML

O XAML (pronuncia-se "zemel") é a nova linguagem de marcação usada para criar interfaces de usuário de forma simples e rápida. É equivalente, porém muito mais poderosa que sua "antecessora", o HTML.

por José Antonio Leal de Farias



Introdução

O XAML (pronuncia-se "zemel") é a nova linguagem de marcação usada para criar interfaces de usuário de forma simples e rápida. É equivalente, porém muito mais poderosa que sua "antecessora", o HTML.

O XAML não é uma linguagem em si. Ela é exatamente como o XML, que não contém nenhum tag específico, mas apenas as regras para crias suas próprias tags. O XAML também é a forma marcação para acessar o modelo de objetos do novo Windows Presentation Foundation e você pode ainda criar seus próprios objetos e acessá-los através do XAML.

Na programação dos dias de hoje, você cria interfaces do usuário escrevendo código em uma linguagem que basicamente foi criada para modelar processos de negócio (C#, C++, Java, etc.). Isso leva tempo e diminui bastante a legibilidade de seu código.Por exemplo, vamos supor que você vai construir uma interface de usuário muito simples para o login do usuário totalmente escrito em C#, como na listagem 1:

Listagem 1 - Código da janela de login em C#

class Form1 : Form
{
     private System.Windows.Forms.Label label1;
     private System.Windows.Forms.TextBox txtName;
     private System.Windows.Forms.TextBox txtPassword;
     private System.Windows.Forms.Label label2;

     public Form1()
     {
   	this.label1 = new System.Windows.Forms.Label();
	this.txtName = new System.Windows.Forms.TextBox();
	this.txtPassword = new System.Windows.Forms.TextBox();
	this.label2 = new System.Windows.Forms.Label();
	this.SuspendLayout();

	this.label1.AutoSize = true;
 	this.label1.Location = new System.Drawing.Point(33, 24);
	this.label1.Name = "label1";
	this.label1.Size = new System.Drawing.Size(61, 14);
	this.label1.TabIndex = 0;
	this.label1.Text = "User Name";

	this.txtName.Location = new System.Drawing.Point(104, 23);
	this.txtName.Name = "txtName";
	this.txtName.Size = new System.Drawing.Size(151, 20);
	this.txtName.TabIndex = 1;
	
	this.txtPassword.Location = new System.Drawing.Point(104, 53);
	this.txtPassword.Name = "txtPassword";
	this.txtPassword.Size = new System.Drawing.Size(151, 20);
	this.txtPassword.TabIndex = 3;

	this.label2.AutoSize = true;
	this.label2.Location = new System.Drawing.Point(17, 51);
	this.label2.Name = "label2";
	this.label2.Size = new System.Drawing.Size(81, 14);
	this.label2.TabIndex = 2;
	this.label2.Text = "User Password";

	this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
	this.ClientSize = new System.Drawing.Size(280, 91);
	this.Controls.Add(this.txtPassword);
	this.Controls.Add(this.label2);
	this.Controls.Add(this.txtName);
	this.Controls.Add(this.label1);
	this.Name = "Form1";
	this.Text = "Form1";
	this.ResumeLayout(false);
	this.PerformLayout();

    }
}

Observe que você tem de escrever muitas linhas para criar esta interface simples. Só para ter uma idéia, veja na listagem 2 o código XAML que obtém o mesmo resultado:

Listagem 2 - Código XAML para a janela de login

<Canvas xmlns="http://schemas.microsoft.com/winfx/avalon/2005" Background="LightGray">
	<TextBlock Canvas.Left="33" Canvas.Top="29" Width="68" Height="14"> Usuário</TextBlock >
      	<TextBox Canvas.Left="85" Canvas.Top="23" Width="151" Height="25"/>
      	<TextBlock Canvas.Left="33" Canvas.Top="59" Width="95" Height="14">Senha</TextBlock >
      	<PasswordBox Canvas.Left="85" Canvas.Top="53" Width="151" Height="25"/>	
</Canvas >

Observe a simplicidade e imagine o quão rápido você pode projetar as interfaces gráficas de sua aplicação. Porque não pensaram nisso antes??

Antes de Começarmos

Tenho de ressaltar que todo o código e procedimentos descritos neste artigo são baseados nas versões beta do SDK do Winfx lançadas no PDC de Setembro de 2005 e que podem não ser realidade na versão final do Winfx.

Não usaremos o Visual Studio neste artigo. Apesar do VS2005 oferecer uma melhor produtividade, neste artigo inicial usaremos uma ferramenta mais simples para testarmos nossos exemplos, o XAMLPAD, que acompanha o SDK do Winfx. O XAMLPAD pode ser visto na figura 1 executando o exemplo do login.


Figura 1 - A interface do XAMLPAD.

Um Pouco de Teoria

O XAML dá a você uma forma rápida e fácil de criar suas interfaces gráficas de forma totalmente visual, como fazemos hoje com páginas Web. Podemos agora entregar essa tarefa facilmente a um XAML-Designer (mais uma profissão aí gente!) e, da mesma forma como fazemos com ASP.NET, entregar a parte do negócio aos programadores! Quem desenvolve pode usar lógica que será invocada em eventos gerados pelos componentes da interface. Esta meta é alcança com extrema elegância com a ajuda de um novo recurso do C# 2.0 chamado de classes parciais.

Todo tag XAML é um objeto do Presentation Foundation (o antigo Avalon) e o XAML é a forma marcação de acessar estes objetos. Portanto, sempre que você cria interfaces de usuário usando XAML, você estará criando também uma classe que conterá o código de negócio desse documento XAML, da mesma forma como temos o code-behind em páginas ASP.NET. Usando essa abordagem, um designer poderá criar a interface sem se preocupar com a lógica da mesma. Da mesma forma, o programador pode se ocupar do negócio sem se preocupar no design da interface que está sendo criada. Isso também melhora a legibilidade do programa, porque o código de design e o código de negócio estão em arquivos diferentes no seu programa. O XAML é apenas XML. E daí?

O XAML não é uma linguagem de programação nem é uma linguagem de marcação, como o HTML. Você não pode criar interfaces gráficas usando o XAML em si, pois ele não tem tags nativos.

Então como você pode criar interfaces usando XAML? Ele basicamente acessa objetos definidos pelo Presentation Foundation ou por você mesmo. Ele não possui tags pré-definidos, ele apenas acessa objetos criados de alguma outra forma.

O XAML é exatamente como o XML, porque o XML não tem nenhum tag pré-definido, mas apenas define regras para criar tags. O XAML segue e mesma regra de sintaxe do XML.

Vamos ao que interessa

Nós já discutimos teorias suficientes, agora é hora de fazer algum trabalho prático e eu acredito na filosofia do "Aprender Fazendo". Se você quer ser um mestre em qualquer tecnologia, leia a teoria primeiro, faça algum trabalho prático usando a tecnologia e então faça algumas perguntas sobre o que você fez. Para sabermos exatamente onde estamos pisando, não vamos usar nenhum ambiente de desenvolvimento sofisticado, como o Visual Studio. Vamos usar apenas o SDK do Winfx e o bloco de notas.

Vamos começar com o tradicional exemplo "Alô Mundo! Na listagem 3 vemos este programa em XAML.

Listagem 3 - Código XAML do Alô mundo

<Canvas xmlns="http://schemas.microsoft.com/winfx/avalon/2005" Background="LightGray">
	<TextBlock FontSize="24">
		Alô Mundo!
	</TextBlock >
</Canvas >

Ele deve ficar como na figura 2.


Figura 2 - Alô Mundo!

Você pode também criar esse programa no bloco de notas e salvar com extensão .xaml. Clique duas vezes no arquivo - ele será aberto no Internet Explorer. Legal não?

Observe o tag <canvas>. O XAML tem diferentes tipos de panels e Canvas é um recipiente que contém outros elementos como <TextBlock> em nosso exemplo que podem ser arranjados em termos de coordenadas x,y. Veremos diferentes tipos de recipientes ao longo de meus artigos.

O que o xmlns e por que eu associei um URL a ele? O XAML é uma linguagem extensível para que você possa definir seus próprios elementos. Imagine que você escreveu no seu próprio XAML um elemento denominado <TextBlock>, e por algum motivo você precisa de um elemento <TextBlock> em seu documento XAML que NÃO é o <TextBlock> do Presentation Foundation. Como o Presentation Foundation já tem um elemento <TextBlock>, então seria impossível para o interpretador interpretar qual é o seu elemento <TextBlock> e qual é o fornecido pelo Presentation Foundation. Veja o código da listagem 4 que ilustra esta situação;

Listagem 4 - O tag <TextBlock> customizado

<Canvas xmlns="http://schemas.microsoft.com/winfx/avalon/2005" Background="LightGray" 
xmlns:myelems="my.elements">
<myelems:TextBlock FontSize="24">Meu TextBlock</TextBlock >
<TextBlock FontSize="24">Alô Mundo!</TextBlock >
</Canvas >

Nesta situação nós atribuímos um único nome aos elementos que criamos e esse nome será usado no atributo xmlns. Mais tarde você referenciará esses elementos pelo prefixo que você atribuiu ao seu namespace.

Você criou um namespace para separar seus elementos de outros. O nome do seu namespace é "my.elements" e você atribuiu um prefixo a ele para que você não escreva o nome todo, toda vez que você acesse seus elementos. Você usará apenas o prefixo quando quiser acessar seus elementos. Neste exemplo o prefixo que você atribuiu para acessar seus elementos é "myelems".

Eventos

O XAML suporta tanto eventos de alto nível como eventos de baixo nível. Para manusear eventos de alto nível você tem que escrever o código em uma linguagem nativa do .NET (tipo o code-behind do ASP.NET), mas alguns eventos de baixo nível podem ser manuseados apenas no XAML. Você não tem que escrever uma única linha do código para manusear alguns eventos de baixo nível.

Agora vamos escrever um programa simples para demonstrar o uso de eventos no XAML.

Listagem 5 - Usando Eventos

<Canvas xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
    xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"
    >
  <Canvas.Resources>
    <Style TargetType="{x:Type Rectangle}">
      <Setter Property="Width" Value="50" />
      <Setter Property="Height" Value="50" />
      <Setter Property="Margin" Value="20" />
      <Setter Property="HorizontalAlignment" Value="Left" />
      <Style.Triggers>
        <EventTrigger RoutedEvent="Rectangle.MouseEnter">
          <EventTrigger.Actions>
            <BeginStoryboard>
              <BeginStoryboard.Storyboard>
                <Storyboard>
                  <DoubleAnimation To="300" Duration="0:0:1.5" 
                    AccelerationRatio="0.10" DecelerationRatio="0.25" 
                    Storyboard.TargetProperty="(Canvas.Width)" />
                </Storyboard>
              </BeginStoryboard.Storyboard>
            </BeginStoryboard>
          </EventTrigger.Actions>
        </EventTrigger>
        <EventTrigger RoutedEvent="Rectangle.MouseLeave">
          <EventTrigger.Actions>
            <BeginStoryboard>
              <BeginStoryboard.Storyboard>
                <Storyboard>
                  <DoubleAnimation Duration="0:0:1.5" 
                    AccelerationRatio="0.10" DecelerationRatio="0.25" 
                    Storyboard.TargetProperty="(Canvas.Width)" />
                </Storyboard>
              </BeginStoryboard.Storyboard>
            </BeginStoryboard>
          </EventTrigger.Actions>
        </EventTrigger>
      </Style.Triggers>
    </Style>
  </Canvas.Resources>

   <Rectangle Canvas.Top="60" Fill="Red" />
   <Rectangle Canvas.Top="120" Fill="Green" />
   <Rectangle Fill="Blue" />
</Canvas>
Este programa desenha 3 retângulos que tem seu tamanho alterado quando passamos o mouse sob eles. A coisa acontece da seguinte forma:

O Tag <Style TargetType="{x:Type Rectangle}"> define o "estilo" dos objetos do tipo retângulo que ficarão dentro desse canvas. Basicamente este estilo compões propriedades simples, como width e Height mas contém também Triggers.

Um Trigger é um manipulador para os eventos dos objetos do Presentation Foundation. Quando um estilo contém um tag tipo <EventTrigger RoutedEvent="Rectangle.MouseEnter"> estamos dizendo que queremos que os <Actions> sejam executados quando o evento desejado (MouseEnter) acontecer. Nesse caso ativamos alguns elementos de animação ao objeto (isso é tema de outro arquivo).

Mas eu não posso chamar algum código meu, tipo o Code-Behind em ASP.NET? Claro que pode, mas isso também fica para um próximo artigo. Aguarde.

Veja na figura 3 como esse programa aparece no XAMLPAD.


Figura 3 - Usando eventos

Então eu posso mudar a aparência default de elementos XAML?

O XAML tem um suporte excelente para aplicação de estilos diferentes em seus componentes. Todos os elementos XAML têm sua própria árvore visual que é usada para classificar aquele componente em particular. Se você acha que a aparência default do componente como um botão não é apropriado para você, você pode mudá-lo usando Estilos. Os Estilos no XAML são parecidos com o CSS no HTML. Mas o suporte do XAML para os estilos é muito mais poderoso que o oferecido no CSS.

Por exemplo, eu posso estabelecer um evento no TextBox, através da propriedade IsFowsed. As propriedades que você estabeleceu através dos estilos têm seus efeitos por um tempo limitado de período. No exemplo anterior se você estabeleceu a propriedade Isfowsed como true no TexBox então sempre que o TexBox for focalizado, o comportamento que você definiu no estilo para aquela propriedade, será aplicada e tão logo a propriedade se torne false aquele comportamento não será aplicado. Tudo isto você pode fazer os estilos XAML sem escrever uma única linha do código.

Antes de mergulhar no rio do código eu gostaria de dizer uma coisa mais sobre os estilos XAML. Os estilos XAML são objetos reusáveis e você pode usá-los sempre que queira. Na realidade eles são recursos dentro do documento XAML, e são definidos na propriedade <Resources> de um Painel.

Continuemos com nosso exemplo de login. Vamos aplicar estilos nas caixas de texto que nós usamos para o nome de usuário e senha. Vamos também capturar um evento no estilo caixa de texto para que quando a caixa de texto esteja focada sua borde se torne vermelha e dentro da caixa fique cor de rosa e quando ela perder o foco volte para sua cor default.

Como não atribuímos nenhum nome a este estilo ele será então o estilo default para todos os elementos deste canvas. Os elementos do TexBox terão duas propriedades default do estilo modificadas, BorderBrush e Background. Você usa a propriedade Triggers do elemento Style para definir eventos que ocorrerão quando o valor de certa propriedade for verdadeiro. Veja a listagem 6:

Listagem 6 - Usando estilos e eventos

<Canvas xmlns="http://schemas.microsoft.com/winfx/avalon/2005" 
	xmlns:Avalon="http://schemas.microsoft.com/winfx/xaml/2005"	Background="LightGray">
	<Canvas.Resources>
	<Style TargetType="{Avalon:Type TextBox}">
	      <Style.Triggers>          			        
			<Trigger Property="TextBox.IsFocused" Value="true">
				<Setter Property="BorderBrush" Value ="Red"></Setter>
				<Setter Property = "Background" Value="Pink"/>
			</Trigger>
      		</Style.Triggers>
	</Style>
	
	</Canvas.Resources>

	<TextBlock Canvas.Left="33" Canvas.Top="30" Width="61" Height="14">
        Login
</TextBlock >
       <TextBox Name="txtName" Canvas.Left="80" Canvas.Top="23" />
      	<TextBlock Canvas.Left="33" Canvas.Top="57">Senha</TextBlock >
      	<TextBox Name="txtPassword" Canvas.Left="80" Canvas.Top="53" Height="24"/>
      	<Button Name="btnLogin" Canvas.Left="194" Canvas.Top="82" >Login</Button>
</Canvas>

O elemento < Trigger> é usado para definir o evento. Ele tem um atributo denominado Property que contém o nome do evento. Ele tem outro atributo denominado Value que contém o valor para indicar quando este evento ocorrerá. Este código tem outro elemento denominado <Setter>, este elemento é usado para estabelecer o valor da propriedade Border Brush em "Red".


Figura 4 - O login com estilos

Conclusão

Esta é uma introdução muito simples do XAML, onde eu procurei focar mais na teoria e nas vantagens de se ter uma linguagem para a descrição de interfaces gráficas. Eu escreverei artigos mais detalhados sobre tópicos específicos como Panels, Controles, Estilos e Animações. Já no próximo artigo iremos usar o Visual Studio 2005 para fazer coisas ainda mais interessantes. Até lá!

José Antonio Leal de Farias

José Antonio Leal de Farias - Bacharel em ciências da computação pela UFCG e atualmente é Gerente de Pesquisa e Desenvolvimento da Light Infocon S.A. É programador profissional nas linguagens C++ e C#, líder do grupo de usuários CGSharp e adora Smartphones!
Veja seu blog em
http://thespoke.net/blogs/jalf/default.aspx.