Share 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, 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:

Janela Nova Solução

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:

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 de plataforma cruzada, 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 , 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 ContentPageclasse. 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:

Exibição padrão Xamarin.Forms

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:

Caixa de diálogo Adicionar Novo Item

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

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:

Texto de rótulo girado

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

Veja como fica:

Texto de rótulo girado com caracteres Unicode

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 StackLayoutarquivo . 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:

Vários controles em uma página

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:

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 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.