Partilhar via


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:

Janela Nova solução

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:

Janela Novo projeto

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:

Caixa de diálogo Novo aplicativo

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 ContentPagepartial 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:

Exibição padrão Xamarin.Forms

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:

Caixa de diálogo Adicionar novo item

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 a VerticalOptions propriedade
  • FontSizeConverter para a FontSize propriedade
  • ColorTypeConverter para a TextColor 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.

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:

Texto do rótulo girado

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 Labelarquivo . 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="&#x201C;Hello, XAML!&#x201D;" … />

Esta é a aparência dele:

Texto de rótulo girado com caracteres Unicode

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:

Vários controles em uma página

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:

Valor do controle deslizante 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.