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, 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 o Visual Studio ou o 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 Iniciar, clique em Criar um novo projeto para criar um novo projeto:
Na janela Criar um novo projeto, selecione Móvel na lista suspensa 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 de plataforma cruzada, 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 , convém 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 XamlSamples .NET Standard compartilhado é onde você gastará praticamente todo o seu tempo de programação. Esses artigos não vão se aventurar fora desse projeto.
Anatomia de um arquivo XAML
Dentro da biblioteca XamlSamples .NET Standard há um par de arquivos com os seguintes nomes:
- App.xaml, o arquivo XAML;
- 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;
- MainPage.xaml.cs, o arquivo code-behind do 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 do Xamarin e a segunda no da Microsoft. Não se preocupe em verificar o que esses URIs apontam. Não tem nada lá. Eles são simplesmente URIs de propriedade do Xamarin e da Microsoft, e basicamente funcionam 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 define um prefixo de x
. Isso é usado para vários elementos e atributos que são intrínsecos ao próprio XAML e que são suportados por outras implementações de XAML. No entanto, esses elementos e atributos são ligeiramente diferentes dependendo do ano incorporado no URI. Xamarin.Forms oferece suporte à especificação XAML de 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 x
prefixo é praticamente universal para o namespace XAML, atributos XAML como Class
são quase sempre chamados de x:Class
.
O x:Class
atributo especifica um nome de classe .NET totalmente qualificado: a MainPage
classe no XamlSamples
namespace. Isso significa que esse arquivo XAML define uma nova classe nomeada MainPage
no XamlSamples
namespace que deriva de ContentPage
—a marca na qual o x:Class
atributo aparece.
O x:Class
atributo 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 tem esta aparência (além das 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 partial
definição de ContentPage
classe. Isso sugere que deveria haver outra definição de classe parcial para MainPage
, mas onde está? E que método é esse InitializeComponent
?
Quando o Visual Studio cria 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 InitializeComponent
definição do método chamado do MainPage
construtor. Essas duas definições parciais MainPage
de classe podem então ser compiladas juntas. Dependendo se o XAML é compilado ou não, o arquivo XAML ou uma forma binária do arquivo XAML é incorporado 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 .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 tempo de execução são geradas no código nos arquivos gerados, então você deve estar familiarizado com eles.
Quando você compila e executa esse programa, o Label
elemento aparece no centro da página como o XAML sugere:
Para visuais mais interessantes, tudo o que você precisa é de 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 ItensXamarin.Forms>> do Visual C# (não Página de Conteúdo (C#), que cria uma página somente de 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.
Definindo 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 no XML.
As ContentPage.Content
tags são chamadas de tags de elemento de propriedade. Content
é uma propriedade de , e geralmente é definida como um único modo de exibição ou um layout com modos de ContentPage
exibição filho. 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 marca 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 e Text
são do tipo String
, Rotation
é do tipo Double
, e IsVisible
(que é true
por padrão e é definido aqui apenas para ilustração) é do tipo Boolean
.Title
A HorizontalTextAlignment
propriedade é 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.
Para propriedades de tipos mais complexos, no entanto, os conversores são usados para analisar o XAML. Estas são classes em Xamarin.Forms que derivam de TypeConverter
. Muitas são classes 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.
O ThicknessTypeConverter
pode 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 de campos estáticos públicos da LayoutOptions
estrutura em valores do tipo LayoutOptions
.
O FontSizeConverter
pode manipular um NamedSize
membro ou um tamanho de fonte numérico.
O ColorTypeConverter
aceita os nomes de campos estáticos públicos da Color
estrutura ou valores RGB hexadecimais, com ou sem um canal alfa, precedidos por um sinal numérico (#). Aqui está a sintaxe sem um canal alfa:
TextColor="#rrggbb"
Cada uma das letras pequenas é um dígito hexadecimal. Veja como um canal alfa é incluído:
TextColor="#aarrggbb">
Para o canal alfa, tenha em mente que FF é totalmente opaco e 00 é totalmente transparente.
Dois outros formatos permitem especificar 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 para a nova página a partir do 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 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;
}
A definição Content
da propriedade da página substitui a configuração da Content
propriedade no arquivo XAML. Quando você compila e implanta a nova versão deste programa, um botão aparece na tela. Pressionando-o navega até HelloXamlPage
. Aqui está a página resultante no iPhone, Android e UWP:
Você pode voltar a 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
. Se você precisar incorporar caracteres Unicode no texto, poderá usar a sintaxe XML padrão. Por exemplo, para colocar a saudação entre aspas inteligentes, use:
<Label Text="“Hello, XAML!”" … />
Veja como fica:
Interações XAML e de 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
arquivo . A Children
propriedade do é definida como sendo do tipoIList<View>
, mas na verdade é um objeto do tipo ElementCollection<View>
, e essa coleção pode ser preenchida com vários modos de StackLayout
exibição 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 é sintaticamente completo e aqui está sua aparência:
No entanto, é provável que você considere este programa para ser funcionalmente deficiente. Talvez o Slider
é suposto fazer com que o Label
para exibir o valor atual, e o Button
é provavelmente destinado a fazer algo dentro do programa.
Como você verá na Parte 4. Noções básicas de vinculaçã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 Button
clique 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 Slider
marcas e Button
precisam incluir atributos para os ValueChanged
eventos 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
estará usando o para exibir o Label
valor atual, o manipulador precisará fazer referência a esse objeto a partir do código. O Label
precisa de um nome, que é especificado com o atributo x:Name
.
<Label x:Name="valueLabel"
Text="A simple Label"
Font="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
O x
prefixo x:Name
do atributo indica que esse atributo é intrínseco ao XAML.
O nome atribuído ao atributo tem as mesmas regras que os x:Name
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 poderia obter o Slider
objeto que está gerando esse evento a sender
partir do argumento e obter a Value
propriedade a partir disso:
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 acionado. 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 of. O manipulador de eventos pode converter com segurança o sender
argumento para um 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 com o await
operador, que retorna quando o método é concluído. Como esse método obtém o Button
disparo do evento do sender
argumento, 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 após a análise do XAML. 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 elementos 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 "andar na árvore" examinando a Content
propriedade da página e os Children
itens nas coleções de layouts. Você pode definir propriedades em modos de exibição acessados dessa maneira ou atribuir manipuladores de eventos a eles dinamicamente.
Fique à 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 os arquivos XAML e 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.