Parte 1. Introdução ao XAML
Em um Xamarin.Forms aplicativo, o XAML é usado principalmente para definir o conteúdo visual de uma página e funciona em conjunto com um arquivo code-behind C#.
O arquivo code-behind fornece suporte de código para a marcação. Juntos, esses dois arquivos contribuem para uma nova definição de classe que inclui exibições filho e inicialização de propriedade. No arquivo XAML, as classes e propriedades são referenciadas com elementos e atributos XML, e os links entre a marcação e o código são estabelecidos.
Criando a solução
Para começar a editar seu primeiro arquivo XAML, use Visual Studio ou Visual Studio para Mac para criar uma nova Xamarin.Forms solução. (Selecione a guia abaixo correspondente ao seu ambiente.)
No Windows, inicie o Visual Studio 2019 e, na janela inicial, clique em Criar um novo projeto para criar um novo projeto:
Na janela Criar um novo projeto, selecione Móvel no menu suspenso Tipo de projeto, selecione o modelo Aplicativo móvel (Xamarin.Forms) e clique no botão Avançar:
Na janela Configurar seu novo projeto, defina o Nome do projeto como XamlSamples (ou o que preferir) e clique no botão Criar.
Na caixa de diálogo Novo aplicativo multiplataforma, clique em Em branco e clique no botão OK:
Quatro projetos são criados na solução: a biblioteca XamlSamples .NET Standard, XamlSamples.Android, XamlSamples.iOS e a solução da Plataforma Universal do Windows, XamlSamples.UWP.
Depois de criar a solução XamlSamples , talvez você queira testar seu ambiente de desenvolvimento selecionando os vários projetos de plataforma como o projeto de inicialização da solução e criando e implantando o aplicativo simples criado pelo modelo de projeto em emuladores de telefone ou dispositivos reais.
A menos que você precise escrever código específico da plataforma, o projeto de biblioteca compartilhada XamlSamples .NET Standard é onde você gastará praticamente todo o seu tempo de programação. Esses artigos não se aventurarão fora desse projeto.
Anatomia de um arquivo XAML
Na biblioteca XamlSamples do .NET Standard há um par de arquivos com os seguintes nomes:
- App.xaml, o arquivo XAML; e
- App.xaml.cs, um arquivo code-behind C# associado ao arquivo XAML.
Você precisará clicar na seta ao lado de App.xaml para ver o arquivo code-behind.
App.xaml e App.xaml.cs contribuem para uma classe chamada App
que deriva de Application
. A maioria das outras classes com arquivos XAML contribui para uma classe que deriva de ContentPage
; esses arquivos usam XAML para definir o conteúdo visual de uma página inteira. Isso é verdadeiro para os outros dois arquivos no projeto XamlSamples :
- MainPage.xaml, o arquivo XAML; e
- MainPage.xaml.cs, o arquivo code-behind C#.
O arquivo MainPage.xaml tem esta aparência (embora a formatação possa ser um pouco diferente):
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamlSamples"
x:Class="XamlSamples.MainPage">
<StackLayout>
<!-- Place new controls here -->
<Label Text="Welcome to Xamarin Forms!"
VerticalOptions="Center"
HorizontalOptions="Center" />
</StackLayout>
</ContentPage>
As duas declarações de namespace XML (xmlns
) referem-se a URIs, a primeira aparentemente no site da Xamarin e a segunda no da Microsoft. Não se preocupe em verificar o que esses URIs apontam. Não há nada lá. Eles são simplesmente URIs de propriedade do Xamarin e da Microsoft e funcionam basicamente como identificadores de versão.
A primeira declaração de namespace XML significa que as marcas definidas no arquivo XAML sem prefixo se referem a classes em Xamarin.Forms, por exemplo ContentPage
, . A segunda declaração de namespace usa o prefixo x
. Ele é usado para vários elementos e atributos que são intrínsecos ao próprio XAML e que são aceitos por outras implementações de XAML. No entanto, esses elementos e atributos são um pouco diferentes dependendo do ano inserido no URI. Xamarin.Forms dá suporte à especificação XAML 2009, mas não a toda.
A local
declaração de namespace permite que você acesse outras classes do projeto de biblioteca do .NET Standard.
No final dessa primeira tag, o prefixo x
é usado para um atributo chamado Class
. Como o uso desse prefixo x
é praticamente universal para o namespace XAML, os atributos XAML, como Class
, são quase sempre chamados de x:Class
.
O atributo x:Class
especifica um nome de classe .NET totalmente qualificado: a classe MainPage
no namespace XamlSamples
. Isso significa que esse arquivo XAML define uma nova classe nomeada MainPage
no namespace que deriva XamlSamples
de ContentPage
—a marca na qual o x:Class
atributo aparece.
O atributo x:Class
só pode aparecer no elemento raiz de um arquivo XAML para definir uma classe C# derivada. Essa é a única nova classe definida no arquivo XAML. Todo o resto que aparece no arquivo XAML é simplesmente instanciado a partir de classes existentes e inicializado.
O arquivo MainPage.xaml.cs se parece com isso (além de diretivas não utilizadas using
):
using Xamarin.Forms;
namespace XamlSamples
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
}
}
A MainPage
classe deriva de , mas observe a definição de ContentPage
partial
classe. Isso sugere que deve haver outra definição de classe parcial para MainPage
, mas onde está? E qual é esse InitializeComponent
método?
Quando o Visual Studio compila o projeto, ele analisa o arquivo XAML para gerar um arquivo de código C#. Se você procurar no diretório XamlSamples\XamlSamples\obj\Debug , encontrará um arquivo chamado XamlSamples.MainPage.xaml.g.cs. O 'g' significa gerado. Esta é a outra definição de classe parcial que MainPage
contém a definição do InitializeComponent
método chamado do MainPage
construtor. Essas duas definições parciais MainPage
de classe podem ser compiladas juntas. Dependendo se o XAML é compilado ou não, o arquivo XAML ou uma forma binária do arquivo XAML é inserido no executável.
Em tempo de execução, o código no projeto de plataforma específico chama um LoadApplication
método, passando para ele uma nova instância da App
classe na biblioteca do .NET Standard. O App
construtor de classe instancia MainPage
. O construtor dessa classe chama InitializeComponent
, que chama o LoadFromXaml
método que extrai o arquivo XAML (ou seu binário compilado) da biblioteca do .NET Standard. LoadFromXaml
inicializa todos os objetos definidos no arquivo XAML, conecta-os todos juntos em relações pai-filho, anexa manipuladores de eventos definidos no código a eventos definidos no arquivo XAML e define a árvore resultante de objetos como o conteúdo da página.
Embora você normalmente não precise gastar muito tempo com arquivos de código gerados, às vezes exceções de runtime são geradas no código nos arquivos gerados, portanto, você deve estar familiarizado com elas.
Quando você compila e executa esse programa, o Label
elemento aparece no centro da página, conforme sugerido pelo XAML:
Para visuais mais interessantes, tudo o que você precisa é de um XAML mais interessante.
Adicionando novas páginas XAML
Para adicionar outras classes baseadas em ContentPage
XAML ao seu projeto, selecione o projeto de biblioteca XamlSamples .NET Standard, clique com o botão direito do mouse e selecione Adicionar > Novo Item.... Na caixa de diálogo Adicionar Novo Item, selecione Página de Conteúdo de Itens do>Xamarin.Forms> Visual C# (não Página de Conteúdo (C#), que cria uma página somente código, ou Modo de Exibição de Conteúdo, que não é uma página). Dê um nome à página, por exemplo, HelloXamlPage:
Dois arquivos são adicionados ao projeto, HelloXamlPage.xaml e o arquivo code-behind HelloXamlPage.xaml.cs.
Configurando o conteúdo da página
Edite o arquivo HelloXamlPage.xaml para que as únicas marcas sejam as de ContentPage
e ContentPage.Content
:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.HelloXamlPage">
<ContentPage.Content>
</ContentPage.Content>
</ContentPage>
As ContentPage.Content
marcas fazem parte da sintaxe exclusiva do XAML. A princípio, eles podem parecer XML inválidos, mas são legais. O ponto não é um caractere especial em XML.
As ContentPage.Content
tags são chamadas de tags de elemento de propriedade. Content
é uma propriedade de ContentPage
, e geralmente é definido como uma única exibição ou um layout com exibições secundárias. Normalmente, as propriedades se tornam atributos em XAML, mas seria difícil definir um Content
atributo para um objeto complexo. Por esse motivo, a propriedade é expressa como um elemento XML que consiste no nome da classe e no nome da propriedade separados por um ponto. Agora a Content
propriedade pode ser definida entre as ContentPage.Content
tags, assim:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.HelloXamlPage"
Title="Hello XAML Page">
<ContentPage.Content>
<Label Text="Hello, XAML!"
VerticalOptions="Center"
HorizontalTextAlignment="Center"
Rotation="-15"
IsVisible="true"
FontSize="Large"
FontAttributes="Bold"
TextColor="Blue" />
</ContentPage.Content>
</ContentPage>
Observe também que um Title
atributo foi definido na tag raiz.
Neste momento, a relação entre classes, propriedades e XML deve ser evidente: uma Xamarin.Forms classe (como ContentPage
ou Label
) aparece no arquivo XAML como um elemento XML. As propriedades dessa classe, incluindo Title
on ContentPage
e sete propriedades de Label
, geralmente 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 and Text
são do tipo String
, Rotation
is do tipo Double
, e IsVisible
(que é true
por padrão e é definido aqui apenas para ilustração) is do tipo Boolean
.Title
A propriedade HorizontalTextAlignment
é do tipo TextAlignment
, que é uma enumeração. Para uma propriedade de qualquer tipo de enumeração, tudo o que você precisa fornecer é um nome de membro.
No entanto, para propriedades de tipos mais complexos, os conversores são usados para analisar o XAML. Estas são classes que Xamarin.Forms derivam de TypeConverter
. Muitas são aulas públicas, mas outras não. Para esse arquivo XAML específico, várias dessas classes desempenham um papel nos bastidores:
LayoutOptionsConverter
para aVerticalOptions
propriedadeFontSizeConverter
para aFontSize
propriedadeColorTypeConverter
para aTextColor
propriedade
Esses conversores controlam a sintaxe permitida das configurações de propriedade.
Eles ThicknessTypeConverter
podem lidar com um, dois ou quatro números separados por vírgulas. Se um número for fornecido, ele se aplica a todos os quatro lados. Com dois números, o primeiro é o preenchimento esquerdo e direito e o segundo é superior e inferior. Quatro números estão na ordem esquerda, superior, direita e inferior.
O LayoutOptionsConverter
pode converter os nomes dos campos estáticos públicos da LayoutOptions
estrutura em valores do tipo LayoutOptions
.
O FontSizeConverter
pode lidar com um NamedSize
membro ou um tamanho de fonte numérico.
O aceita ColorTypeConverter
os nomes dos campos estáticos públicos da Color
estrutura ou valores RGB hexadecimais, com ou sem canal alfa, precedidos por um sinal numérico (#). Aqui está a sintaxe sem um canal alfa:
TextColor="#rrggbb"
Cada uma das letras minúsculas é um dígito hexadecimal. Veja como um canal alfa é incluído:
TextColor="#aarrggbb">
Para o canal alfa, lembre-se de que FF é totalmente opaco e 00 é totalmente transparente.
Dois outros formatos permitem que você especifique apenas um único dígito hexadecimal para cada canal:
TextColor="#rgb"
TextColor="#argb"
Nesses casos, o dígito é repetido para formar o valor. Por exemplo, #CF3 é a cor RGB CC-FF-33.
Navegação de Página
Quando você executa o programa XamlSamples , o MainPage
é exibido. Para ver o novo HelloXamlPage
, você pode defini-lo como a nova página de inicialização no arquivo App.xaml.cs ou navegar até a nova página a partir de MainPage
.
Para implementar a navegação, primeiro altere o código no construtor App.xaml.cs para que um NavigationPage
objeto seja criado:
public App()
{
InitializeComponent();
MainPage = new NavigationPage(new MainPage());
}
No construtor MainPage.xaml.cs, você pode criar um construtor simples Button
e usar o manipulador de eventos para navegar até HelloXamlPage
:
public MainPage()
{
InitializeComponent();
Button button = new Button
{
Text = "Navigate!",
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center
};
button.Clicked += async (sender, args) =>
{
await Navigation.PushAsync(new HelloXamlPage());
};
Content = button;
}
Definir a Content
propriedade da página substitui a Content
configuração da propriedade no arquivo XAML. Quando você compila e implanta a nova versão deste programa, um botão aparece na tela. Pressioná-lo navega até HelloXamlPage
. Aqui está a página resultante no iPhone, Android e UWP:
Você pode navegar de volta para MainPage
usar o < botão Voltar no iOS, usando a seta para a esquerda na parte superior da página ou na parte inferior do telefone no Android ou usando a seta para a esquerda na parte superior da página no Windows 10.
Sinta-se à vontade para experimentar o XAML para diferentes maneiras de renderizar o Label
arquivo . Se você precisar inserir qualquer caractere Unicode no texto, poderá usar a sintaxe XML padrão. Por exemplo, para colocar a saudação entre aspas inglesas, use:
<Label Text="“Hello, XAML!”" … />
Esta é a aparência dele:
Interações XAML e código
O exemplo HelloXamlPage contém apenas um único Label
na página, mas isso é muito incomum. A maioria dos ContentPage
derivados define a Content
propriedade como um layout de algum tipo, como um StackLayout
. A Children
propriedade do StackLayout
é definida como do tipo IList<View>
, mas na verdade é um objeto do tipo ElementCollection<View>
, e essa coleção pode ser preenchida com várias exibições ou outros layouts. Em XAML, essas relações pai-filho são estabelecidas com hierarquia XML normal. Aqui está um arquivo XAML para uma nova página chamada XamlPlusCodePage:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.XamlPlusCodePage"
Title="XAML + Code Page">
<StackLayout>
<Slider VerticalOptions="CenterAndExpand" />
<Label Text="A simple Label"
Font="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Button Text="Click Me!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
Esse arquivo XAML está sintaticamente completo e aqui está o que ele parece:
No entanto, é provável que você considere este programa funcionalmente deficiente. Talvez o Slider
deva fazer com que o Label
exiba o valor atual, e provavelmente Button
se destina a fazer algo dentro do programa.
Como você verá na Parte 4. Noções básicas de associação de dados, o trabalho de exibir um Slider
valor usando um Label
pode ser tratado inteiramente em XAML com uma associação de dados. Mas é útil ver a solução de código primeiro. Mesmo assim, lidar com o clique Button
definitivamente requer código. Isso significa que o arquivo code-behind para XamlPlusCodePage
deve conter manipuladores para o ValueChanged
evento do Slider
e o Clicked
evento do Button
. Vamos adicioná-los:
namespace XamlSamples
{
public partial class XamlPlusCodePage
{
public XamlPlusCodePage()
{
InitializeComponent();
}
void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
{
}
void OnButtonClicked(object sender, EventArgs args)
{
}
}
}
Esses manipuladores de eventos não precisam ser públicos.
De volta ao arquivo XAML, as marcas Slider
e Button
precisam incluir atributos para os eventos ValueChanged
e Clicked
que fazem referência a esses manipuladores:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.XamlPlusCodePage"
Title="XAML + Code Page">
<StackLayout>
<Slider VerticalOptions="CenterAndExpand"
ValueChanged="OnSliderValueChanged" />
<Label Text="A simple Label"
Font="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Button Text="Click Me!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Clicked="OnButtonClicked" />
</StackLayout>
</ContentPage>
Observe que atribuir um manipulador a um evento tem a mesma sintaxe que atribuir um valor a uma propriedade.
Se o manipulador para o ValueChanged
evento do Slider
estiver usando o Label
para exibir o valor atual, o manipulador precisará fazer referência a esse objeto do código. O Label
precisa de um nome, que é especificado com o x:Name
atributo.
<Label x:Name="valueLabel"
Text="A simple Label"
Font="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
O prefixo x
do atributo x:Name
indica que esse atributo é intrínseco ao XAML.
O nome que você atribui ao atributo x:Name
tem as mesmas regras que os nomes de variáveis C#. Por exemplo, ele deve começar com uma letra ou sublinhado e não conter espaços incorporados.
Agora, o ValueChanged
manipulador de eventos pode definir o Label
para exibir o novo Slider
valor. O novo valor está disponível nos argumentos do evento:
void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
{
valueLabel.Text = args.NewValue.ToString("F3");
}
Ou o manipulador pode obter o Slider
objeto que está gerando esse evento do sender
argumento e obter a Value
propriedade dele:
void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
{
valueLabel.Text = ((Slider)sender).Value.ToString("F3");
}
Quando você executa o programa pela primeira vez, o Label
não exibe o Slider
valor porque o ValueChanged
evento ainda não foi disparado. Mas qualquer manipulação do Slider
faz com que o valor seja exibido:
Agora, para o Button
. Vamos simular uma resposta a um Clicked
evento exibindo um alerta com o Text
botão do botão. O manipulador de eventos pode converter o sender
argumento com segurança em a Button
e, em seguida, acessar suas propriedades:
async void OnButtonClicked(object sender, EventArgs args)
{
Button button = (Button)sender;
await DisplayAlert("Clicked!",
"The button labeled '" + button.Text + "' has been clicked",
"OK");
}
O método é definido como async
porque o método é assíncrono DisplayAlert
e deve ser precedido await
pelo operador, que retorna quando o método é concluído. Como esse método obtém o acionamento Button
do evento do argumento sender
, o mesmo manipulador pode ser usado para vários botões.
Você viu que um objeto definido em XAML pode disparar um evento que é manipulado no arquivo code-behind e que o arquivo code-behind pode acessar um objeto definido em XAML usando o nome atribuído a ele com o x:Name
atributo. Essas são as duas maneiras fundamentais pelas quais o código e o XAML interagem.
Alguns insights adicionais sobre como o XAML funciona podem ser obtidos examinando o arquivo XamlPlusCode.xaml.g.cs recém-gerado, que agora inclui qualquer nome atribuído a qualquer x:Name
atributo como um campo privado. Aqui está uma versão simplificada desse arquivo:
public partial class XamlPlusCodePage : ContentPage {
private Label valueLabel;
private void InitializeComponent() {
this.LoadFromXaml(typeof(XamlPlusCodePage));
valueLabel = this.FindByName<Label>("valueLabel");
}
}
A declaração deste campo permite que a variável seja usada livremente em qualquer lugar dentro do XamlPlusCodePage
arquivo de classe parcial sob sua jurisdição. Em tempo de execução, o campo é atribuído depois que o XAML é analisado. Isso significa que o valueLabel
campo é null
quando o construtor começa, XamlPlusCodePage
mas válido depois InitializeComponent
é chamado.
Depois InitializeComponent
de retornar o controle de volta ao construtor, os visuais da página foram construídos como se tivessem sido instanciados e inicializados no código. O arquivo XAML não desempenha mais nenhuma função na classe. Você pode manipular esses objetos na página da maneira que desejar, por exemplo, adicionando modos de exibição ao StackLayout
, ou definindo a Content
propriedade da página como algo totalmente diferente. Você pode "percorrer a árvore" examinando a Content
propriedade da página e os itens nas Children
coleções de layouts. Você pode definir propriedades em exibições acessadas dessa maneira ou atribuir manipuladores de eventos a elas dinamicamente.
Sinta-se à vontade. É sua página e o XAML é apenas uma ferramenta para criar seu conteúdo.
Resumo
Com esta introdução, você viu como um arquivo XAML e um arquivo de código contribuem para uma definição de classe e como o XAML e os arquivos de código interagem. Mas o XAML também tem seus próprios recursos sintáticos exclusivos que permitem que ele seja usado de maneira muito flexível. Você pode começar a explorá-los na Parte 2. Sintaxe XAML essencial.