Você está na página 1de 1651

Contents

Xamarin.Forms
Introdução
Requisitos
Instalação
Criar seu primeiro aplicativo
Início rápido de página única
Início rápido de várias páginas
Início rápido do banco de dados local
Início rápido de estilos
Aprofundamento
XAML
Controles XAML
Noções básicas de XAML
Parte 1. Introdução ao XAML
Parte 2. Sintaxe essencial do XAML
Parte 3. Extensões de marcação do XAML
Parte 4. Conceitos básicos da associação de dados
Parte 5. De associações de dados a MVVM
Compilação de XAML
Caixa de ferramentas do XAML
Visualizador do XAML
Dados do tempo de design
Controles personalizados
Namespaces XAML
Esquemas personalizados de namespace do XAML
Prefixos recomendados de namespace do XAML
Extensões de marcação do XAML
Consumo de extensões de marcação do XAML
Criação de extensões de marcação do XAML
Modificadores de campo
Passando argumentos
Propriedades associáveis
Propriedades anexadas
Dicionários de recurso
XAML Standard (Versão prévia)
Controles
Carregar XAML em tempo de execução
Conceitos básicos de aplicativo
Acessibilidade
Propriedades de automação
Navegação por teclado
Classe de aplicativo
Ciclo de vida do aplicativo
Indexação de aplicativo e vinculação profunda
Comportamentos
Introdução
Comportamentos anexados
Comportamentos do Xamarin.Forms
Comportamentos reutilizáveis
EffectBehavior
EventToCommandBehavior
Renderizadores personalizados
Introdução
Classes base de renderizador e controles nativos
Personalizando uma entrada
Personalizando uma ContentPage
Personalizando um mapa
Personalizando um marcador de mapa
Realçando uma área circular em um mapa
Realçando uma região em um mapa
Realçando uma rota em um mapa
Personalizando uma ListView
Personalizando um ViewCell
Implementando uma exibição
Implementando um HybridWebView
Implementando um player de vídeo
Criando os players de vídeo da plataforma
Reproduzindo um vídeo da Web
Associando fontes de vídeo ao player
Carregando vídeos de recursos do aplicativo
Acessando a biblioteca de vídeos do dispositivo
Controles de transporte de vídeo personalizado
Posicionamento de vídeo personalizado
Associação de dados
Associações básicas
Modo de associação
Formação de cadeia de caracteres
Caminho de associação
Associação de conversores de valor
Associação de fallbacks
A interface de comando
Associações compiladas
DependencyService
Introdução
Implementando a conversão de texto em fala
Verificando a orientação do dispositivo
Verificando o status da bateria
Selecionando da biblioteca de fotos
Efeitos
Introdução
Criação de efeitos
Passar parâmetros
Parâmetros como propriedades CLR
Parâmetros como propriedades anexadas
Invocação de eventos
Arquivos
Gestos
Toque
Fixar
Panorâmica
Passar o dedo
Localização
Localização de cadeias de caracteres e imagens
Localização da direita para a esquerda
Bancos de dados locais
MessagingCenter
Navegação
Navegação hierárquica
TabbedPage
CarouselPage
MasterDetailPage
Páginas modais
Exibindo pop-ups
Shell
Modelos
Modelos de controle
Introdução
Criação do modelo de controle
Associações de modelo
Modelos de dados
Introdução
Criação de modelo de dados
Seleção de modelo de dados
Gatilhos
Interface do Usuário
Animação
Animação
Animações simples
Funções de easing
Animações personalizadas
BoxView
Botão
CollectionView
Dados
Layout
Seleção
EmptyView
Rolagem
Cores
Referência de Controles
Pages (Páginas)
Layouts
Exibições
Células
DataPages
Introdução
Referência de Controles
DatePicker
Elementos gráficos com SkiaSharp
Imagens
ImageButton
Layouts
StackLayout
AbsoluteLayout
RelativeLayout
Grade
FlexLayout
ScrollView
LayoutOptions
Margem e preenchimento
Orientação do dispositivo
Tablet e desktop
Layouts associáveis
Criando um layout personalizado
Compactação de Layout
ListView
Data Sources
Aparência de célula
Aparência de lista
Interatividade
Desempenho
Mapas
Seletor
Definir a propriedade ItemsSource de um seletor
Adicionar dados à coleção de itens do seletor
Controle deslizante
Passador
Estilos
Aplicar estilo a aplicativos do Xamarin.Forms usando os estilos do XAML
Introdução
Estilos explícitos
Estilos implícitos
Estilos globais
Herança de estilo
Estilos dinâmicos
Estilos de dispositivo
Classes de estilos
Aplicar estilo a aplicativos do Xamarin.Forms usando as CSS (folhas de estilos em
cascata)
TableView
Texto
Rotular
Entrada
Editor
Fontes
Estilos
Temas
Tema claro
Tema escuro
Criar um tópico personalizado
TimePicker
Visual
Visual material
Criar um renderizador visual
Gerenciador de Estado Visual
WebView
Recursos da plataforma
Android
AppCompat e Design de material
Botão de sombras e preenchimento
Opções do IME de entrada
Sombras de ImageButton
Rolagem rápida de ListView
Altura da barra de NavigationPage
Eventos de ciclo de vida da página
Modo de entrada do teclado virtual
Passar o dedo na página TabbedPage
Animações de transição da página TabbedPage
Cor e posicionamento da barra de ferramentas TabbedPage
Elevação de VisualElement
Modo de cor herdado de VisualElement
Conteúdo misto de WebView
Classe de dispositivo
iOS
Cor da tela de fundo da célula
Cor do cursor de entrada
Tamanho da fonte de entrada
Formatação
Estilo de apresentação da página modal do iPad
Títulos de página grandes
Estilo do cabeçalho de grupo de ListView
Animações em linha de ListView
Estilo do separador de ListView
Atualizações de controle do thread principal
Separador da barra de NavigationPage
Modo de cor do texto da barra de NavigationPage
Translucência da barra de NavigationPage
Visibilidade da barra de status da página
Seleção de item do seletor
Guia do Layout da Área de Segurança
Toques de conteúdo de ScrollView
Reconhecimento de gesto de panorâmica simultâneo
Toque do elevador de controle deslizante
Desfoque de VisualElement
Sombras de VisualElement
Modo de cor herdado de VisualElement
Formulários nativos
Exibições nativas
Exibições nativas em XAML
Exibições nativas em C#
Outras plataformas
GTK#
Mac
Tizen
WPF
Especificações da plataforma
Windows
Sentido de leitura de InputView
SelectionMode de ListView
Barra de navegação de MasterDetailPage
Posicionamento da barra de ferramentas da página
Instalação da plataforma
Verificação ortográfica de SearchBar
Ícones de TabbedPage
Chaves de acesso de VisualElement
Modo de cor herdado de VisualElement
Alertas do JavaScript de WebView
Xamarin.Essentials
Introdução
Acelerômetro
Informações do aplicativo
Barômetro
Bateria
Área de Transferência
Conversores de cor
Bússola
Conectividade
Detectar movimento
Informações sobre DeviceDisplay
Informações sobre o dispositivo
Email
Auxiliares do sistema de arquivos
Lanterna
Geocódigo
Geolocalização
Giroscópio
Inicializador
Magnetômetro
Thread principal
Mapas
Abrir navegador
Sensor de orientação
Discagem telefônica
Extensões da plataforma (tamanho, retângulo, ponto)
Preferências
Armazenamento seguro
Compartilhar
SMS
Conversão de texto em fala
Conversores de unidade
Monitoramento de versões
Vibrar
Solução de problemas
Serviços de dados e de nuvem
Noções básicas de exemplo
Consumo de serviços Web
ASMX
WCF
REST
Aplicativos móveis do Azure
Autenticar o acesso aos serviços Web
REST
OAuth
Aplicativos móveis do Azure
Azure Active Directory B2C
Integração do Azure Active Directory B2C com Aplicativos Móveis do Azure
Sincronizar dados com Serviços Web
Aplicativos móveis do Azure
Enviar notificações por push
Azure
Armazenar arquivos na nuvem
Armazenamento do Azure
Pesquisar dados na nuvem
Azure Search
Aplicativos sem servidor
Verificação de
Armazenar dados em um banco de dados de documento
Consumo de um banco de dados de documento do Azure Cosmos DB
Autenticar usuários com um banco de dados de documento do Azure Cosmos DB
Adicionar inteligência com Serviços Cognitivos
Reconhecimento de fala
Verificação ortográfica
Tradução de texto
Reconhecimento de emoção
Implantação e Teste
Como publicar aplicativos iOS
Como publicar aplicativos Android
Como publicar aplicativos UWP
Como publicar aplicativos Mac
Desempenho
Testes automatizados no Visual Studio App Center
Conceitos avançados e recursos internos
Resolução de dependência
Renderizadores Rápidos
.NET Standard
Solução de problemas
Perguntas frequentes
Posso atualizar o modelo padrão Xamarin.Forms para um pacote NuGet mais
recente?
Por que o designer XAML do Visual Studio não funciona para arquivos XAML do
Xamarin.Forms?
Erro de build do Android: The "LinkAssemblies" task failed unexpectedly
Por que meu projeto Android Xamarin.Forms.Maps falha com
COMPILETODALVIK: UNEXPECTED TOP-LEVEL ERROR?
Notas sobre a versão
Exemplos
Criação de aplicativos móveis com Xamarin.Forms Book
Livro eletrônico de padrões de aplicativo empresarial
Elementos gráficos de SkiaSharp em Xamarin.Forms
Requisitos do Xamarin.Forms
12/04/2019 • 3 minutes to read • Edit Online

Requisitos de sistema de plataforma e desenvolvimento para Xamarim.Forms.


Consulte o artigo de Instalação para obter uma visão geral da instalação e das práticas recomendadas aplicáveis
entre plataformas.

Plataformas de destino
Aplicativos Xamarin.Forms podem ser gravados para os seguintes sistemas operacionais:
iOS 8 ou superior
Android 4.4 (API 19) ou superior (mais detalhes)
Plataforma Universal do Windows do Windows 10 (mais detalhes)
Presume-se que os desenvolvedores estejam familiarizados com o .NET Standard e com Projetos
Compartilhados.
Suporte adicional da plataforma
O status dessas plataformas está disponível no GitHub do Xamarin.Forms:
Samsung Tizen
macOS
GTK#
WPF
Plataformas de versões anteriores
Não há suporte para uso do Xamarin.Forms 3.0 nas seguintes plataformas:
WinRT do Windows 8.1/Windows Phone 8.1
Windows Phone 8 Silverlight
Android
Você precisa ter a plataforma das Ferramentas do SDK do Android e da API do Android mais recente instalada. É
possível atualizar para as versões mais recentes usando o Gerenciador de SDK do Android.
Além disso, a versão de destino/compilação para projetos do Android deve ser definida como Usar a plataforma
mais recente instalada. No entanto, a versão mínima pode ser definida como API 19, de modo que você pode
continuar dando suporte a dispositivos que usam Android 4.4 e mais recentes. Esses valores são definidos nas
Opções de Projeto:
Visual Studio
Visual Studio para Mac
Opções do projeto > aplicativo > Propriedades do aplicativo
Requisitos do sistema de desenvolvimento
Aplicativos Xamarin.Forms podem ser desenvolvidos no macOS e no Windows. No entanto, o Windows e o
Visual Studio são necessários para produzir versões do Windows do aplicativo.

Requisitos do sistema do Mac


Você pode usar o Visual Studio para Mac para desenvolver aplicativos xamarin. Forms em macOS High Sierra
(10.13) ou mais recente. Para desenvolver aplicativos iOS, é recomendável ter pelo menos o iOS 10 SDK e o
Xcode 9 instalado.

NOTE
Aplicativos do Windows não podem ser desenvolvidos no macOS.

Requisitos do sistema do Windows


Aplicativos Xamarin.Forms para iOS e Android podem ser compilados em qualquer instalação do Windows que
dê suporte a desenvolvimento do Xamarin. É necessário ter o Visual Studio 2017 ou mais recente em execução no
Windows 7 ou superior. Um Mac em rede é necessário para o desenvolvimento do iOS.
UWP (Plataforma Universal do Windows)
O desenvolvimento de aplicativos Xamarin.Forms para UWP requer:
Windows 10 (versão mais recente recomendada, mínimo Fall Creators Update)
Visual Studio de 2019 recomendado (Visual Studio 2017 versão 15,8 mínimo)
Windows 10 SDK
Você pode também adicionar um aplicativo UWP (Plataforma Universal do Windows) a uma solução
Xamarin.Forms existente a qualquer momento.
Instalando o Xamarin
12/04/2019 • 4 minutes to read • Edit Online

Como configurar o Visual Studio e Xamarin para começar a criar aplicativos móveis com o .NET.

Instalando o Xamarin no Windows

Instruções passo a passo


O Xamarin pode ser instalado como parte de um novo instalação do Visual Studio de 2019, com as seguintes
etapas:
1. Baixe o Visual Studio 2019 Community, Visual Studio Professional ou Visual Studio Enterprise na Visual
Studio página (links para download são fornecidos na parte inferior).
2. Clique duas vezes no pacote baixado para iniciar a instalação.
3. Selecione a carga de trabalho Desenvolvimento móvel com .NET na tela de instalação:
[![Mdesenvolvimento de obile com seleção de .NET](~/get-started/installation/windows-images/vs2019-
mobile-dev-workload-sml.png)](~/get-started/installation/windows-images/vs2019-mobile-dev-
workload.png#lightbox)
4. Quando você estiver pronto para começar a instalação do Visual Studio de 2019, clique o instalar botão
no canto inferior direito:

Dependendo de qual edição do Visual Studio de 2019 que você está instalando, o processo de instalação
pode levar muito tempo para ser concluída. Você pode usar as barras de progresso para monitorar a
instalação:

5. Quando a instalação do Visual Studio de 2019 for concluída, clique no inicie botão para iniciar o Visual
Studio:
Adicionando o Xamarin ao Visual Studio de 2019
Se o Visual Studio de 2019 já estiver instalado, adicionar o Xamarin executando novamente o instalador do Visual
Studio de 2019 para modificar as cargas de trabalho (consulte modificar o Visual Studio para obter detalhes). Em
seguida, siga as etapas listadas acima para instalar o Xamarin.
Para obter mais informações sobre como baixar e instalar o Visual Studio de 2019, consulte instalar o Visual
Studio 2019.

Instalando o Xamarin no Windows

Instruções passo a passo


O Xamarin pode ser instalado como parte de uma nova instalação do Visual Studio 2017, com as seguintes
etapas:
1. Baixe o Visual Studio 2017 Community, o Visual Studio Professional ou o Visual Studio Enterprise na
página do Visual Studio (os links para download são fornecidos na parte inferior).
2. Clique duas vezes no pacote baixado para iniciar a instalação.
3. Selecione a carga de trabalho Desenvolvimento móvel com .NET na tela de instalação:

4. Enquanto Desenvolvimento móvel com .NET estiver selecionado, veja o painel Detalhes da
instalação à direita. Nele, é possível anular a seleção das opções de desenvolvimento móvel que você não
deseja instalar.
5. Quando estiver pronto para começar a instalação do Visual Studio 2017, clique no botão Instalar no canto
inferior direito:

Dependendo da edição do Visual Studio 2017 que você estiver instalando, o processo de instalação poderá
levar muito tempo para ser concluído. Você pode usar as barras de progresso para monitorar a instalação:

6. Quando a instalação do Visual Studio 2017 for concluída, clique no botão Iniciar para iniciá-lo:

Adicionando o Xamarin ao Visual Studio 2017


Se o Visual Studio 2017 já está instalado, adicione o Xamarin executando novamente o instalador do Visual
Studio 2017 para modificar as cargas de trabalho (consulte Modificar o Visual Studio para obter detalhes). Em
seguida, siga as etapas listadas acima para instalar o Xamarin.
Para obter mais informações sobre como baixar e instalar o Visual Studio 2017, consulte Instalar o Visual Studio
2017.

Instalando o Xamarin no macOS

Instruções passo a passo


Além deste vídeo, há uma guia de instalação passo a passo que trata do Visual Studio para Mac e Xamarin.

Links relacionados
Desinstalando o Xamarin
Instruções de configuração de firewall do Xamarin
Compilar seu primeiro aplicativo Xamarin.Forms
18/04/2019 • 5 minutes to read • Edit Online

Assista a este vídeo e acompanhe-o para compilar seu primeiro aplicativo móvel com Xamarin.Forms.

Instruções passo a passo para Windows


Baixar o exemplo
Siga estas etapas em conjunto com o vídeo acima:
1. Escolha arquivo > Novo > projeto... ou pressione o criar novo projeto... botão:

2. Pesquise por "Xamarin" ou escolha Mobile da tipo de projeto menu. Selecione o aplicativo móvel
(xamarin. Forms) tipo de projeto:
3. Escolha um nome de projeto – o exemplo usa "AwesomeApp":

4. Clique no em branco tipo de projeto e verifique se Android e iOS estão selecionadas:

5. Aguarde até que os pacotes do NuGet sejam restaurados (a mensagem "Restauração concluída" será
exibida na barra de status).
6. Inicie o Android Emulator pressionando o botão de depuração (ou o item de menu Depurar > Iniciar
Depuração).
7. Edite MainPage.xaml, adicionando este XAML antes do final de </StackLayout> :
<Button Text="Click Me" Clicked="Button_Clicked" />

8. Edite MainPage.xaml.cs, adicionando este código ao final da classe:

int count = 0;
void Button_Clicked(object sender, System.EventArgs e)
{
count++;
((Button)sender).Text = $"You clicked {count} times.";
}

9. Depure o aplicativo no Android:

TIP
É possível compilar e depurar o aplicativo iOS no Visual Studio com um computador Mac em rede. Veja as instruções
de instalação para obter mais informações.

Instruções passo a passo para Windows


Baixar o exemplo
Siga estas etapas em conjunto com o vídeo acima:
1. Escolha Arquivo > Novo > Projeto... ou pressione o botão Criar novo projeto... e, em seguida, selecione
Visual C# > Multiplataforma > Aplicativo Móvel (Xamarin.Forms):
2. Certifique-se de que Android e iOS estejam selecionados, com compartilhamento de código .NET
Standard:

3. Aguarde até que os pacotes do NuGet sejam restaurados (a mensagem "Restauração concluída" será
exibida na barra de status).
4. Inicie o Android Emulator pressionando o botão de depuração (ou o item de menu Depurar > Iniciar
Depuração).
5. Edite MainPage.xaml, adicionando este XAML antes do final de </StackLayout> :

<Button Text="Click Me" Clicked="Button_Clicked" />

6. Edite MainPage.xaml.cs, adicionando este código ao final da classe:

int count = 0;
void Button_Clicked(object sender, System.EventArgs e)
{
count++;
((Button)sender).Text = $"You clicked {count} times.";
}

7. Depure o aplicativo no Android:


TIP
É possível compilar e depurar o aplicativo iOS no Visual Studio com um computador Mac em rede. Veja as instruções
de instalação para obter mais informações.

Instruções passo a passo para Mac


Baixar o exemplo
Siga estas etapas em conjunto com o vídeo acima:
1. Escolha Arquivo > Nova Solução... ou pressione o botão Novo Projeto... e, em seguida, selecione
Multiplataforma > Aplicativo > Aplicativo de Formulários em Branco:

2. Certifique-se de que Android e iOS estejam selecionados, com compartilhamento de código .NET
Standard:
3. Restaure os pacotes do NuGet clicando com o botão direito do mouse na solução:

4. Inicie o Android Emulator pressionando o botão de depuração (ou Executar > Iniciar Depuração).
5. Edite MainPage.xaml, adicionando este XAML antes do final de </StackLayout> :

<Button Text="Click Me" Clicked="Handle_Clicked" />

6. Edite MainPage.xaml.cs, adicionando este código ao final da classe:

int count = 0;
void Handle_Clicked(object sender, System.EventArgs e)
{
count++;
((Button)sender).Text = $"You clicked {count} times.";
}

7. Depure o aplicativo no Android:


8. Clique com o botão direito do mouse para definir o iOS para o Projeto de inicialização:

9. Depure o aplicativo no iOS:


Você pode baixar o código completo na Galeria de amostras ou exibi-lo no GitHub.

Próximas etapas
Único Page Quickstart – compilar um aplicativo mais funcional.
Exemplos de Xamarin.Forms – baixe e execute exemplos de código e de aplicativos.
Livro eletrônico Creating Mobile Apps (Criando aplicativos móveis) – capítulos detalhados que ensinam o
desenvolvimento de Xamarin.Forms, disponível em PDF e incluindo centenas de exemplos adicionais.
Criar um aplicativo xamarin. Forms de página única
12/04/2019 • 24 minutes to read • Edit Online

[![Dbaixar exemplo](~/media/shared/download.png) Baixar a amostra]


(https://developer.xamarin.com/samples/xamarin-forms/GetStarted/Notes/SinglePage/)
Neste início rápido, você aprenderá como:
Crie um aplicativo de plataforma cruzada xamarin. Forms.
Defina a interface do usuário para uma página usando a linguagem de marcação de aplicativo extensível
(XAML ).
Interagir com elementos de interface do usuário XAML do código.
O guia de início rápido explica como criar um aplicativo de xamarin. Forms entre plataformas, que permite que
você insira uma observação e mantê-lo no armazenamento do dispositivo. O aplicativo final é mostrado abaixo:

Pré -requisitos
Visual Studio 2019 (versão mais recente), com o desenvolvimento móvel com .NET carga de trabalho
instalada.
Dados de Conhecimento da C#.
(opcional) Um Mac emparelhado para compilar o aplicativo no iOS.

Para obter mais informações sobre esses pré-requisitos, consulte instalando o Xamarin. Para obter informações
sobre como conectar o Visual Studio de 2019 para um host de build do Mac, consulte emparelhar com Mac para
desenvolvimento do xamarin. IOS.

Introdução ao Visual Studio de 2019


1. Inicie o Visual Studio de 2019 e na janela de início, clique em criar um novo projeto para criar um novo
projeto:
2. No criar um novo projeto janela, selecione Mobile no tipo de projeto lista suspensa, selecione o
aplicativo móvel (xamarin. Forms modelo) e clique no próxima botão:

3. No configurar seu novo projeto janela, defina as nome do projeto para notas, escolha um local
adequado para o projeto e clique no criar botão:
IMPORTANT
Os snippets C# e XAML neste início rápido requerem que a solução seja nomeada como Notas. O uso de um nome
diferente resultará em erros de build ao copiar o código deste início rápido para a solução.

4. No novo aplicativo de plataforma cruzada caixa de diálogo, clique em aplicativo em brancoe clique
no Okey botão:

Para obter mais informações sobre a biblioteca .NET Standard criada, confira Anatomia de um aplicativo
Xamarin.Forms em Aprofundamento do Início Rápido do Xamarin.Forms.
5. No Gerenciador de Soluções, no projeto Notas, clique duas vezes em MainPage.xaml para abri-lo:
6. Em MainPage.xaml, remova todo o código de modelo e substitua-o pelo código a seguir:

<?xml version="1.0" encoding="utf-8"?>


<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Notes.MainPage">
<StackLayout Margin="10,35,10,10">
<Label Text="Notes"
HorizontalOptions="Center"
FontAttributes="Bold" />
<Editor x:Name="editor"
Placeholder="Enter your note"
HeightRequest="100" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Text="Save"
Clicked="OnSaveButtonClicked" />
<Button Grid.Column="1"
Text="Delete"
Clicked="OnDeleteButtonClicked"/>
</Grid>
</StackLayout>
</ContentPage>

Esse código define declarativamente a interface do usuário para a página, que consiste em uma Label para
exibir texto, uma Editor para entrada de texto e dois Button instâncias que direcionam o aplicativo para
salvar ou excluir um arquivo. As duas instâncias de Button são dispostas horizontalmente em uma Grid ,
com o Label , o Editor e a Grid dispostos verticalmente em um StackLayout . Para obter mais
informações sobre como criar a interface do usuário, consulte interface do usuário na aprofundamento de
início rápido de xamarin. Forms.
Salve as alterações em MainPage.xaml ao pressionar CTRL+S e feche o arquivo.
7. No Gerenciador de Soluções, no projeto Notas, expanda MainPage.xaml e clique duas vezes em
MainPage.xaml.cs para abri-lo:
8. Em MainPage.xaml.cs, remova todo o código de modelo e substitua-o pelo código a seguir:
using System;
using System.IO;
using Xamarin.Forms;

namespace Notes
{
public partial class MainPage : ContentPage
{
string _fileName =
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "notes.txt");

public MainPage()
{
InitializeComponent();

if (File.Exists(_fileName))
{
editor.Text = File.ReadAllText(_fileName);
}
}

void OnSaveButtonClicked(object sender, EventArgs e)


{
File.WriteAllText(_fileName, editor.Text);
}

void OnDeleteButtonClicked(object sender, EventArgs e)


{
if (File.Exists(_fileName))
{
File.Delete(_fileName);
}
editor.Text = string.Empty;
}
}
}

Esse código define um campo _fileName , que referencia um arquivo chamado notes.txt que armazenará
os dados de notas na pasta de dados local do aplicativo. Quando o construtor de página for executado o
arquivo será lido, caso exista, e exibido no Editor . Quando o Button Salvar for pressionado, o
manipulador de eventos OnSaveButtonClicked será executado, salvando no arquivo o conteúdo do Editor .
Quando o Button Excluir for pressionado, o manipulador de eventos OnDeleteButtonClicked será
executado, excluindo o arquivo, caso ele exista, e removendo todo o texto do Editor . Para obter mais
informações sobre a interação do usuário, consulte responder à interação do usuário na aprofundamento
de início rápido de xamarin. Forms.
Salve as alterações em MainPage.xaml.cs ao pressionar CTRL+S e feche o arquivo.
Criando o Início Rápido
1. No Visual Studio, selecione o item de menu Criar > Criar Solução (ou pressione F6). A solução será criada
e uma mensagem de êxito será exibida na barra de status do Visual Studio:
Se houver erros, repita as etapas anteriores e corrija-os até que a solução seja compilada com êxito.
2. Na barra de ferramentas do Visual Studio, pressione o botão Iniciar (o botão triangular que se parece com
o botão Reproduzir) para iniciar o aplicativo em seu emulador Android escolhido:

Insira uma nota e pressione o botão Salvar.


Para obter mais informações sobre como o aplicativo é iniciado em cada plataforma, consulte iniciá-lo em
cada plataforma na aprofundamento de início rápido de xamarin. Forms.

NOTE
As etapas a seguir deverão ser realizadas somente se você tiver um Mac emparelhado que atenda aos requisitos do
sistema para o desenvolvimento no Xamarin.Forms.

3. Na barra de ferramentas do Visual Studio, clique com o botão direito do mouse no projeto Notes.iOS e
selecione Definir como projeto de inicialização.
4. Na barra de ferramentas do Visual Studio, pressione o botão Iniciar (o botão triangular que se parece com
o botão Reproduzir) para iniciar o aplicativo em seu Simulador remoto do iOS escolhido:

Insira uma nota e pressione o botão Salvar.


Para obter mais informações sobre como o aplicativo é iniciado em cada plataforma, consulte iniciá-lo em
cada plataforma na aprofundamento de início rápido de xamarin. Forms.
Pré -requisitos
Visual Studio 2017, com o desenvolvimento móvel com .NET carga de trabalho instalada.
Dados de Conhecimento da C#.
(opcional) Um Mac emparelhado para compilar o aplicativo no iOS.

Para obter mais informações sobre esses pré-requisitos, consulte instalando o Xamarin. Para obter informações
sobre como conectar o Visual Studio de 2019 para um host de build do Mac, consulte emparelhar com Mac para
desenvolvimento do xamarin. IOS.

Introdução ao Visual Studio 2017


1. Inicie o Visual Studio 2017 e, na página inicial, clique em criar novo projeto... para criar um novo projeto:

2. Na caixa de diálogo Novo Projeto, clique em Multiplataforma, selecione o modelo Aplicativo Móvel
(Xamarin.Forms), defina o Nome como Notas, escolha um local adequado para o projeto e clique no
botão OK:

IMPORTANT
Os snippets C# e XAML neste início rápido requerem que a solução seja nomeada como Notas. O uso de um nome
diferente resultará em erros de build ao copiar o código deste início rápido para a solução.

3. Na caixa de diálogo Novo Aplicativo de Plataforma Cruzada, clique em Aplicativo em Branco,


selecione .NET Standard como a estratégia de compartilhamento de código e clique no botão OK:
Para obter mais informações sobre a biblioteca .NET Standard criada, confira Anatomia de um aplicativo
Xamarin.Forms em Aprofundamento do Início Rápido do Xamarin.Forms.
4. No Gerenciador de Soluções, no projeto Notas, clique duas vezes em MainPage.xaml para abri-lo:

5. Em MainPage.xaml, remova todo o código de modelo e substitua-o pelo código a seguir:


<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Notes.MainPage">
<StackLayout Margin="10,35,10,10">
<Label Text="Notes"
HorizontalOptions="Center"
FontAttributes="Bold" />
<Editor x:Name="editor"
Placeholder="Enter your note"
HeightRequest="100" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Text="Save"
Clicked="OnSaveButtonClicked" />
<Button Grid.Column="1"
Text="Delete"
Clicked="OnDeleteButtonClicked"/>
</Grid>
</StackLayout>
</ContentPage>

Esse código define declarativamente a interface do usuário para a página, que consiste em uma Label para
exibir texto, uma Editor para entrada de texto e dois Button instâncias que direcionam o aplicativo para
salvar ou excluir um arquivo. As duas instâncias de Button são dispostas horizontalmente em uma Grid ,
com o Label , o Editor e a Grid dispostos verticalmente em um StackLayout . Para obter mais
informações sobre como criar a interface do usuário, consulte interface do usuário na aprofundamento de
início rápido de xamarin. Forms.
Salve as alterações em MainPage.xaml ao pressionar CTRL+S e feche o arquivo.
6. No Gerenciador de Soluções, no projeto Notas, expanda MainPage.xaml e clique duas vezes em
MainPage.xaml.cs para abri-lo:
7. Em MainPage.xaml.cs, remova todo o código de modelo e substitua-o pelo código a seguir:
using System;
using System.IO;
using Xamarin.Forms;

namespace Notes
{
public partial class MainPage : ContentPage
{
string _fileName =
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "notes.txt");

public MainPage()
{
InitializeComponent();

if (File.Exists(_fileName))
{
editor.Text = File.ReadAllText(_fileName);
}
}

void OnSaveButtonClicked(object sender, EventArgs e)


{
File.WriteAllText(_fileName, editor.Text);
}

void OnDeleteButtonClicked(object sender, EventArgs e)


{
if (File.Exists(_fileName))
{
File.Delete(_fileName);
}
editor.Text = string.Empty;
}
}
}

Esse código define um campo _fileName , que referencia um arquivo chamado notes.txt que armazenará
os dados de notas na pasta de dados local do aplicativo. Quando o construtor de página for executado o
arquivo será lido, caso exista, e exibido no Editor . Quando o Button Salvar for pressionado, o
manipulador de eventos OnSaveButtonClicked será executado, salvando no arquivo o conteúdo do Editor .
Quando o Button Excluir for pressionado, o manipulador de eventos OnDeleteButtonClicked será
executado, excluindo o arquivo, caso ele exista, e removendo todo o texto do Editor . Para obter mais
informações sobre a interação do usuário, consulte responder à interação do usuário na aprofundamento
de início rápido de xamarin. Forms.
Salve as alterações em MainPage.xaml.cs ao pressionar CTRL+S e feche o arquivo.
Criando o Início Rápido
1. No Visual Studio, selecione o item de menu Criar > Criar Solução (ou pressione F6). A solução será criada
e uma mensagem de êxito será exibida na barra de status do Visual Studio:
Se houver erros, repita as etapas anteriores e corrija-os até que a solução seja compilada com êxito.
2. Na barra de ferramentas do Visual Studio, pressione o botão Iniciar (o botão triangular que se parece com
o botão Reproduzir) para iniciar o aplicativo em seu emulador Android escolhido:

Insira uma nota e pressione o botão Salvar.


Para obter mais informações sobre como o aplicativo é iniciado em cada plataforma, consulte iniciá-lo em
cada plataforma na aprofundamento de início rápido de xamarin. Forms.

NOTE
As etapas a seguir deverão ser realizadas somente se você tiver um Mac emparelhado que atenda aos requisitos do
sistema para o desenvolvimento no Xamarin.Forms.

3. Na barra de ferramentas do Visual Studio, clique com o botão direito do mouse no projeto Notes.iOS e
selecione Definir como projeto de inicialização.
4. Na barra de ferramentas do Visual Studio, pressione o botão Iniciar (o botão triangular que se parece com
o botão Reproduzir) para iniciar o aplicativo em seu Simulador remoto do iOS escolhido:

Insira uma nota e pressione o botão Salvar.


Para obter mais informações sobre como o aplicativo é iniciado em cada plataforma, consulte iniciá-lo em
cada plataforma na aprofundamento de início rápido de xamarin. Forms.
Pré -requisitos
Visual Studio para Mac (versão mais recente), iOS e o suporte da plataforma Android instalado.
Xcode (versão mais recente).
Dados de Conhecimento da C#.
Para obter mais informações sobre esses pré-requisitos, consulte instalando o Xamarin.

Introdução ao Visual Studio para Mac


1. Clique em Iniciar o Visual Studio para Mac e na janela de início New para criar um novo projeto:
2. Na caixa de diálogo Escolher um modelo para seu novo projeto, clique em Multiplataforma >
Aplicativo, selecione o modelo do Aplicativo de Formulários em Branco e clique no botão Avançar:

3. Na caixa de diálogo Configurar seu aplicativo de formulários em branco, nomeie o novo aplicativo
como Notas, selecione o botão de opção Usar .NET Standard e clique no botão Avançar:
4. Na caixa de diálogo Configurar seu novo aplicativo de formulários em branco, deixe os nomes do
Projeto e da Solução definidos como Notas, escolha um local adequado para o projeto e clique no botão
Criar para criá-lo:

IMPORTANT
Os snippets C# e XAML neste início rápido requerem que a solução e o projeto sejam nomeados como Notas. O uso
de um nome diferente resultará em erros de build ao copiar o código deste início rápido para o projeto.
Para obter mais informações sobre a biblioteca .NET Standard criada, confira Anatomia de um aplicativo
Xamarin.Forms em Aprofundamento do Início Rápido do Xamarin.Forms.
5. No Painel de Soluções, no projeto Notas, clique duas vezes em MainPage.xaml para abri-lo:

6. Em MainPage.xaml, remova todo o código de modelo e substitua-o pelo código a seguir:

<?xml version="1.0" encoding="utf-8"?>


<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Notes.MainPage">
<StackLayout Margin="10,35,10,10">
<Label Text="Notes"
HorizontalOptions="Center"
FontAttributes="Bold" />
<Editor x:Name="editor"
Placeholder="Enter your note"
HeightRequest="100" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Text="Save"
Clicked="OnSaveButtonClicked" />
<Button Grid.Column="1"
Text="Delete"
Clicked="OnDeleteButtonClicked"/>
</Grid>
</StackLayout>
</ContentPage>

Esse código define declarativamente a interface do usuário para a página, que consiste em uma Label para
exibir texto, uma Editor para entrada de texto e dois Button instâncias que direcionam o aplicativo para
salvar ou excluir um arquivo. As duas instâncias de Button são dispostas horizontalmente em uma Grid ,
com o Label , o Editor e a Grid dispostos verticalmente em um StackLayout . Para obter mais
informações sobre como criar a interface do usuário, consulte interface do usuário na aprofundamento de
início rápido de xamarin. Forms.
Salve as alterações em MainPage.xaml ao escolher Arquivo > Salvar (ou ao pressionar ⌘ + S ) e feche o
arquivo.
7. No Painel de Soluções, no projeto Notas, expanda MainPage.xaml e clique duas vezes em
MainPage.xaml.cs para abri-lo:
8. Em MainPage.xaml.cs, remova todo o código de modelo e substitua-o pelo código a seguir:

using System;
using System.IO;
using Xamarin.Forms;

namespace Notes
{
public partial class MainPage : ContentPage
{
string _fileName =
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "notes.txt");

public MainPage()
{
InitializeComponent();

if (File.Exists(_fileName))
{
editor.Text = File.ReadAllText(_fileName);
}
}

void OnSaveButtonClicked(object sender, EventArgs e)


{
File.WriteAllText(_fileName, editor.Text);
}

void OnDeleteButtonClicked(object sender, EventArgs e)


{
if (File.Exists(_fileName))
{
File.Delete(_fileName);
}
editor.Text = string.Empty;
}
}
}

Esse código define um campo _fileName , que referencia um arquivo chamado notes.txt que armazenará
os dados de notas na pasta de dados local do aplicativo. Quando o construtor de página for executado o
arquivo será lido, caso exista, e exibido no Editor . Quando o Button Salvar for pressionado, o
manipulador de eventos OnSaveButtonClicked será executado, salvando no arquivo o conteúdo do Editor .
Quando o Button Excluir for pressionado, o manipulador de eventos OnDeleteButtonClicked será
executado, excluindo o arquivo, caso ele exista, e removendo todo o texto do Editor . Para obter mais
informações sobre a interação do usuário, consulte responder à interação do usuário na aprofundamento
de início rápido de xamarin. Forms.
Salve as alterações em MainPage.xaml.cs ao escolher Arquivo > Salvar (ou ao pressionar ⌘ + S ) e
feche o arquivo.
Criando o Início Rápido
1. No Visual Studio para Mac, selecione o item de menu Compilar > Compilar Tudo (ou pressione ⌘ + B ).
Os projetos serão criados e uma mensagem de êxito será exibida na barra de ferramentas do Visual Studio
para Mac.

Se houver erros, repita as etapas anteriores e corrija-os até que os projetos sejam compilados com êxito.
2. No painel de soluções, selecione o Notes.iOS projeto, o botão direito do mouse e selecione definir
como projeto de inicialização:

3. Na barra de ferramentas do Visual Studio para Mac, pressione o botão Iniciar (o botão triangular que se
parece com o botão Reproduzir) para iniciar o aplicativo no Simulador do iOS escolhido:

Insira uma nota e pressione o botão Salvar.


Para obter mais informações sobre como o aplicativo é iniciado em cada plataforma, consulte iniciá-lo em
cada plataforma na aprofundamento de início rápido de xamarin. Forms.
4. No painel de soluções, selecione o Notes.Droid projeto, o botão direito do mouse e selecione definir
como projeto de inicialização:

5. Na barra de ferramentas do Visual Studio para Mac, pressione o botão Iniciar (o botão triangular que se
parece com o botão Reproduzir) para iniciar o aplicativo em seu emulador Android escolhido:

Insira uma nota e pressione o botão Salvar.


Para obter mais informações sobre como o aplicativo é iniciado em cada plataforma, consulte iniciá-lo em
cada plataforma na aprofundamento de início rápido de xamarin. Forms.

Próximas etapas
Neste início rápido, você aprendeu como:
Crie um aplicativo de plataforma cruzada xamarin. Forms.
Defina a interface do usuário para uma página usando a linguagem de marcação de aplicativo extensível
(XAML ).
Interagir com elementos de interface do usuário XAML do código.
Para ativar esse aplicativo de página única em um aplicativo de várias página, continue para o próximo início
rápido.
Avançar

Links relacionados
Anotações (amostra)
Aprofundamento de início rápido do xamarin. Forms
Executar a navegação em um aplicativo xamarin.
Forms de várias páginas
12/04/2019 • 26 minutes to read • Edit Online

[![Dbaixar exemplo](~/media/shared/download.png) Baixar a amostra]


(https://developer.xamarin.com/samples/xamarin-forms/GetStarted/Notes/MultiPage/)
Neste início rápido, você aprenderá como:
Adicione páginas adicionais a uma solução do xamarin. Forms.
Execute a navegação entre páginas.
Use a ligação de dados para sincronizar dados entre elementos de interface do usuário e sua fonte de dados.
O guia de início rápido explica como ativar um plataforma cruzada xamarin. Forms aplicativo de página única,
capaz de armazenar uma anotação única, em um aplicativo de várias página, capaz de armazenar várias anotações.
O aplicativo final é mostrado abaixo:

Pré -requisitos
Você deve concluir com êxito a guia de início rápido anterior antes de tentar este início rápido. Como alternativa,
baixe o exemplo de início rápido anterior e usá-lo como ponto de partida para este início rápido.

Atualizar um aplicativo com o Visual Studio


1. Inicie o Visual Studio. Na janela de início, clique o notas solução na lista de projetos/soluções recentes, ou
clique em abrir um projeto ou soluçãoe, na Abrir projeto/solução caixa de diálogo Selecione o arquivo
de solução para o projeto de notas:
2. No Gerenciador de soluções, clique com botão direito no notas do projeto e selecione Adicionar >
nova pasta:

3. Na Gerenciador de soluções, nomeie a nova pasta modelos:


4. Na Gerenciador de soluções, selecione o modelos pasta, o botão direito do mouse e selecione
Adicionar > Novo Item... :

5. No Adicionar Novo Item caixa de diálogo, selecione Visual C# itens > classe, nomeie o novo arquivo
Observaçãoe clique no adicionar botão:

Isso adicionará uma classe chamada Observação para o modelos pasta dos notas projeto.
6. Na Note.cs, remova todo o código de modelo e substitua-o pelo código a seguir:
using System;

namespace Notes.Models
{
public class Note
{
public string Filename { get; set; }
public string Text { get; set; }
public DateTime Date { get; set; }
}
}

Essa classe define um Note modelo que armazenará os dados sobre cada Observação no aplicativo.
Salve as alterações em Note.cs pressionando CTRL + Se feche o arquivo.
7. No Gerenciador de soluções, clique com botão direito no notas do projeto e selecione Adicionar >
Novo Item... . No Adicionar Novo Item caixa de diálogo, selecione Visual C# itens > xamarin. Forms
> página de conteúdo, nomeie o novo arquivo NoteEntryPagee clique no Adicionar botão:

Isso adicionará uma nova página chamada NoteEntryPage para a pasta raiz do projeto. Esta página será a
segunda página do aplicativo.
8. Na NoteEntryPage.xaml, remova todo o código de modelo e substitua-o pelo código a seguir:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Notes.NoteEntryPage"
Title="Note Entry">
<StackLayout Margin="20">
<Editor Placeholder="Enter your note"
Text="{Binding Text}"
HeightRequest="100" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Text="Save"
Clicked="OnSaveButtonClicked" />
<Button Grid.Column="1"
Text="Delete"
Clicked="OnDeleteButtonClicked"/>
</Grid>
</StackLayout>
</ContentPage>

Esse código define declarativamente a interface do usuário para a página, que consiste em uma Editor
para entrada de texto e dois Button instâncias que direcionam o aplicativo para salvar ou excluir um
arquivo. Os dois Button instâncias são dispostas horizontalmente em uma Grid , com o Editor e Grid
sendo dispostos verticalmente em um StackLayout . Além disso, o Editor usa associação de dados para
associar ao Text propriedade do Note modelo. Para obter mais informações sobre associação de dados,
consulte vinculação de dados na aprofundamento de início rápido de xamarin. Forms.
Salve as alterações em NoteEntryPage.xaml pressionando CTRL + Se feche o arquivo.
9. Na NoteEntryPage.xaml.cs, remova todo o código de modelo e substitua-o pelo código a seguir:
using System;
using System.IO;
using Xamarin.Forms;
using Notes.Models;

namespace Notes
{
public partial class NoteEntryPage : ContentPage
{
public NoteEntryPage()
{
InitializeComponent();
}

async void OnSaveButtonClicked(object sender, EventArgs e)


{
var note = (Note)BindingContext;

if (string.IsNullOrWhiteSpace(note.Filename))
{
// Save
var filename = Path.Combine(App.FolderPath, $"{Path.GetRandomFileName()}.notes.txt");
File.WriteAllText(filename, note.Text);
}
else
{
// Update
File.WriteAllText(note.Filename, note.Text);
}

await Navigation.PopAsync();
}

async void OnDeleteButtonClicked(object sender, EventArgs e)


{
var note = (Note)BindingContext;

if (File.Exists(note.Filename))
{
File.Delete(note.Filename);
}

await Navigation.PopAsync();
}
}
}

Este código armazena uma Note instância, que representa uma anotação única, em de BindingContext da
página. Quando o salve Button é pressionado a OnSaveButtonClicked manipulador de eventos é
executado, o que seja salva o conteúdo do Editor para um novo arquivo com um nome de arquivo gerado
aleatoriamente, ou para um arquivo existente se uma anotação está sendo atualizada. Em ambos os casos, o
arquivo é armazenado na pasta de dados do aplicativo local para o aplicativo. Em seguida, o método navega
de volta para a página anterior. Quando o exclua Button é pressionado a OnDeleteButtonClicked
manipulador de eventos é executado, o que exclui o arquivo, desde que ela existe e navega de volta para a
página anterior. Para obter mais informações sobre navegação, consulte navegação na aprofundamento de
início rápido de xamarin. Forms.
Salve as alterações em NoteEntryPage.xaml.cs pressionando CTRL + Se feche o arquivo.

WARNING
A tentativa de compilar o aplicativo neste ponto resultará em erros que serão corrigidos em etapas subsequentes.
10. No Gerenciador de soluções, clique com botão direito no notas do projeto e selecione Adicionar >
Novo Item... . No Adicionar Novo Item caixa de diálogo, selecione Visual C# itens > xamarin. Forms
> página de conteúdo, nomeie o novo arquivo NotesPagee clique no adicionar botão.
Isso adicionará uma página chamada NotesPage para a pasta raiz do projeto. Esta página será a página
raiz do aplicativo.
11. Na NotesPage.xaml, remova todo o código de modelo e substitua-o pelo código a seguir:

<?xml version="1.0" encoding="UTF-8"?>


<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Notes.NotesPage"
Title="Notes">
<ContentPage.ToolbarItems>
<ToolbarItem Text="+"
Clicked="OnNoteAddedClicked" />
</ContentPage.ToolbarItems>
<ListView x:Name="listView"
Margin="20"
ItemSelected="OnListViewItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Text}"
Detail="{Binding Date}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>

Esse código define declarativamente a interface do usuário para a página, que consiste em uma ListView e
uma ToolbarItem . O ListView usa dados de associação para exibir todas as anotações são recuperadas
pelo aplicativo e selecionando uma observação navegará até o NoteEntryPage em que a anotação pode ser
modificada. Como alternativa, uma nova anotação pode ser criada, pressionando o ToolbarItem . Para obter
mais informações sobre associação de dados, consulte vinculação de dados na aprofundamento de início
rápido de xamarin. Forms.
Salve as alterações em NotesPage.xaml pressionando CTRL + Se feche o arquivo.
12. Na NotesPage.xaml.cs, remova todo o código de modelo e substitua-o pelo código a seguir:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Xamarin.Forms;
using Notes.Models;

namespace Notes
{
public partial class NotesPage : ContentPage
{
public NotesPage()
{
InitializeComponent();
}

protected override void OnAppearing()


{
base.OnAppearing();

var notes = new List<Note>();

var files = Directory.EnumerateFiles(App.FolderPath, "*.notes.txt");


foreach (var filename in files)
{
notes.Add(new Note
{
Filename = filename,
Text = File.ReadAllText(filename),
Date = File.GetCreationTime(filename)
});
}

listView.ItemsSource = notes
.OrderBy(d => d.Date)
.ToList();
}

async void OnNoteAddedClicked(object sender, EventArgs e)


{
await Navigation.PushAsync(new NoteEntryPage
{
BindingContext = new Note()
});
}

async void OnListViewItemSelected(object sender, SelectedItemChangedEventArgs e)


{
if (e.SelectedItem != null)
{
await Navigation.PushAsync(new NoteEntryPage
{
BindingContext = e.SelectedItem as Note
});
}
}
}
}

Esse código define a funcionalidade para o NotesPage . Quando a página for exibida, o OnAppearing método
é executado, que preenche a ListView com as observações que foram recuperadas da pasta de dados do
aplicativo local. Quando o ToolbarItem é pressionado a OnNoteAddedClicked manipulador de eventos é
executado. Esse método navega para o NoteEntryPage , definindo o BindingContext dos NoteEntryPage para
um novo Note instância. Quando um item na ListView está selecionado o OnListViewItemSelected
manipulador de eventos é executado. Esse método navega para o NoteEntryPage , definindo o
BindingContext dos NoteEntryPage para selecionado Note instância. Para obter mais informações sobre
navegação, consulte navegação na aprofundamento de início rápido de xamarin. Forms.
Salve as alterações em NotesPage.xaml.cs pressionando CTRL + Se feche o arquivo.

WARNING
A tentativa de compilar o aplicativo neste ponto resultará em erros que serão corrigidos em etapas subsequentes.

13. Na Gerenciador de soluções, clique duas vezes em App.xaml.cs para abri-lo. Em seguida, substitua o
código existente pelo código a seguir:

using System;
using System.IO;
using Xamarin.Forms;

namespace Notes
{
public partial class App : Application
{
public static string FolderPath { get; private set; }

public App()
{
InitializeComponent();
FolderPath =
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData));
MainPage = new NavigationPage(new NotesPage());
}
...
}
}

Esse código adiciona uma declaração de namespace para o System.IO namespace e adiciona uma
declaração para um estático FolderPath propriedade do tipo string . O FolderPath propriedade é usada
para armazenar o caminho no dispositivo onde Observe que os dados serão armazenados. Além disso, o
código inicializa o FolderPath propriedade no App construtor e inicializa o MainPage propriedade seja
uma NavigationPage que hospeda um instância do NotesPage . Para obter mais informações sobre
navegação, consulte navegação na aprofundamento de início rápido de xamarin. Forms.
Salve as alterações em App.xaml.cs ao pressionar CTRL + S e feche o arquivo.
14. Na Gerenciador de soluções, no notas do projeto, clique com botão direito MainPage. XAMLe
selecione excluir. Na caixa de diálogo que aparece pressione a Okey botão para remover o arquivo de
disco rígido.
Isso remove uma página que não é mais usada.
15. Compile e execute o projeto em cada plataforma. Para obter mais informações, consulte criando o guia de
início rápido.
Sobre o NotesPage pressione a + botão para navegar para o NoteEntryPage e insira uma observação.
Depois de salvar a nota o aplicativo será navegue de volta para o NotesPage.
Insira um número de observações, de comprimento variado, para observar o comportamento do aplicativo.

Atualizar um aplicativo com o Visual Studio para Mac


1. Inicialize o Visual Studio para Mac. Na janela de início, clique em abrire na caixa de diálogo, selecione o
arquivo de solução para o projeto de notas:

2. No painel de soluções, selecione o notas projeto, o botão direito do mouse e selecione Adicionar >
nova pasta:

3. No painel de soluções, nomeie a nova pasta modelos:


4. No painel de soluções, selecione o modelos pasta, o botão direito do mouse e selecione Adicionar >
novo arquivo... :

5. No novo arquivo caixa de diálogo, selecione geral > classe vazia, nomeie o novo arquivo Observaçãoe
clique no novo botão:

Isso adicionará uma classe chamada Observação para o modelos pasta dos notas projeto.
6. Na Note.cs, remova todo o código de modelo e substitua-o pelo código a seguir:
using System;

namespace Notes.Models
{
public class Note
{
public string Filename { get; set; }
public string Text { get; set; }
public DateTime Date { get; set; }
}
}

Essa classe define um Note modelo que armazenará os dados sobre cada Observação no aplicativo.
Salve as alterações em Note.cs escolhendo arquivo > Salvar (ou pressionando ⌘ + S ) e feche o arquivo.
7. No painel de soluções, selecione o notas projeto, o botão direito do mouse e selecione Adicionar >
novo arquivo... . No novo arquivo caixa de diálogo, selecione formulários > formulários ContentPage
XAML, nomeie o novo arquivo NoteEntryPagee clique no novo botão:

Isso adicionará uma nova página chamada NoteEntryPage para a pasta raiz do projeto. Esta página será a
segunda página do aplicativo.
8. Na NoteEntryPage.xaml, remova todo o código de modelo e substitua-o pelo código a seguir:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Notes.NoteEntryPage"
Title="Note Entry">
<StackLayout Margin="20">
<Editor Placeholder="Enter your note"
Text="{Binding Text}"
HeightRequest="100" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Text="Save"
Clicked="OnSaveButtonClicked" />
<Button Grid.Column="1"
Text="Delete"
Clicked="OnDeleteButtonClicked"/>
</Grid>
</StackLayout>
</ContentPage>

Esse código define declarativamente a interface do usuário para a página, que consiste em uma Editor
para entrada de texto e dois Button instâncias que direcionam o aplicativo para salvar ou excluir um
arquivo. Os dois Button instâncias são dispostas horizontalmente em uma Grid , com o Editor e Grid
sendo dispostos verticalmente em um StackLayout . Além disso, o Editor usa associação de dados para
associar ao Text propriedade do Note modelo. Para obter mais informações sobre associação de dados,
consulte vinculação de dados na aprofundamento de início rápido de xamarin. Forms.
Salve as alterações em NoteEntryPage.xaml escolhendo arquivo > Salvar (ou pressionando ⌘ + S ) e
feche o arquivo.
9. Na NoteEntryPage.xaml.cs, remova todo o código de modelo e substitua-o pelo código a seguir:
using System;
using System.IO;
using Xamarin.Forms;
using Notes.Models;

namespace Notes
{
public partial class NoteEntryPage : ContentPage
{
public NoteEntryPage()
{
InitializeComponent();
}

async void OnSaveButtonClicked(object sender, EventArgs e)


{
var note = (Note)BindingContext;

if (string.IsNullOrWhiteSpace(note.Filename))
{
// Save
var filename = Path.Combine(App.FolderPath, $"{Path.GetRandomFileName()}.notes.txt");
File.WriteAllText(filename, note.Text);
}
else
{
// Update
File.WriteAllText(note.Filename, note.Text);
}

await Navigation.PopAsync();
}

async void OnDeleteButtonClicked(object sender, EventArgs e)


{
var note = (Note)BindingContext;

if (File.Exists(note.Filename))
{
File.Delete(note.Filename);
}

await Navigation.PopAsync();
}
}
}

Este código armazena uma Note instância, que representa uma anotação única, em de BindingContext da
página. Quando o salve Button é pressionado a OnSaveButtonClicked manipulador de eventos é
executado, o que seja salva o conteúdo do Editor para um novo arquivo com um nome de arquivo gerado
aleatoriamente, ou para um arquivo existente se uma anotação está sendo atualizada. Em ambos os casos, o
arquivo é armazenado na pasta de dados do aplicativo local para o aplicativo. Em seguida, o método navega
de volta para a página anterior. Quando o exclua Button é pressionado a OnDeleteButtonClicked
manipulador de eventos é executado, o que exclui o arquivo, desde que ela existe e navega de volta para a
página anterior. Para obter mais informações sobre navegação, consulte navegação na aprofundamento de
início rápido de xamarin. Forms.
Salve as alterações em NoteEntryPage.xaml.cs escolhendo arquivo > Salvar (ou pressionando ⌘ + S ) e
feche o arquivo.
WARNING
A tentativa de compilar o aplicativo neste ponto resultará em erros que serão corrigidos em etapas subsequentes.

10. No painel de soluções, selecione o notas projeto, o botão direito do mouse e selecione Adicionar >
novo arquivo... . No novo arquivo caixa de diálogo, selecione formulários > formulários ContentPage
XAML, nomeie o novo arquivo NotesPagee clique no novo botão.
Isso adicionará uma página chamada NotesPage para a pasta raiz do projeto. Esta página será a página
raiz do aplicativo.
11. Na NotesPage.xaml, remova todo o código de modelo e substitua-o pelo código a seguir:

<?xml version="1.0" encoding="UTF-8"?>


<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Notes.NotesPage"
Title="Notes">
<ContentPage.ToolbarItems>
<ToolbarItem Text="+"
Clicked="OnNoteAddedClicked" />
</ContentPage.ToolbarItems>
<ListView x:Name="listView"
Margin="20"
ItemSelected="OnListViewItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Text}"
Detail="{Binding Date}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>

Esse código define declarativamente a interface do usuário para a página, que consiste em uma ListView e
uma ToolbarItem . O ListView usa dados de associação para exibir todas as anotações são recuperadas
pelo aplicativo e selecionando uma observação navegará até o NoteEntryPage em que a anotação pode ser
modificada. Como alternativa, uma nova anotação pode ser criada, pressionando o ToolbarItem . Para obter
mais informações sobre associação de dados, consulte vinculação de dados na aprofundamento de início
rápido de xamarin. Forms.
Salve as alterações em NotesPage.xaml escolhendo arquivo > Salvar (ou pressionando ⌘ + S ) e feche o
arquivo.
12. Na NotesPage.xaml.cs, remova todo o código de modelo e substitua-o pelo código a seguir:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Xamarin.Forms;
using Notes.Models;

namespace Notes
{
public partial class NotesPage : ContentPage
{
public NotesPage()
{
InitializeComponent();
}

protected override void OnAppearing()


{
base.OnAppearing();

var notes = new List<Note>();

var files = Directory.EnumerateFiles(App.FolderPath, "*.notes.txt");


foreach (var filename in files)
{
notes.Add(new Note
{
Filename = filename,
Text = File.ReadAllText(filename),
Date = File.GetCreationTime(filename)
});
}

listView.ItemsSource = notes
.OrderBy(d => d.Date)
.ToList();
}

async void OnNoteAddedClicked(object sender, EventArgs e)


{
await Navigation.PushAsync(new NoteEntryPage
{
BindingContext = new Note()
});
}

async void OnListViewItemSelected(object sender, SelectedItemChangedEventArgs e)


{
if (e.SelectedItem != null)
{
await Navigation.PushAsync(new NoteEntryPage
{
BindingContext = e.SelectedItem as Note
});
}
}
}
}

Esse código define a funcionalidade para o NotesPage . Quando a página for exibida, o OnAppearing método
é executado, que preenche a ListView com as observações que foram recuperadas da pasta de dados do
aplicativo local. Quando o ToolbarItem é pressionado a OnNoteAddedClicked manipulador de eventos é
executado. Esse método navega para o NoteEntryPage , definindo o BindingContext dos NoteEntryPage para
um novo Note instância. Quando um item na ListView está selecionado o OnListViewItemSelected
manipulador de eventos é executado. Esse método navega para o NoteEntryPage , definindo o
BindingContext dos NoteEntryPage para selecionado Note instância. Para obter mais informações sobre
navegação, consulte navegação na aprofundamento de início rápido de xamarin. Forms.
Salve as alterações em NotesPage.xaml.cs escolhendo arquivo > Salvar (ou pressionando ⌘ + S ) e
feche o arquivo.

WARNING
A tentativa de compilar o aplicativo neste ponto resultará em erros que serão corrigidos em etapas subsequentes.

13. No painel de soluções, clique duas vezes em App.xaml.cs para abri-lo. Em seguida, substitua o código
existente pelo código a seguir:

using System;
using System.IO;
using Xamarin.Forms;

namespace Notes
{
public partial class App : Application
{
public static string FolderPath { get; private set; }

public App()
{
InitializeComponent();
FolderPath =
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData));
MainPage = new NavigationPage(new NotesPage());
}
...
}
}

Esse código adiciona uma declaração de namespace para o System.IO namespace e adiciona uma
declaração para um estático FolderPath propriedade do tipo string . O FolderPath propriedade é usada
para armazenar o caminho no dispositivo onde Observe que os dados serão armazenados. Além disso, o
código inicializa o FolderPath propriedade no App construtor e inicializa o MainPage propriedade seja
uma NavigationPage que hospeda um instância do NotesPage . Para obter mais informações sobre
navegação, consulte navegação na aprofundamento de início rápido de xamarin. Forms.
Salve as alterações em App.xaml.cs escolhendo Arquivo > Salvar (ou pressionando ⌘ + S ) e feche o
arquivo.
14. No painel de soluções, no notas do projeto, clique com botão direito MainPage. XAMLe selecione
remover. Na caixa de diálogo que aparece pressione a excluir botão para remover o arquivo de disco
rígido.
Isso remove uma página que não é mais usada.
15. Compile e execute o projeto em cada plataforma. Para obter mais informações, consulte criando o guia de
início rápido.
Sobre o NotesPage pressione a + botão para navegar para o NoteEntryPage e insira uma observação.
Depois de salvar a nota o aplicativo será navegue de volta para o NotesPage.
Insira um número de observações, de comprimento variado, para observar o comportamento do aplicativo.
Próximas etapas
Neste início rápido, você aprendeu como:
Adicione páginas adicionais a uma solução do xamarin. Forms.
Execute a navegação entre páginas.
Use a ligação de dados para sincronizar dados entre elementos de interface do usuário e sua fonte de dados.
Para modificar o aplicativo para que ele armazena seus dados em um banco de dados local SQLite.NET, continue
para o próximo início rápido.
Avançar

Links relacionados
Anotações (amostra)
Aprofundamento de início rápido do xamarin. Forms
Store dados em um banco de dados Local
SQLite.NET
16/04/2019 • 17 minutes to read • Edit Online

Baixar o exemplo
Neste início rápido, você aprenderá como:
Use o Gerenciador de pacotes do NuGet para adicionar um pacote do NuGet a um projeto.
Store dados localmente em um banco de dados SQLite.NET.
O guia de início rápido orienta como armazenar dados em um banco de dados local do SQLite.NET. O aplicativo
final é mostrado abaixo:

Pré -requisitos
Você deve concluir com êxito a guia de início rápido anterior antes de tentar este início rápido. Como alternativa,
baixe o exemplo de início rápido anterior e usá-lo como ponto de partida para este início rápido.

Atualizar um aplicativo com o Visual Studio


1. Inicie o Visual Studio e abra a solução de notas.
2. Na Gerenciador de soluções, selecione o notas do projeto, clique com botão direito e selecione
gerenciar pacotes NuGet... :
3. No Gerenciador de Pacotes NuGet, selecione a guia Procurar, pesquise pelo pacote NuGet sqlite-net-
pcl, selecione-o e clique no botão Instalar para adicioná-lo ao projeto:

NOTE
Há diversos pacotes NuGet com nomes semelhantes. O pacote correto tem estes atributos:
Autor(es): Frank A. Krueger
Id: sqlite-net-pcl
Link do NuGet: sqlite-net-pcl
Apesar do nome do pacote, este pacote NuGet pode ser usado em projetos do .NET Standard.

Este pacote será usado para incorporar operações de banco de dados ao aplicativo.
4. Na Gerenciador de soluções, no notas projeto, abra Note.cs no modelos pasta e substitua o existente
de código com o o código a seguir:
using System;
using SQLite;

namespace Notes.Models
{
public class Note
{
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
public string Text { get; set; }
public DateTime Date { get; set; }
}
}

Essa classe define um Note modelo que armazenará os dados sobre cada Observação no aplicativo. O ID
propriedade é marcada com PrimaryKey e AutoIncrement atributos para garantir que cada Note instância
no banco de dados SQLite.NET terá uma id exclusiva fornecida pelo SQLite.NET.
Salve as alterações em Note.cs pressionando CTRL + Se feche o arquivo.

WARNING
A tentativa de compilar o aplicativo neste ponto resultará em erros que serão corrigidos em etapas subsequentes.

5. Na Gerenciador de soluções, adicione uma nova pasta chamada dados para o notas projeto.
6. Na Gerenciador de soluções, no notas do projeto, adicione uma nova classe denominada
NoteDatabase para o dados pasta.
7. Na NoteDatabase.cs, substitua o código existente pelo código a seguir:
using System.Collections.Generic;
using System.Threading.Tasks;
using SQLite;
using Notes.Models;

namespace Notes.Data
{
public class NoteDatabase
{
readonly SQLiteAsyncConnection _database;

public NoteDatabase(string dbPath)


{
_database = new SQLiteAsyncConnection(dbPath);
_database.CreateTableAsync<Note>().Wait();
}

public Task<List<Note>> GetNotesAsync()


{
return _database.Table<Note>().ToListAsync();
}

public Task<Note> GetNoteAsync(int id)


{
return _database.Table<Note>()
.Where(i => i.ID == id)
.FirstOrDefaultAsync();
}

public Task<int> SaveNoteAsync(Note note)


{
if (note.ID != 0)
{
return _database.UpdateAsync(note);
}
else
{
return _database.InsertAsync(note);
}
}

public Task<int> DeleteNoteAsync(Note note)


{
return _database.DeleteAsync(note);
}
}
}

Essa classe contém código para criar o banco de dados, ler dados a partir dele, gravação de dados e exclua
dados dele. O código usa APIs SQLite.NET assíncronas que movem operações de banco de dados para
threads de segundo plano. Além disso, o construtor NoteDatabase usa o caminho para o arquivo de banco
de dados como um argumento. Esse caminho será fornecido pelo App classe na próxima etapa.
Salve as alterações em NoteDatabase.cs pressionando CTRL + Se feche o arquivo.

WARNING
A tentativa de compilar o aplicativo neste ponto resultará em erros que serão corrigidos em etapas subsequentes.

8. Na Gerenciador de soluções, no notas do projeto, clique duas vezes em App.xaml.cs para abri-lo. Em
seguida, substitua o código existente pelo código a seguir:
using System;
using System.IO;
using Xamarin.Forms;
using Notes.Data;

namespace Notes
{
public partial class App : Application
{
static NoteDatabase database;

public static NoteDatabase Database


{
get
{
if (database == null)
{
database = new
NoteDatabase(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"Notes.db3"));
}
return database;
}
}

public App()
{
InitializeComponent();
MainPage = new NavigationPage(new NotesPage());
}
...
}
}

Esse código define uma Database que cria uma nova propriedade NoteDatabase instância como um
singleton, passando o nome do arquivo do banco de dados como o argumento para o NoteDatabase
construtor. A vantagem de expor o banco de dados como um singleton é que uma conexão de banco de
dados individual criada é mantida aberta enquanto o aplicativo é executado, evitando, portanto, o trabalho
de abrir e fechar o arquivo de banco de dados cada vez que uma operação de banco de dados é realizada.
Salve as alterações em App.xaml.cs ao pressionar CTRL + S e feche o arquivo.

WARNING
A tentativa de compilar o aplicativo neste ponto resultará em erros que serão corrigidos em etapas subsequentes.

9. Na Gerenciador de soluções, no notas do projeto, clique duas vezes em NotesPage.xaml.cs para abri-
lo. Em seguida, substitua o OnAppearing método com o código a seguir:

protected override async void OnAppearing()


{
base.OnAppearing();

listView.ItemsSource = await App.Database.GetNotesAsync();


}

Esse código preenche a ListView com as observações armazenadas no banco de dados.


Salve as alterações em NotesPage.xaml.cs pressionando CTRL + Se feche o arquivo.
WARNING
A tentativa de compilar o aplicativo neste ponto resultará em erros que serão corrigidos em etapas subsequentes.

10. Na Gerenciador de soluções, clique duas vezes em NoteEntryPage.xaml.cs para abri-lo. Em seguida,
substitua os OnSaveButtonClicked e OnDeleteButtonClicked métodos com o código a seguir:

async void OnSaveButtonClicked(object sender, EventArgs e)


{
var note = (Note)BindingContext;
note.Date = DateTime.UtcNow;
await App.Database.SaveNoteAsync(note);
await Navigation.PopAsync();
}

async void OnDeleteButtonClicked(object sender, EventArgs e)


{
var note = (Note)BindingContext;
await App.Database.DeleteNoteAsync(note);
await Navigation.PopAsync();
}

O NoteEntryPage armazena um Note instância, que representa uma anotação única, nas BindingContext
da página. Quando o OnSaveButtonClicked manipulador de eventos é executado, o Note instância é salva
no banco de dados e o aplicativo navega de volta à página anterior. Quando o OnDeleteButtonClicked
manipulador de eventos é executado, o Note instância é excluída do banco de dados e o aplicativo navega
de volta à página anterior.
Salve as alterações em NoteEntryPage.xaml.cs pressionando CTRL + Se feche o arquivo.
11. Compile e execute o projeto em cada plataforma. Para obter mais informações, consulte criando o guia de
início rápido.
Sobre o NotesPage pressione a + botão para navegar para o NoteEntryPage e insira uma observação.
Depois de salvar a nota o aplicativo será navegue de volta para o NotesPage.
Insira um número de observações, de comprimento variado, para observar o comportamento do aplicativo.

Atualizar um aplicativo com o Visual Studio para Mac


1. Inicie o Visual Studio para Mac e abra o projeto de notas.
2. No painel de soluções, selecione o notas do projeto, clique com botão direito e selecione Adicionar >
Adicionar pacotes NuGet... :
3. Na janela Adicionar Pacotes, pesquise pelo pacote NuGet sqlite-net-pcl, selecione-o e clique no botão
Adicionar Pacote para adicioná-lo ao projeto:

NOTE
Há diversos pacotes NuGet com nomes semelhantes. O pacote correto tem estes atributos:
Autor: Frank A. Krueger
Id: sqlite-net-pcl
Link do NuGet: sqlite-net-pcl
Apesar do nome do pacote, este pacote NuGet pode ser usado em projetos do .NET Standard.

Este pacote será usado para incorporar operações de banco de dados ao aplicativo.
4. No painel de soluções, no notas projeto, abra Note.cs no modelos pasta e substitua o código existente
pelo seguinte código:
using System;
using SQLite;

namespace Notes.Models
{
public class Note
{
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
public string Text { get; set; }
public DateTime Date { get; set; }
}
}

Essa classe define um Note modelo que armazenará os dados sobre cada Observação no aplicativo. O ID
propriedade é marcada com PrimaryKey e AutoIncrement atributos para garantir que cada Note instância
no banco de dados SQLite.NET terá uma id exclusiva fornecida pelo SQLite.NET.
Salve as alterações em Note.cs escolhendo arquivo > Salvar (ou pressionando ⌘ + S ) e feche o arquivo.

WARNING
A tentativa de compilar o aplicativo neste ponto resultará em erros que serão corrigidos em etapas subsequentes.

5. No painel de soluções, adicione uma nova pasta chamada dados para o notas projeto.
6. No painel de soluções, no notas do projeto, adicione uma nova classe denominada NoteDatabase para
o dados pasta.
7. Na NoteDatabase.cs, substitua o código existente pelo código a seguir:
using System.Collections.Generic;
using System.Threading.Tasks;
using SQLite;
using Notes.Models;

namespace Notes.Data
{
public class NoteDatabase
{
readonly SQLiteAsyncConnection _database;

public NoteDatabase(string dbPath)


{
_database = new SQLiteAsyncConnection(dbPath);
_database.CreateTableAsync<Note>().Wait();
}

public Task<List<Note>> GetNotesAsync()


{
return _database.Table<Note>().ToListAsync();
}

public Task<Note> GetNoteAsync(int id)


{
return _database.Table<Note>()
.Where(i => i.ID == id)
.FirstOrDefaultAsync();
}

public Task<int> SaveNoteAsync(Note note)


{
if (note.ID != 0)
{
return _database.UpdateAsync(note);
}
else
{
return _database.InsertAsync(note);
}
}

public Task<int> DeleteNoteAsync(Note note)


{
return _database.DeleteAsync(note);
}
}
}

Essa classe contém código para criar o banco de dados, ler dados a partir dele, gravação de dados e exclua
dados dele. O código usa APIs SQLite.NET assíncronas que movem operações de banco de dados para
threads de segundo plano. Além disso, o construtor NoteDatabase usa o caminho para o arquivo de banco
de dados como um argumento. Esse caminho será fornecido pelo App classe na próxima etapa.
Salve as alterações em NoteDatabase.cs escolhendo arquivo > Salvar (ou pressionando ⌘ + S ) e feche
o arquivo.

WARNING
A tentativa de compilar o aplicativo neste ponto resultará em erros que serão corrigidos em etapas subsequentes.

8. No painel de soluções, no notas do projeto, clique duas vezes em App.xaml.cs para abri-lo. Em seguida,
substitua o código existente pelo código a seguir:
using System;
using System.IO;
using Xamarin.Forms;
using Notes.Data;

namespace Notes
{
public partial class App : Application
{
static NoteDatabase database;

public static NoteDatabase Database


{
get
{
if (database == null)
{
database = new
NoteDatabase(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"Notes.db3"));
}
return database;
}
}

public App()
{
InitializeComponent();
MainPage = new NavigationPage(new NotesPage());
}
...
}
}

Esse código define uma Database que cria uma nova propriedade NoteDatabase instância como um
singleton, passando o nome do arquivo do banco de dados como o argumento para o NoteDatabase
construtor. A vantagem de expor o banco de dados como um singleton é que uma conexão de banco de
dados individual criada é mantida aberta enquanto o aplicativo é executado, evitando, portanto, o trabalho
de abrir e fechar o arquivo de banco de dados cada vez que uma operação de banco de dados é realizada.
Salve as alterações em App.xaml.cs escolhendo Arquivo > Salvar (ou pressionando ⌘ + S ) e feche o
arquivo.

WARNING
A tentativa de compilar o aplicativo neste ponto resultará em erros que serão corrigidos em etapas subsequentes.

9. No painel de soluções, no notas do projeto, clique duas vezes em NotesPage.xaml.cs para abri-lo. Em
seguida, substitua o OnAppearing método com o código a seguir:

protected override async void OnAppearing()


{
base.OnAppearing();

listView.ItemsSource = await App.Database.GetNotesAsync();


}

Esse código preenche a ListView com as observações armazenadas no banco de dados.


Salve as alterações em NotesPage.xaml.cs escolhendo arquivo > Salvar (ou pressionando ⌘ + S ) e
feche o arquivo.

WARNING
A tentativa de compilar o aplicativo neste ponto resultará em erros que serão corrigidos em etapas subsequentes.

10. No painel de soluções, clique duas vezes em NoteEntryPage.xaml.cs para abri-lo. Em seguida,
substitua os OnSaveButtonClicked e OnDeleteButtonClicked métodos com o código a seguir:

async void OnSaveButtonClicked(object sender, EventArgs e)


{
var note = (Note)BindingContext;
note.Date = DateTime.UtcNow;
await App.Database.SaveNoteAsync(note);
await Navigation.PopAsync();
}

async void OnDeleteButtonClicked(object sender, EventArgs e)


{
var note = (Note)BindingContext;
await App.Database.DeleteNoteAsync(note);
await Navigation.PopAsync();
}

O NoteEntryPage armazena um Note instância, que representa uma anotação única, nas BindingContext
da página. Quando o OnSaveButtonClicked manipulador de eventos é executado, o Note instância é salva
no banco de dados e o aplicativo navega de volta à página anterior. Quando o OnDeleteButtonClicked
manipulador de eventos é executado, o Note instância é excluída do banco de dados e o aplicativo navega
de volta à página anterior.
Salve as alterações em NoteEntryPage.xaml.cs escolhendo arquivo > Salvar (ou pressionando ⌘ + S ) e
feche o arquivo.
11. Compile e execute o projeto em cada plataforma. Para obter mais informações, consulte criando o guia de
início rápido.
Sobre o NotesPage pressione a + botão para navegar para o NoteEntryPage e insira uma observação.
Depois de salvar a nota o aplicativo será navegue de volta para o NotesPage.
Insira um número de observações, de comprimento variado, para observar o comportamento do aplicativo.

Próximas etapas
Neste início rápido, você aprendeu como:
Use o Gerenciador de pacotes do NuGet para adicionar um pacote do NuGet a um projeto.
Store dados localmente em um banco de dados SQLite.NET.
Para definir o estilo de aplicativo com os estilos XAML, continue para o próximo início rápido.
Avançar

Links relacionados
Notas (exemplo)
Aprofundamento de início rápido do xamarin. Forms
Definir o estilo de um aplicativo xamarin. Forms de
plataforma cruzada
12/04/2019 • 10 minutes to read • Edit Online

Baixar o exemplo
Neste início rápido, você aprenderá como:
Um aplicativo xamarin. Forms usando os estilos XAML de estilo.
O guia de início rápido explica como definir o estilo de um aplicativo de plataforma cruzada xamarin. Forms com
estilos XAML. O aplicativo final é mostrado abaixo:

Pré -requisitos
Você deve concluir com êxito a guia de início rápido anterior antes de tentar este início rápido. Como alternativa,
baixe o exemplo de início rápido anterior e usá-lo como ponto de partida para este início rápido.

Atualizar um aplicativo com o Visual Studio


1. Inicie o Visual Studio e abra a solução de notas.
2. Na Gerenciador de soluções, no notas do projeto, clique duas vezes em App. XAML para abri-lo. Em
seguida, substitua o código existente pelo código a seguir:
<?xml version="1.0" encoding="utf-8"?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Notes.App">
<Application.Resources>

<Thickness x:Key="PageMargin">20</Thickness>

<!-- Colors -->


<Color x:Key="AppBackgroundColor">WhiteSmoke</Color>
<Color x:Key="iOSNavigationBarColor">WhiteSmoke</Color>
<Color x:Key="AndroidNavigationBarColor">#2196F3</Color>
<Color x:Key="iOSNavigationBarTextColor">Black</Color>
<Color x:Key="AndroidNavigationBarTextColor">White</Color>

<!-- Implicit styles -->


<Style TargetType="{x:Type NavigationPage}">
<Setter Property="BarBackgroundColor"
Value="{OnPlatform iOS={StaticResource iOSNavigationBarColor},
Android={StaticResource AndroidNavigationBarColor}}" />
<Setter Property="BarTextColor"
Value="{OnPlatform iOS={StaticResource iOSNavigationBarTextColor},
Android={StaticResource AndroidNavigationBarTextColor}}" />
</Style>

<Style TargetType="{x:Type ContentPage}"


ApplyToDerivedTypes="True">
<Setter Property="BackgroundColor"
Value="{StaticResource AppBackgroundColor}" />
</Style>

</Application.Resources>
</Application>

Esse código define uma Thickness de valor, uma série de Color valores e estilos implícitos para o
NavigationPage e ContentPage . Observe que esses estilos, que estão no nível do aplicativo
ResourceDictionary , podem ser consumidos em todo o aplicativo. Para obter mais informações sobre
estilos de XAML, consulte estilos na aprofundamento de início rápido de xamarin. Forms.
Salve as alterações em App. XAML pressionando CTRL + Se feche o arquivo.
3. Na Gerenciador de soluções, no notas do projeto, clique duas vezes em NotesPage.xaml para abri-lo.
Em seguida, substitua o código existente pelo código a seguir:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Notes.NotesPage"
Title="Notes">
<ContentPage.Resources>
<!-- Implicit styles -->
<Style TargetType="{x:Type ListView}">
<Setter Property="BackgroundColor"
Value="{StaticResource AppBackgroundColor}" />
</Style>
</ContentPage.Resources>

<ContentPage.ToolbarItems>
<ToolbarItem Text="+"
Clicked="OnNoteAddedClicked" />
</ContentPage.ToolbarItems>

<ListView x:Name="listView"
Margin="{StaticResource PageMargin}"
ItemSelected="OnListViewItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Text}"
Detail="{Binding Date}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

</ContentPage>

Este código adiciona um estilo implícito para o ListView para o nível de página ResourceDictionary e
define o ListView.Margin propriedade com um valor definido no nível do aplicativo ResourceDictionary .
Observe que o ListView estilo implícito foi adicionado ao nível da página ResourceDictionary , porque ele
só é consumido pelo NotesPage . Para obter mais informações sobre estilos de XAML, consulte estilos na
aprofundamento de início rápido de xamarin. Forms.
Salve as alterações em NotesPage.xaml pressionando CTRL + Se feche o arquivo.
4. No painel de soluções, no notas do projeto, clique duas vezes em NoteEntryPage.xaml para abri-lo. Em
seguida, substitua o código existente pelo código a seguir:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Notes.NoteEntryPage"
Title="Note Entry">
<ContentPage.Resources>
<!-- Implicit styles -->
<Style TargetType="{x:Type Editor}">
<Setter Property="BackgroundColor"
Value="{StaticResource AppBackgroundColor}" />
</Style>

<Style TargetType="Button"
ApplyToDerivedTypes="True"
CanCascade="True">
<Setter Property="FontSize" Value="Medium" />
<Setter Property="BackgroundColor" Value="LightGray" />
<Setter Property="TextColor" Value="Black" />
<Setter Property="BorderRadius" Value="5" />
</Style>
</ContentPage.Resources>

<StackLayout Margin="{StaticResource PageMargin}">


<Editor Placeholder="Enter your note"
Text="{Binding Text}"
HeightRequest="100" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Text="Save"
Clicked="OnSaveButtonClicked" />
<Button Grid.Column="1"
Text="Delete"
Clicked="OnDeleteButtonClicked" />
</Grid>
</StackLayout>

</ContentPage>

Esse código adiciona os estilos implícitos para o Editor e Button modos de exibição para o nível de
página ResourceDictionary e define o StackLayout.Margin propriedade com um valor definido no nível do
aplicativo ResourceDictionary . Observe que o Editor e Button estilos implícitos foram adicionados ao
nível da página ResourceDictionary , porque eles são consumidos somente pelo NoteEntryPage . Para obter
mais informações sobre estilos de XAML, consulte estilos na aprofundamento de início rápido de xamarin.
Forms.
Salve as alterações em NoteEntryPage.xaml pressionando CTRL + Se feche o arquivo.
5. Compile e execute o projeto em cada plataforma. Para obter mais informações, consulte criando o guia de
início rápido.
Sobre o NotesPage pressione a + botão para navegar para o NoteEntryPage e insira uma observação.
Em cada página, observe como o estilo foi alterado de início rápido anterior.

Atualizar um aplicativo com o Visual Studio para Mac


1. Inicie o Visual Studio para Mac e abra o projeto de notas.
2. No painel de soluções, no notas do projeto, clique duas vezes em App. XAML para abri-lo. Em seguida,
substitua o código existente pelo código a seguir:
<?xml version="1.0" encoding="utf-8"?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Notes.App">
<Application.Resources>

<Thickness x:Key="PageMargin">20</Thickness>

<!-- Colors -->


<Color x:Key="AppBackgroundColor">WhiteSmoke</Color>
<Color x:Key="iOSNavigationBarColor">WhiteSmoke</Color>
<Color x:Key="AndroidNavigationBarColor">#2196F3</Color>
<Color x:Key="iOSNavigationBarTextColor">Black</Color>
<Color x:Key="AndroidNavigationBarTextColor">White</Color>

<!-- Implicit styles -->


<Style TargetType="{x:Type NavigationPage}">
<Setter Property="BarBackgroundColor"
Value="{OnPlatform iOS={StaticResource iOSNavigationBarColor},
Android={StaticResource AndroidNavigationBarColor}}" />
<Setter Property="BarTextColor"
Value="{OnPlatform iOS={StaticResource iOSNavigationBarTextColor},
Android={StaticResource AndroidNavigationBarTextColor}}" />
</Style>

<Style TargetType="{x:Type ContentPage}"


ApplyToDerivedTypes="True">
<Setter Property="BackgroundColor"
Value="{StaticResource AppBackgroundColor}" />
</Style>

</Application.Resources>
</Application>

Esse código define uma Thickness de valor, uma série de Color valores e estilos implícitos para o
NavigationPage e ContentPage . Observe que esses estilos, que estão no nível do aplicativo
ResourceDictionary , podem ser consumidos em todo o aplicativo. Para obter mais informações sobre
estilos de XAML, consulte estilos na aprofundamento de início rápido de xamarin. Forms.
Salve as alterações em App. XAML escolhendo arquivo > Salvar (ou pressionando ⌘ + S ) e feche o
arquivo.
3. Na Gerenciador de soluções, no notas do projeto, clique duas vezes em NotesPage.xaml para abri-lo.
Em seguida, substitua o código existente pelo código a seguir:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Notes.NotesPage"
Title="Notes">
<ContentPage.Resources>
<!-- Implicit styles -->
<Style TargetType="{x:Type ListView}">
<Setter Property="BackgroundColor"
Value="{StaticResource AppBackgroundColor}" />
</Style>
</ContentPage.Resources>

<ContentPage.ToolbarItems>
<ToolbarItem Text="+"
Clicked="OnNoteAddedClicked" />
</ContentPage.ToolbarItems>

<ListView x:Name="listView"
Margin="{StaticResource PageMargin}"
ItemSelected="OnListViewItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Text}"
Detail="{Binding Date}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

</ContentPage>

Este código adiciona um estilo implícito para o ListView para o nível de página ResourceDictionary e
define o ListView.Margin propriedade com um valor definido no nível do aplicativo ResourceDictionary .
Observe que o ListView estilo implícito foi adicionado ao nível da página ResourceDictionary , porque ele
só é consumido pelo NotesPage . Para obter mais informações sobre estilos de XAML, consulte estilos na
aprofundamento de início rápido de xamarin. Forms.
Salve as alterações em NotesPage.xaml escolhendo arquivo > Salvar (ou pressionando ⌘ + S ) e feche o
arquivo.
4. Na Gerenciador de soluções, no notas do projeto, clique duas vezes em NoteEntryPage.xaml para
abri-lo. Em seguida, substitua o código existente pelo código a seguir:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Notes.NoteEntryPage"
Title="Note Entry">
<ContentPage.Resources>
<!-- Implicit styles -->
<Style TargetType="{x:Type Editor}">
<Setter Property="BackgroundColor"
Value="{StaticResource AppBackgroundColor}" />
</Style>

<Style TargetType="Button"
ApplyToDerivedTypes="True"
CanCascade="True">
<Setter Property="FontSize" Value="Medium" />
<Setter Property="BackgroundColor" Value="LightGray" />
<Setter Property="TextColor" Value="Black" />
<Setter Property="BorderRadius" Value="5" />
</Style>
</ContentPage.Resources>

<StackLayout Margin="{StaticResource PageMargin}">


<Editor Placeholder="Enter your note"
Text="{Binding Text}"
HeightRequest="100" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Text="Save"
Clicked="OnSaveButtonClicked" />
<Button Grid.Column="1"
Text="Delete"
Clicked="OnDeleteButtonClicked" />
</Grid>
</StackLayout>

</ContentPage>

Esse código adiciona os estilos implícitos para o Editor e Button modos de exibição para o nível de
página ResourceDictionary e define o StackLayout.Margin propriedade com um valor definido no nível do
aplicativo ResourceDictionary . Observe que o Editor e Button estilos implícitos foram adicionados ao
nível da página ResourceDictionary , porque eles são consumidos somente pelo NoteEntryPage . Para obter
mais informações sobre estilos de XAML, consulte estilos na aprofundamento de início rápido de xamarin.
Forms.
Salve as alterações em NoteEntryPage.xaml escolhendo arquivo > Salvar (ou pressionando ⌘ + S ) e
feche o arquivo.
5. Compile e execute o projeto em cada plataforma. Para obter mais informações, consulte criando o guia de
início rápido.
Sobre o NotesPage pressione a + botão para navegar para o NoteEntryPage e insira uma observação.
Em cada página, observe como o estilo foi alterado de início rápido anterior.

Próximas etapas
Neste início rápido, você aprendeu como:
Um aplicativo xamarin. Forms usando os estilos XAML de estilo.
Para saber mais sobre os conceitos básicos do desenvolvimento de aplicativos usando o xamarin. Forms, continue
o aprofundamento do guia de início rápido.
Avançar

Links relacionados
Notas (exemplo)
Aprofundamento de início rápido do xamarin. Forms
Aprofundamento de início rápido do
xamarin. Forms
12/04/2019 • 35 minutes to read • Edit Online

No início rápido do xamarin. Forms, o aplicativo de anotações foi criado. Este artigo analisa o que
foi criado para entender os fundamentos de como os aplicativos Xamarin.Forms funcionam.

Introdução ao Visual Studio


O Visual Studio organiza o código em Soluções e Projetos. Uma solução é um contêiner que
pode conter um ou mais projetos. Um projeto pode ser um aplicativo, uma biblioteca com
suporte, um aplicativo de teste, entre outros. O aplicativo de anotações consiste em uma solução
contendo quatro projetos, conforme mostrado na seguinte captura de tela:

Os projetos são:
Notas – esse projeto é o projeto de biblioteca .NET Standard que contém todos os códigos
compartilhados e a interface do usuário compartilhada.
Notes.Android – esse projeto contém código específico do Android e é o ponto de entrada
para o aplicativo Android.
Notes.iOS – esse projeto contém código específico do iOS e é o ponto de entrada para o
aplicativo iOS.
Notes.UWP – esse projeto contém o código específico da plataforma Universal do Windows
(UWP ) e é o ponto de entrada para o aplicativo UWP.

Anatomia de um aplicativo xamarin. Forms


Captura de tela a seguir mostra o conteúdo do projeto de biblioteca .NET Standard de notas no
Visual Studio:
O projeto tem um nó Dependências que contém os nós NuGet e SDK:
NuGet – o xamarin. Forms e pacotes do NuGet sqlite-net-pcl que foram adicionados ao
projeto.
SDK – o metapacote NETStandard.Library que faz referência ao conjunto completo de
pacotes NuGet que definem o .NET Standard.

Introdução ao Visual Studio para Mac


O Visual Studio para Mac segue a prática do Visual Studio de organizar o código em Soluções e
Projetos. Uma solução é um contêiner que pode conter um ou mais projetos. Um projeto pode
ser um aplicativo, uma biblioteca com suporte, um aplicativo de teste, entre outros. O aplicativo
de anotações consiste em uma solução contendo três projetos, conforme mostrado na seguinte
captura de tela:

Os projetos são:
Notas – esse projeto é o projeto de biblioteca .NET Standard que contém todos os códigos
compartilhados e a interface do usuário compartilhada.
Notes.Android – esse projeto contém código específico do Android e é o ponto de entrada
para aplicativos Android.
Notes.iOS – esse projeto contém código específico do iOS e é o ponto de entrada para
aplicativos iOS.

Anatomia de um aplicativo xamarin. Forms


Captura de tela a seguir mostra o conteúdo do projeto de biblioteca .NET Standard de notas no
Visual Studio para Mac:
O projeto tem um nó Dependências que contém os nós NuGet e SDK:
NuGet – o xamarin. Forms e pacotes do NuGet sqlite-net-pcl que foram adicionados ao
projeto.
SDK – o metapacote NETStandard.Library que faz referência ao conjunto completo de
pacotes NuGet que definem o .NET Standard.
O projeto também consiste em vários arquivos:
Data\NoteDatabase.CS – essa classe contém o código para criar o banco de dados, ler
dados a partir dele, gravação de dados e exclua dados dele.
Models\Note.CS – essa classe define um Note modelo cujas instâncias armazenam dados
sobre cada Observação no aplicativo.
XAML – a marcação XAML para a classe App , que define um dicionário de recursos para o
aplicativo.
App.XAML.CS – o code-behind para a classe App , que é responsável por instanciar a
primeira página que será exibida pelo aplicativo em cada plataforma e por processar eventos
de ciclo de vida do aplicativo.
AssemblyInfo.cs – esse arquivo contém um atributo de aplicativo sobre o projeto, que é
aplicado no nível do assembly.
NotesPage.xaml – a marcação XAML o para o NotesPage classe, que define a interface do
usuário para a página exibida quando o aplicativo é iniciado.
NotesPage.xaml.cs – o code-behind para o NotesPage classe, que contém a lógica de
negócios que é executada quando o usuário interage com a página.
NoteEntryPage.xaml – a marcação XAML o para o NoteEntryPage classe, que define a
interface do usuário para a página exibida quando o usuário insere uma observação.
NoteEntryPage.xaml.cs – o code-behind para o NoteEntryPage classe, que contém a lógica
de negócios que é executada quando o usuário interage com a página.
Para saber mais sobre a anatomia de um aplicativo Xamarin.iOS, consulte Anatomia de um
aplicativo Xamarin.iOS. Para saber mais sobre a anatomia de um aplicativo Xamarin.Android,
consulte Anatomia de um aplicativo Xamarin.Android.

Conceitos básicos de arquitetura e aplicativo


Um aplicativo Xamarin.Forms é arquitetado da mesma forma que um aplicativo tradicional de
plataforma cruzada. O código compartilhado normalmente é colocado em uma biblioteca do
.NET Standard e aplicativos específicos de plataforma consomem o código compartilhado. O
diagrama a seguir mostra uma visão geral dessa relação para o aplicativo de anotações:

Para maximizar a reutilização de código de inicialização, os aplicativos Xamarin.Forms têm uma


única classe chamada App , que é responsável por instanciar a primeira página que será exibida
pelo aplicativo em cada plataforma, conforme mostrado no exemplo de código a seguir:
using Xamarin.Forms;

namespace Notes
{
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new NavigationPage(new NotesPage());
}
...
}
}

Esse código define a MainPage propriedade do App de classe para um NavigationPage instância
cujo conteúdo é um NotesPage instância.
Além disso, o AssemblyInfo.cs arquivo contém um atributo único aplicativo, que é aplicado no
nível de assembly:

using Xamarin.Forms.Xaml;

[assembly: XamlCompilation(XamlCompilationOptions.Compile)]

O XamlCompilation atributo ativa no compilador de XAML, para que o XAML é compilado


diretamente em linguagem intermediária. Para saber mais, consulte XAML Compilation
(Compilação de XAML ).

Iniciar o aplicativo em cada plataforma


iOS
Para iniciar a página inicial do xamarin. Forms no iOS, o projeto de Notes.iOS define o
AppDelegate classe que herda o FormsApplicationDelegate classe:

namespace Notes.iOS
{
[Register("AppDelegate")]
public partial class AppDelegate :
global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
LoadApplication(new App());
return base.FinishedLaunching(app, options);
}
}
}

A substituição FinishedLaunching inicializa a estrutura do Xamarin.Forms ao chamar o método


Init . Isso faz a implementação específica do iOS do Xamarin.Forms ser carregada no aplicativo
antes que o controlador de exibição de raiz seja definido pela chamada para o método
LoadApplication .

Android
Para iniciar a página inicial do xamarin. Forms no Android, o projeto Notes.Android inclui código
que cria um com o MainLauncher atributo, com a atividade herdando a
Activity
FormsAppCompatActivity classe:

namespace Notes.Droid
{
[Activity(Label = "Notes",
Icon = "@mipmap/icon",
Theme = "@style/MainTheme",
MainLauncher = true,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;

base.OnCreate(savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}
}
}

A substituição OnCreate inicializa a estrutura do Xamarin.Forms ao chamar o método Init . Isso


faz a implementação específica do Android do Xamarin.Forms ser carregada no aplicativo antes
de o aplicativo Xamarin.Forms ser carregado.
Plataforma Universal do Windows
Em aplicativos UWP (Plataforma Universal do Windows), o método Init que inicializa a
estrutura Xamarin.Forms é chamado da classe App :

Xamarin.Forms.Forms.Init (e);

if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
...
}

Isso faz a implementação específica de UWP do Xamarin.Forms ser carregada no aplicativo. A


página inicial do xamarin. Forms é iniciada quando o MainPage classe:

namespace Notes.UWP
{
public sealed partial class MainPage
{
public MainPage()
{
this.InitializeComponent();
this.LoadApplication(new Notes.App());
}
}
}

O aplicativo Xamarin.Forms é carregado com o método LoadApplication .


NOTE
Aplicativos da plataforma Windows universal podem ser criados com o xamarin. Forms, mas somente
usando o Visual Studio no Windows.

Interface do usuário
Há quatro grupos de controle principal usados para criar a interface do usuário de um aplicativo
xamarin. Forms:
1. Páginas – as páginas do Xamarin.Forms representam telas de aplicativos móveis de
plataforma cruzada. O aplicativo de anotações usa o ContentPage classe para exibir telas
únicas. Para saber mais sobre páginas, consulte Xamarin.Forms Pages (Páginas do
Xamarin.Forms).
2. Exibições – as exibições do Xamarin.Forms são os controles exibidos na interface do usuário,
como rótulos, botões e caixas de entrada de texto. O aplicativo de anotações concluído usa o
ListView , Editor , e Button modos de exibição. Para saber mais sobre exibições, consulte
Xamarin.Forms Views (Exibições do Xamarin.Forms).
3. Layouts – os layouts do Xamarin.Forms são contêineres usados para compor exibições em
estruturas lógicas. O aplicativo de anotações usa o StackLayout classe para organizar os
modos de exibição em uma pilha vertical e o Grid classe para organizar botões
horizontalmente. Para saber mais sobre layouts, consulte Xamarin.Forms Layouts (Layouts do
Xamarin.Forms).
4. Células – as células do Xamarin.Forms são elementos especializados usados para itens em
uma lista e descrevem como cada item em uma lista deve ser desenhado. O aplicativo de
anotações usa o TextCell para exibir dois itens para cada linha na lista. Para saber mais sobre
células, consulte Xamarin.Forms Cells (Células do Xamarin.Forms).
No tempo de execução, cada controle será mapeado para seu equivalente nativo, que é o que
será renderizado.
Layout
O aplicativo de anotações usa o StackLayout para simplificar o desenvolvimento de aplicativos
de plataforma cruzada organizando automaticamente os modos de exibição na tela,
independentemente do tamanho da tela. Os elementos filho são posicionados um após o outro,
horizontalmente ou verticalmente, na ordem em que foram adicionados. A quantidade de espaço
que o StackLayout usará dependerá de como as propriedades HorizontalOptions e
VerticalOptions forem definidas, mas por padrão o StackLayout tentará usar a tela inteira.

O código XAML a seguir mostra um exemplo do uso de um StackLayout ao layout de


NoteEntryPage :
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Notes.NoteEntryPage"
Title="Note Entry">
...
<StackLayout Margin="{StaticResource PageMargin}">
<Editor Placeholder="Enter your note"
Text="{Binding Text}"
HeightRequest="100" />
<Grid>
...
</Grid>
</StackLayout>
</ContentPage>

Por padrão o StackLayout assume uma orientação vertical. No entanto, ela pode ser alterada
para uma orientação horizontal, definindo a StackLayout.Orientation propriedade para o
StackOrientation.Horizontal membro de enumeração.

NOTE
O tamanho dos modos de exibição pode ser definido por meio de HeightRequest e WidthRequest
propriedades.

Para obter mais informações sobre a classe StackLayout , veja StackLayout.


Respondendo à interação do usuário
Um objeto definido em XAML pode acionar um evento que é processado no arquivo code-
behind. O seguinte exemplo de código mostra a OnSaveButtonClicked método no code-behind
para o NoteEntryPage classe, que é executado em resposta ao Clicked disparo de eventos no
salvar botão .

async void OnSaveButtonClicked(object sender, EventArgs e)


{
var note = (Note)BindingContext;
note.Date = DateTime.UtcNow;
await App.Database.SaveNoteAsync(note);
await Navigation.PopAsync();
}

O OnSaveButtonClicked método salva a anotação no banco de dados e navega de volta para a


página anterior.

NOTE
O arquivo code-behind de uma classe XAML pode acessar um objeto definido em XAML usando o nome
atribuído a ele com o atributo x:Name . O valor atribuído a esse atributo tem as mesmas regras que
variáveis C#, no sentido de que deve começar com uma letra ou um sublinhado e não conter espaços.

A fiação do salvamento botão para o OnSaveButtonClicked método ocorre na marcação XAML


para o NoteEntryPage classe:
<Button Text="Save"
Clicked="OnSaveButtonClicked" />

Listas
O ListView é responsável por exibir uma coleção de itens verticalmente em uma lista. Cada item
no ListView estará contido em uma única célula.
O seguinte exemplo de código mostra a ListView da NotesPage :

<ListView x:Name="listView"
Margin="{StaticResource PageMargin}"
ItemSelected="OnListViewItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Text}"
Detail="{Binding Date}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

O layout de cada linha na ListView é definido dentro de ListView.ItemTemplate elemento e usa


dados de associação para exibir todas as anotações são recuperadas pelo aplicativo. O
ListView.ItemsSource estiver definida como a fonte de dados em NotesPage.xaml.cs :

protected override async void OnAppearing()


{
base.OnAppearing();

listView.ItemsSource = await App.Database.GetNotesAsync();


}

Esse código preenche a ListView com as observações armazenadas no banco de dados.


Quando uma linha está selecionada na ListView , o ItemSelected evento é acionado. Um
manipulador de eventos, chamado OnListViewItemSelected , é executado quando o evento é
acionado:

async void OnListViewItemSelected(object sender, SelectedItemChangedEventArgs e)


{
if (e.SelectedItem != null)
{
...
}
}

O ItemSelected evento pode acessar o objeto que foi associado à célula por meio de
e.SelectedItem propriedade.
Para obter mais informações sobre o ListView da classe, consulte ListView.

Navegação
o Xamarin.Forms oferece uma série de experiências de navegação de página diferentes,
dependendo do tipo do Page sendo usado. Para ContentPage navegação de instâncias pode ser
modal ou hierárquica. Para obter informações sobre navegação modal, consulte páginas modais
do xamarin. Forms.
NOTE
As classes CarouselPage , MasterDetailPage e TabbedPage oferecem experiências de navegação
alternativas. Para obter mais informações, veja Navegação.

No painel de Navegação hierárquica, o NavigationPage classe é usada para navegar por meio de
uma pilha de ContentPage objetos, frente e para trás, conforme desejado. A classe implementa
navegação como uma pilha UEPS (último a entrar, primeiro a sair) de objetos Page . Para mover-
se de uma página para outra, um aplicativo enviará por push uma nova página para a pilha de
navegação, na qual ela se tornará a página ativa. Para retornar à página anterior, o aplicativo
removerá o item mais recente, que é a página atual da pilha de navegação, então a nova página
de nível mais alto se tornará a página ativa.
A classe NavigationPage também adicionará uma barra de navegação à parte superior da página
que exibe um título e um botão Voltar apropriado para a plataforma, que retornará à página
anterior.
A primeira página adicionada a uma pilha de navegação é conhecida como o raiz página do
aplicativo e o exemplo de código a seguir mostra como isso é feito no aplicativo de anotações:

public App ()
{
...
MainPage = new NavigationPage (new NotesPage ());
}

Todas as instâncias do ContentPage têm uma propriedade Navigation que expõe métodos para
modificar a pilha de páginas. Esses métodos devem ser invocados somente se o aplicativo incluir
um NavigationPage . Para navegar até o NoteEntryPage , é necessário invocar o método
PushAsync conforme demonstrado no exemplo de código abaixo:

await Navigation.PushAsync(new NoteEntryPage());

Isso faz com que o novo NoteEntryPage objeto a ser enviado para a pilha de navegação, em que
ele se torna a página ativa.
A página ativa pode ser removida como o item mais recente da pilha de navegação pressionando
o botão Voltar no dispositivo, independentemente de este ser um botão físico no dispositivo ou
um botão na tela. Para retornar programaticamente à página original, o objeto NoteEntryPage
deve invocar o método PopAsync , conforme demonstrado no exemplo de código abaixo:

await Navigation.PopAsync();

Para obter mais informações sobre navegação hierárquica, veja Navegação hierárquica.

Associação de dados
Vinculação de dados é usada para simplificar como um aplicativo Xamarin.Forms exibe e
interage com seus dados. Ela estabelece uma conexão entre a interface do usuário e o aplicativo
subjacente. A classe BindableObject contém a maior parte da infraestrutura para dar suporte à
vinculação de dados.
A vinculação de dados conecta dois objetos, chamados de a origem e o destino. O objeto origem
fornece os dados. O objeto destino consumirá (e geralmente exibirá) dados do objeto de origem.
Por exemplo, um Editor (destino objeto) normalmente associará sua Text propriedade para
um público string propriedade em um código -fonte objeto. O diagrama a seguir ilustra essa
relação de associação:

O principal benefício da vinculação de dados é que você não precisa se preocupar sobre a
sincronização de dados entre suas exibições e a fonte de dados. As alterações no objeto de
origem são enviadas automaticamente para o objeto de destino nos bastidores pela estrutura de
associação, enquanto as alterações no objeto de destino podem ser opcionalmente enviadas de
volta para o objeto de origem.
Estabelecimento de dados de associação é um processo em duas etapas:
A propriedade BindingContext do objeto de destino deve ser definida como a origem.
Uma associação deve ser estabelecida entre o destino e a origem. Em XAML, isso é obtido
usando a extensão de marcação Binding .

No aplicativo de anotações, o destino da associação é o Editor que exibe uma observação,


enquanto o Note instância definida como o BindingContext de NoteEntryPage é a associação
código-fonte.
O BindingContext do NoteEntryPage é definido durante a navegação de página, conforme
mostrado no exemplo de código a seguir:

async void OnNoteAddedClicked(object sender, EventArgs e)


{
await Navigation.PushAsync(new NoteEntryPage
{
BindingContext = new Note()
});
}

async void OnListViewItemSelected(object sender, SelectedItemChangedEventArgs e)


{
if (e.SelectedItem != null)
{
await Navigation.PushAsync(new NoteEntryPage
{
BindingContext = e.SelectedItem as Note
});
}
}

No OnNoteAddedClicked método, que é executado quando uma nova nota é adicionada ao


aplicativo, o BindingContext dos NoteEntryPage é definido como um novo Note instância. No
OnListViewItemSelected método, que é executado quando uma anotação existente é selecionada
na ListView , o BindingContext do NoteEntryPage é definido como selecionado Note instância,
que pode é acessada por meio do e.SelectedItem propriedade.
IMPORTANT
Embora a propriedade BindingContext de cada objeto de destino possa ser definida individualmente,
isso não é necessário. BindingContext é uma propriedade especial que é herdada por todos os seus
filhos. Portanto, quando o BindingContext no ContentPage é definido como um Note instância,
todos os filhos do ContentPage têm o mesmo BindingContext e pode associar a propriedades
públicas da Note objeto.

O Editor na NoteEntryPage , em seguida, associa ao Text propriedade do Note objeto:

<Editor Placeholder="Enter your note"


Text="{Binding Text}"
... />

Uma associação entre a propriedade Editor.Text e a propriedade Text do objeto de origem é


estabelecida. As alterações feitas de Editor serão propagadas automaticamente para o Note
objeto. Da mesma forma, se forem feitas alterações para o Note.Text propriedade, o mecanismo
de associação do xamarin. Forms também atualizará o conteúdo do Editor . Isso é conhecido
como uma associação bidirecional.
Para obter mais informações sobre associação de dados, confira Associação de Dados do
Xamarin.Forms.

Estilo
Aplicativos xamarin. Forms geralmente contêm vários elementos visuais que têm uma aparência
idêntica. Definir a aparência de cada elemento visual pode ser repetitiva e sujeito a erros. Em vez
disso, podem ser criados estilos que definem a aparência e, em seguida, aplicada aos elementos
visuais necessários.
O Style classe agrupa uma coleção de valores de propriedade em um único objeto, em seguida,
pode ser aplicado a várias instâncias do elemento visual. Estilos são armazenados em uma
ResourceDictionary , no nível do aplicativo, o nível de página ou o nível de exibição. Escolhendo
onde definir um Style impactos em que ele pode ser usado:
Style instâncias definidas no nível do aplicativo podem ser aplicadas em todo o aplicativo.
Style instâncias definidas no nível de página podem ser aplicadas para a página e seus
filhos.
Style instâncias definidas no nível de exibição podem ser aplicadas para o modo de exibição
e seus filhos.

IMPORTANT
Todos os estilos que são usados em todo o aplicativo são armazenados no dicionário de recursos do
aplicativo para evitar a duplicação. No entanto, o XAML que é específico para uma página não deve ser
incluído no dicionário de recursos do aplicativo, como os recursos então serão analisados na inicialização
do aplicativo em vez de quando exigido por uma página.

Cada Style instância contém uma coleção de um ou mais Setter objetos, com cada Setter
tendo um Property e uma Value . O Property é o nome da propriedade associável do elemento
de estilo é aplicado, e o Value é o valor que é aplicado à propriedade. O exemplo de código a
seguir mostra um estilo de NoteEntryPage :
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Notes.NoteEntryPage"
Title="Note Entry">
<ContentPage.Resources>
<!-- Implicit styles -->
<Style TargetType="{x:Type Editor}">
<Setter Property="BackgroundColor"
Value="{StaticResource AppBackgroundColor}" />
</Style>
...
</ContentPage.Resources>
...
</ContentPage>

Esse estilo é aplicado a qualquer Editor instâncias na página.


Ao criar uma Style ,o TargetType propriedade sempre é necessária.

NOTE
Definir o estilo de um aplicativo xamarin. Forms tradicionalmente é realizado usando estilos XAML. No
entanto, o xamarin. Forms também dá suporte a elementos visuais de estilo usando folhas de estilo em
cascata (CSS). Para obter mais informações, consulte aplicativos de estilo de xamarin. Forms usando
folhas de estilo em cascata (CSS).

Para obter mais informações sobre estilos XAML, consulte estilos aplicativos xamarin. Forms
usando os estilos XAML.
Fornecer estilos específicos de plataforma
O OnPlatform extensões de marcação permitem que você personalize a aparência da interface do
usuário em uma base por plataforma:

<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Notes.App">
<Application.Resources>
...
<Color x:Key="iOSNavigationBarColor">WhiteSmoke</Color>
<Color x:Key="AndroidNavigationBarColor">#2196F3</Color>
<Color x:Key="iOSNavigationBarTextColor">Black</Color>
<Color x:Key="AndroidNavigationBarTextColor">White</Color>

<Style TargetType="{x:Type NavigationPage}">


<Setter Property="BarBackgroundColor"
Value="{OnPlatform iOS={StaticResource iOSNavigationBarColor},
Android={StaticResource AndroidNavigationBarColor}}"
/>
<Setter Property="BarTextColor"
Value="{OnPlatform iOS={StaticResource iOSNavigationBarTextColor},
Android={StaticResource
AndroidNavigationBarTextColor}}" />
</Style>
...
</Application.Resources>
</Application>

Isso Style define diferentes Color valores para o BarBackgroundColor e BarTextColor


Propriedades de NavigationPage , dependendo da plataforma que está sendo usada.
Para obter mais informações sobre extensões de marcação XAML, consulte Extensões de
marcação XAML. Para obter informações sobre o OnPlatform extensão de marcação, consulte
extensão de marcação OnPlatform.

Teste e implantação
Tanto o Visual Studio para Mac quanto o Visual Studio oferecem várias opções para testar e
implantar um aplicativo. Depurar aplicativos é uma parte comum do ciclo de vida de
desenvolvimento de aplicativo e ajuda a diagnosticar problemas de código. Para saber mais,
consulte Definir um ponto de interrupção, Percorrer o código e Enviar as informações para a
janela de log.
Simuladores são um bom lugar para começar a implantar e testar um aplicativo e eles
apresentam recursos úteis para testar aplicativos. No entanto, os usuários não consumirão o
aplicativo final em um simulador, assim, os aplicativos devem ser testados em dispositivos reais
antecipadamente e com frequência. Para saber mais sobre o provisionamento de dispositivo iOS,
consulte Provisionamento de Dispositivo. Para saber mais sobre o provisionamento de
dispositivo Android, consulte Configurar o dispositivo para desenvolvimento.

Próximas etapas
Essa informação aprofundada examinou os conceitos básicos do desenvolvimento de aplicativos
usando o xamarin. Forms. As próximas etapas sugeridas incluem ler sobre as seguintes
funcionalidades:
Há quatro grupos de controle principais usados para criar a interface do usuário de um
aplicativo Xamarin.Forms. Para obter mais informações, confira Referência de controles.
A associação de dados é uma técnica para vincular propriedades de dois objetos para que as
alterações em uma propriedade sejam automaticamente refletidas na outra propriedade. Para
obter mais informações, confira Associação de dados.
O Xamarin.Forms oferece uma série de experiências de navegação de página diferentes,
dependendo do tipo de página sendo usado. Para obter mais informações, veja Navegação.
Estilos ajudam a reduzir as marcações repetitivas e permitem que a aparência de aplicativos
seja alterada com mais facilidade. Para obter mais informações, confira Definindo o estilo de
aplicativos Xamarin.Forms.
As extensões de marcação XAML estendem a eficiência e a flexibilidade do XAML permitindo
que os atributos do elemento sejam definidos de fontes que não sejam cadeias de caracteres
de texto literal. Para obter mais informações, confira Extensões de marcação XAML.
Os modelos de dados fornecem a capacidade de definir a apresentação de dados em exibições
com suporte. Para saber mais, veja Modelos de dados.
Cada página, layout e exibição é renderizado diferentemente em cada plataforma usando uma
classe Renderer , que por sua vez cria um controle nativo, organiza sua disposição na tela e
adiciona o comportamento especificado no código compartilhado. Os desenvolvedores
podem implementar suas próprias classes Renderer personalizadas para personalizar a
aparência e/ou o comportamento de um controle. Para obter mais informações, veja
Renderizadores personalizados.
Efeitos também permitem que os controles nativos em cada plataforma sejam personalizados.
Os efeitos são criados em projetos específicos da plataforma aplicando subclasses à classe
PlatformEffect e consumidos anexando-os a um controle Xamarin.Forms apropriado. Para
obter mais informações, veja Efeitos.
O código compartilhado pode acessar a funcionalidade nativa por meio da classe
DependencyService . Para obter mais informações, consulte Acessar recursos nativos com
DependencyService.
Como alternativa, veja Criando aplicativos móveis com Xamarin.Forms, um livro de Charles
Petzold, é uma ótima opção para saber mais sobre o Xamarin.Forms. O livro está disponível em
PDF ou em vários formatos de livro eletrônico.

Links relacionados
Linguagem de marcação de aplicativo extensível (XAML )
Associação de dados
Referência de Controles
Extensões de marcação XAML
Exemplos do Xamarin.Forms
Exemplos de Introdução
Referência de API de xamarin. Forms
Aprendizado autodirigido gratuito (vídeo)
Linguagem de marcação de aplicativo extensível
(XAML)
12/04/2019 • 6 minutes to read

XAML é uma linguagem de marcação declarativa que pode ser usada para definir interfaces do usuário. A
interface do usuário é definida em um arquivo XML usando a sintaxe XAML, enquanto o comportamento de
tempo de execução é definido em um arquivo code-behind separado.

Evolve 2016: Tornando-se um mestre de XAML

NOTE
Experimente o visualização padrão de XAML

Controles XAML
Todas as exibições que são definidas no xamarin. Forms podem ser referenciadas em arquivos XAML.

Noções básicas de XAML


XAML permite que os desenvolvedores definam interfaces do usuário em aplicativos xamarin. Forms usando
marcação em vez de código. XAML nunca é necessária em um programa do xamarin. Forms, mas ele é compatível
com ferramentas e geralmente é mais visualmente coerente e mais sucinta do que o código equivalente. XAML é
especialmente adequado para uso com a arquitetura de aplicativo populares Model-View -ViewModel (MVVM ):
XAML define o modo de exibição que esteja vinculado ao código do ViewModel por meio de ligações de dados
com base em XAML.

Compilação de XAML
Opcionalmente, XAML pode ser compilado direto na IL (linguagem intermediária) com o compilador XAML
(XAMLC ). Este artigo descreve como usar o XAMLC e seus benefícios.

Visualizador do XAML
O XAML pré-visualizador renderiza uma visualização dinâmica de uma página lado a lado com a marcação XAML,
permitindo que você veja sua interface do usuário renderizado conforme você digita.

Namespaces XAML
XAML usa a xmlns atributo XML para declarações de namespace. Este artigo apresenta a sintaxe do namespace
XAML e demonstra como declarar um namespace XAML para um tipo de acesso.

Esquemas personalizados de namespace do XAML


Um esquema personalizado de namespace XAML pode ser definido com o XmlnsDefinitionAttribute classe, que
especifica um mapeamento entre uma URL personalizada e um ou mais namespaces CLR. O esquema de
namespace personalizado, em seguida, pode ser usado em declarações de namespace XAML.
Prefixos recomendados de namespace do XAML
O XmlnsPrefixAttribute classe pode ser usada por autores de controle para especificar um prefixo recomendado a
ser associado a um namespace XAML, para uso do XAML.

Extensões de marcação do XAML


XAML inclui extensões de marcação para definir atributos para valores ou objetos além do que podem ser
expressas com cadeias de caracteres simples. Isso inclui a referência de constantes, propriedades estáticas e
campos, dicionários de recursos e as associações de dados.

Modificadores de campo
O x:FieldModifier atributo namespace Especifica o nível de acesso para os campos gerados para elementos
nomeados do XAML.

Passando argumentos
XAML pode ser usado para passar argumentos para os construtores não padrão ou a métodos de fábrica. Este
artigo demonstra como usar os atributos XAML que podem ser usados para passar argumentos para construtores,
para chamar métodos de fábrica e para especificar o tipo de um argumento genérico.

Propriedades associáveis
No xamarin. Forms, a funcionalidade de propriedades comuns de runtime (CLR ) de linguagem é estendida por
propriedades associáveis. Uma propriedade associável é um tipo especial de propriedade, em que o valor da
propriedade é controlado pelo sistema de propriedades de xamarin. Forms. Este artigo fornece uma introdução a
propriedades associáveis e demonstra como criar e consumi-los.

Propriedades anexadas
Uma propriedade anexada é um tipo especial de propriedade associável, definido em uma classe, mas anexado a
outros objetos e reconhecível no XAML como um atributo que contém uma classe e um nome de propriedade
separados por um período. Este artigo fornece uma introdução para propriedades anexadas e demonstra como
criar e consumi-los.

Dicionários de recurso
Recursos XAML são definições de objetos que podem ser usados mais de uma vez. Um ResourceDictionary
permite que os recursos sejam definidos em um único local e reutilizadas em todo um aplicativo xamarin. Forms.
Este artigo demonstra como criar e consumir um ResourceDictionary e como mesclar um ResourceDictionary em
outro.

Carregar XAML em tempo de execução


XAML pode ser carregado e analisado em tempo de execução com o LoadFromXaml métodos de extensão.
Controles XAML
12/04/2019 • 4 minutes to read

[![Dbaixar exemplo](~/media/shared/download.png) Baixar a amostra]


(https://developer.xamarin.com/samples/FormsGallery/)
Modos de exibição são objetos de interface do usuário, como rótulos, botões e controles deslizantes que são
normalmente conhecidos como controles ou widgets em outros ambientes de programação gráficas. As exibições
compatíveis com o xamarin. Forms todos derivam de View classe.
Todas as exibições que são definidas no xamarin. Forms podem ser referenciadas em arquivos XAML.

Modos de exibição para apresentação

BoxView
<BoxView Color="Accent"
Exibe um retângulo de uma cor específica. WidthRequest="150"
HeightRequest="150"
HorizontalOptions="Center">

API / guia

Image
<Image Source="https://aka.ms/campus.jpg"
Exibe um bitmap. Aspect="AspectFit"
HorizontalOptions="Center" />

API / guia

Rotular
<Label Text="Hello, Xamarin.Forms!"
Exibe um ou mais linhas de texto. FontSize="Large"
FontAttributes="Italic"
HorizontalTextAlignment="Center" />

API / guia
Mapa
<maps:Map ItemsSource="{Binding Locations}" />
Exibe um mapa.

API / guia

WebView
<WebView
Exibe as páginas da Web ou conteúdo HTML. Source="https://docs.microsoft.com/xamarin/"
VerticalOptions="FillAndExpand" />

API / guia

Modos de exibição que iniciam comandos

Botão
<Button Text="Click Me!"
Exibe o texto em um objeto retangular. Font="Large"
BorderWidth="1"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Clicked="OnButtonClicked" />

API / guia

ImageButton
<ImageButton Source="XamarinLogo.png"
Exibe uma imagem em um objeto retangular. HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Clicked="OnImageButtonClicked" />

API / guia

SearchBar
<SearchBar Placeholder="Xamarin.Forms Property"
Exibe uma barra de pesquisa, para executar uma pesquisa.
SearchButtonPressed="OnSearchBarButtonPressed" />

API
Modos de exibição para definir valores

Controle deslizante
<Slider Minimum="0"
Permite a seleção de um double valor de um intervalo Maximum="100"
contínuo. VerticalOptions="CenterAndExpand" />

API / guia

Passador
<Stepper Minimum="0"
Permite a seleção de um double valor de um intervalo de Maximum="10"
incremental. Increment="0.1"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />

API / guia

Alternar
<Switch IsToggled="false"
Permite a seleção de um boolean valor. HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />

API

DatePicker
<DatePicker Format="D"
Permite a seleção de uma data. VerticalOptions="CenterAndExpand" />

API / guia
TimePicker
<TimePicker Format="T"
Permite a seleção de uma hora. VerticalOptions="CenterAndExpand" />

API / guia

Modos de exibição de edição de texto

Entrada
<Entry Keyboard="Email"
Permite que uma única linha de texto a ser inserido e editadas. Placeholder="Enter email address"
VerticalOptions="CenterAndExpand" />

API / guia

Editor
<Editor VerticalOptions="FillAndExpand" />
Permite que várias linhas de texto a ser inserido e editado.

API / guia

Modos de exibição para indicar a atividade

ActivityIndicator
<ActivityIndicator IsRunning="True"
Exibe uma animação para mostrar que o aplicativo está
envolvido em uma atividade demorada, sem fornecer VerticalOptions="CenterAndExpand" />
nenhuma indicação de progresso.

API
ProgressBar
<ProgressBar Progress=".5"
Exibe uma animação para mostrar que o aplicativo está em VerticalOptions="CenterAndExpand" />
andamento através de uma atividade demorada.

API

Exibições que mostram coleções

CollectionView
<CollectionView ItemsSource="{Binding Monkeys}">
Exibe uma lista rolável de itens selecionáveis de dados, usando ItemTemplate="{StaticResource
as especificações de layout diferente. MonkeyTemplate}"
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical"
Span="2" />
</CollectionView.ItemsLayout>
</CollectionView/>

Guia

ListView
<ListView ItemsSource="{Binding Monkeys}">
Exibe uma lista rolável de itens de dados podem ser ItemTemplate="{StaticResource
selecionados. MonkeyTemplate}" />

API / guia
Seletor
<Picker Title="Select a monkey"
Exibe o item de seleção de uma lista de cadeias de caracteres TitleColor="Red">
de texto. <Picker.ItemsSource<
<x:Array Type="{x:Type x:String}">
<x:String>Baboon</x:String>
<x:String>Capuchin Monkey</x:String>
<x:String>Blue Monkey</x:String>
<x:String>Squirrel Monkey</x:String>
<x:String>Golden Lion Tamarin</x:String>
<x:String>Howler Monkey</x:String>
<x:String>Japanese Macaque</x:String>
</x:Array>
</Picker.ItemsSource>
</Picker>

API / guia

TableView
<TableView Intent="Settings">
Exibe uma lista de linhas interativas. <TableRoot>
<TableSection Title="Ring">
<SwitchCell Text="New Voice Mail" />
<SwitchCell Text="New Mail" On="true"
/>
</TableSection>
</TableRoot>
API / guia </TableView>

Links relacionados
Exemplo de xamarin. Forms FormsGallery
Exemplos do Xamarin.Forms
Documentação da API de xamarin. Forms
Noções básicas de XAML de xamarin. Forms
12/04/2019 • 7 minutes to read

[![Dbaixar exemplo](~/media/shared/download.png) Baixar a amostra]


(https://developer.xamarin.com/samples/xamarin-forms/XamlSamples/)
XAML (eXtensible Application Markup Language) permite que os desenvolvedores definam interfaces do usuário
em aplicativos Xamarin.Forms usando marcação em vez do código. XAML nunca é necessária em um programa
do xamarin. Forms, mas geralmente é mais sucinta e coerente visualmente mais que o código equivalente e
potencialmente editável. XAML é especialmente adequado para uso com a arquitetura de aplicativo popular do
MVVM (Model-View -ViewModel): XAML define o modo de exibição que esteja vinculado ao código do
ViewModel por meio de ligações de dados com base em XAML.

Conteúdo de Noções básicas XAML


Visão geral
Parte 1. Introdução ao XAML
Parte 2. Sintaxe XAML essencial
Parte 3. Extensões de marcação XAML
Parte 4. Noções básicas de vinculação de dados
Parte 5. De associação de dados a MVVM
Além desses artigos Noções básicas de XAML, você pode baixar capítulos do livro criação de aplicativos móveis
com xamarin. Forms:

Tópicos XAML são abordados mais detalhadamente nos vários capítulos do livro, incluindo:

Capítulo 7. XAML vs. Código Baixar PDF Resumo

Capítulo 8. Código e XAML em harmonia Baixar PDF Resumo

Capítulo 10. Extensões de marcação XAML Baixar PDF Resumo

Capítulo 18. MVVM Baixar PDF Resumo

Esses capítulos podem ser baixado gratuitamente.

Visão geral
XAML é uma linguagem baseada em XML criada pela Microsoft como uma alternativa ao código de programação
para instanciar e inicializando objetos e organizar os objetos em hierarquias pai-filho. XAML tem foram
adaptados para várias tecnologias dentro do .NET framework, mas encontrou sua utilidade maior na definição do
layout de interfaces do usuário dentro do Windows Presentation Foundation (WPF ), Silverlight, o tempo de
execução do Windows e o Windows Universal UWP (plataforma).
XAML também é parte do xamarin. Forms, a plataforma cruzada nativamente com base em interface de
programação para iOS, Android e UWP dispositivos móveis. Dentro do arquivo XAML, o desenvolvedor de
xamarin. Forms pode definir interfaces do usuário usando todos os o xamarin. Forms exibições, layouts e páginas,
como classes de cliente. O arquivo XAML pode ser compilado ou incorporado no executável. De qualquer forma,
as informações de XAML são analisadas no momento da compilação para localizar objetos nomeados e
novamente em tempo de execução para instanciar e inicializar objetos e para estabelecer links entre esses objetos
e o código de programação.
XAML tem várias vantagens sobre o código equivalente:
XAML geralmente é mais sucinta e legíveis que o código equivalente.
A hierarquia pai-filho inerente no XML permite que o XAML simular com maior clareza visual a hierarquia pai-
filho de objetos de interface do usuário.
XAML pode ser facilmente manuscritas por programadores, mas também serve para ser compatível com
ferramentas e geradas por ferramentas de design visual.
Obviamente, também há desvantagens, relacionadas principalmente às limitações que são intrínsecas para
linguagens de marcação:
XAML não pode conter código. Todos os manipuladores de eventos devem ser definidos em um arquivo de
código.
XAML não pode conter loops para processamento repetitivo. (No entanto, vários objetos visuais do xamarin.
Forms — mais notoriamente ListView — pode gerar vários filhos com base nos objetos no seu ItemsSource
coleção.)
XAML não pode conter processamento condicional (no entanto, uma associação de dados pode fazer
referência a um conversor de associação baseada em código que permite efetivamente que algum
processamento condicional.)
XAML geralmente não é possível instanciar classes que definem um construtor sem parâmetros. (No entanto,
há algumas vezes, uma solução alternativa para essa restrição.)
XAML geralmente não é possível chamar métodos. (Novamente, essa restrição pode, às vezes, ser superada.)
Não há ainda um designer visual para gerar o XAML em aplicativos xamarin. Forms. Todos os XAML deve ser
escrito manualmente, mas há uma XAML pré-visualizador. Os programadores novo XAML talvez queira
frequentemente compilar e executar seus aplicativos, especialmente após qualquer coisa que podem não estar
corretas, obviamente. Os desenvolvedores até mesmo com muita experiência em XAML sabem que
experimentação é gratificante.
XAML é, basicamente, XML, mas a XAML tem alguns recursos exclusivos de sintaxe. Os mais importantes são:
Elementos de propriedade
Propriedades anexadas
Extensões de marcação
Esses recursos estão não extensões XML. XAML é XML inteiramente legal. Mas esses recursos de sintaxe XAML
usam XML de maneiras exclusivas. Eles serão discutidos em detalhes nos artigos a seguir, que terminam com uma
introdução ao uso do XAML para implementar o MVVM.

Requisitos
Este artigo pressupõe que esteja familiarizado com o xamarin. Forms. Este artigo também pressupõe alguma
familiaridade com XML, inclusive a entender o uso de declarações de namespace XML e os termos elemento,
marca, e atributo.
Quando você estiver familiarizado com o xamarin. Forms e XML, começar a ler parte 1. Introdução ao XAML .

Links relacionados
XamlSamples
Criar o catálogo de aplicativos móveis
Exemplos do Xamarin.Forms
Parte 1. Introdução ao XAML
12/04/2019 • 30 minutes to read

baixar o exemplo
Em um aplicativo xamarin. Forms, o XAML é usado principalmente para definir o conteúdo visual de uma página
e funciona em conjunto com um C# arquivo code-behind.
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 modos de exibição filho e inicialização de propriedade. Dentro do arquivo
XAML, classes e propriedades são referenciadas com atributos e elementos XML e links entre a marcação e
código são estabelecidas.

Criando a solução
Para começar a editar seu primeiro arquivo XAML, use o Visual Studio ou Visual Studio para Mac para criar uma
nova solução xamarin. Forms. (Selecione a guia abaixo correspondentes ao seu ambiente.)
Visual Studio
Visual Studio para Mac
No Windows, use o Visual Studio para selecionar arquivo > Novo > projeto no menu. No novo projeto caixa
de diálogo, selecione Visual C# > plataforma cruzada à esquerda e, em seguida, aplicativo móvel (xamarin.
Forms) na lista no centro.

Selecione um local para a solução, dê um nome de XamlSamples (ou acordo com sua preferência) e pressione
Okey.
Na próxima tela, selecione a aplicativo em branco modelo e o .NET Standard estratégia de compartilhamento
de código:
Pressione Okey.
Quatro projetos são criados na solução: o XamlSamples .NET Standard library, XamlSamples.Android,
XamlSamples.iOSe a plataforma Universal do Windows solução, XamlSamples.UWP.
Depois de criar o XamlSamples solução, você talvez queira testar seu ambiente de desenvolvimento,
selecionando os vários projetos de plataforma como o projeto de inicialização da solução e criar e implantar o
aplicativo simples criado por o modelo de projeto em emuladores de telefone ou em dispositivos reais.
A menos que você precisa escrever código específico da plataforma, compartilhado XamlSamples projeto de
biblioteca .NET Standard é onde você vai gastar praticamente todo seu tempo programação. Estes artigos não
serão se aventurar fora desse projeto.
Anatomia de um arquivo XAML
Dentro de XamlSamples biblioteca .NET Standard são um par de arquivos com os seguintes nomes:
App. XAML, o arquivo XAML; e
App.XAML.CS, um C# de lógica arquivo associado ao arquivo XAML.
Você precisará clicar na seta ao lado App. XAML para ver o arquivo code-behind.
Ambos App. XAML e App.xaml.cs contribuem para uma classe denominada App que deriva de Application . A
maioria das outras classes com arquivos XAML contribuem 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 na XamlSamples projeto:
MainPage. XAML, o arquivo XAML; e
MainPage.xaml.cs, o C# arquivo code-behind.
O MainPage. XAML arquivo tem esta aparência (embora a formatação pode 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>

O namespace XML de dois ( xmlns ) declarações façam referência URIs, a primeira aparentemente no site de web
do Xamarin e o segundo da Microsoft. Não se preocupe em que ponto os URIs para a verificação. Não há nada.
Eles são simplesmente URIs pertencentes a Xamarin e a Microsoft e eles basicamente funcionam como
identificadores de versão.
A primeira declaração de namespace XML significa que marcas definidas dentro do arquivo XAML sem prefixo se
referem às classes no 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 para XAML em si e que são
compatíveis com outras implementações de XAML. No entanto, esses elementos e atributos são ligeiramente
diferentes dependendo do ano inserido no URI. Xamarin. Forms dá suporte à especificação do XAML 2009, mas
nem tudo dela.
O local declaração de namespace permite que você acesse outras classes do projeto de biblioteca do .NET
Standard.
No final da primeira marca, o x prefixo é usado para um atributo chamado Class . Porque o uso deste x
prefixo é praticamente universal para o namespace XAML, atributos XAML, como Class quase sempre são
chamados de x:Class .
O x:Classatributo especifica um nome de classe totalmente qualificado do .NET: o MainPage classe o
XamlSamples namespace. Isso significa que esse arquivo XAML define uma nova classe chamada MainPage no
XamlSamples namespace que deriva ContentPage — a marca na qual o x:Class atributo é exibido.

O x:Class atributo só pode aparecer no elemento raiz de um arquivo XAML para definir um derivada C# classe.
Esta é a classe somente novo definido no arquivo XAML. Em vez disso, tudo o que aparece no arquivo XAML é
instanciado a partir de classes existentes-las simplesmente e inicializado.
O MainPage.xaml.cs arquivo tem esta aparência (além de não utilizados using diretivas):

using Xamarin.Forms;

namespace XamlSamples
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
}
}

O MainPage classe deriva ContentPage , mas observe o partial definição de classe. Isso sugere que deve haver
outra definição de classe parcial para MainPage , mas onde ele está? E o que é isso InitializeComponent método?
Quando o Visual Studio compila o projeto, ele analisa o arquivo XAML para gerar um C# arquivo de código. Se
você olhar o XamlSamples\XamlSamples\obj\Debug diretório, você encontrará um arquivo chamado
XamlSamples.MainPage.xaml.g.cs. 'g' significa gerado. Isso é outra definição de classe parcial de MainPage
que contém a definição do InitializeComponent método chamado do MainPage construtor. Esses dois parcial
MainPage definições de classe podem ser compiladas juntos. Dependendo se o XAML é compilado ou não, o
arquivo XAML ou um formato binário do arquivo XAML é incorporado no executável.
No tempo de execução de código nas chamadas de projeto de plataforma em particular uma LoadApplication
método, passando a ele uma nova instância do App classe na biblioteca do .NET Standard. O App cria uma
instância do construtor de classe MainPage . Chama o construtor da classe 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 tudo isso junto em relações pai-
filho, anexa os manipuladores de eventos definidos no código aos eventos definido no arquivo XAML e define a
árvore resultante de objetos, como o conteúdo da página.
Embora você normalmente não precisa gastar muito tempo com arquivos de código gerados, às vezes, tempo de
execução exceções são geradas em código em arquivos gerados, portanto, você deve estar familiarizado com eles.
Quando você compilar e executar este programa, o Label elemento aparece no centro da página, como sugere o
XAML:

Para visuais mais interessantes, tudo o que você precisa é mais interessante de XAML.

Adição de novas páginas XAML


Visual Studio
Visual Studio para Mac
Para adicionar outros XAML baseado ContentPage classes ao seu projeto, selecione o XamlSamples biblioteca
.NET Standard de projeto e invoque o projeto > Adicionar Novo Item item de menu. Na parte esquerda dos
Adicionar Novo Item caixa de diálogo, selecione Visual C# e xamarin. Forms. Na lista Selecione página de
conteúdo (não página de conteúdo (C#), que cria uma página somente de código, ou exibição de conteúdo,
que não é uma página). Nomeie a página, por exemplo, HelloXamlPage.xaml:
Dois arquivos são adicionados ao projeto, HelloXamlPage.xaml e o arquivo code-behind
HelloXamlPage.xaml.cs.

Conteúdo da página de configuração


Editar o HelloXamlPage.xaml arquivo para que as marcas somente são aqueles para 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>

O ContentPage.Content marcas fazem parte da sintaxe de XAML exclusivo. Primeiro, elas podem parecer ser um
XML inválido, mas são válidas. O período não é um caractere especial em XML.
O ContentPage.Content marcas são chamadas elemento de propriedade marcas. Content é uma propriedade de
ContentPage e geralmente é definido como um modo de exibição único ou um layout com modos de exibição
filho. Normalmente propriedades tornam-se atributos em XAML, mas ele seria difícil de definir um Content de
atributo para um objeto complexo. Por esse motivo, a propriedade é expressa como um elemento XML que
consiste em nome de classe e o nome da propriedade separados por um período. Agora o Content propriedade
pode ser definida entre o ContentPage.Content marcas, como este:

<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 as classes, propriedades e XML deve ser evidente: xamarin. Forms uma classe
(como ContentPage ou Label ) aparece no arquivo XAML como um elemento XML. Propriedades da classe —
incluindo Title na ContentPage e sete propriedades de Label — normalmente são exibidos como atributos
XML.
Existem muitos atalhos para definir os valores dessas propriedades. Algumas propriedades são tipos de dados
básicos: por exemplo, o Title e Text propriedades 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 .

O 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, conversores são usados para analisar o XAML. Essas são
classes no xamarin. Forms que derivam de TypeConverter . Muitos são classes públicas, mas alguns não são. Para
esse arquivo XAML específico, várias dessas classes desempenham um papel nos bastidores:
LayoutOptionsConverter para o VerticalOptions propriedade
FontSizeConverter para o FontSize propriedade
ColorTypeConverter para o TextColor propriedade

Esses conversores regem 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, a primeira é left e right padding e o
segundo é a parte superior e inferior. Quatro números estão em ordem esquerda, superior, direita e inferior.
O LayoutOptionsConverter pode converter os nomes dos campos estáticos públicos do LayoutOptions estrutura
para valores do tipo LayoutOptions .
O FontSizeConverter pode lidar com um NamedSize membro ou um tamanho de fonte numérica.
O ColorTypeConverter aceita os nomes dos campos estáticos públicos do Color estrutura ou valores RGB
hexadecimais, com ou sem um canal alfa, precedido por um sinal numérico (#). Aqui está a sintaxe sem um canal
alfa:
TextColor="#rrggbb"

Cada uma das letras pouco é um dígito hexadecimal. Aqui está como um canal alfa está incluído:
TextColor="#aarrggbb">

Para o canal alfa, tenha em mente que FF é totalmente opaca e 00 é totalmente transparente.
Dois outros formatos permitem que você especifique apenas um 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 FF -CC -33.

Navegação de página
Quando você executa o XamlSamples programa, o MainPage é exibida. Para ver o novo HelloXamlPage você
pode definir que, como a inicialização de novo, página em de App.xaml.cs do arquivo ou navegue para a nova
página de MainPage .
Para implementar a navegação, primeiro altere o código na App.xaml.cs construtor para que um NavigationPage
objeto é criado:
public App()
{
InitializeComponent();
MainPage = new NavigationPage(new MainPage());
}

No MainPage.xaml.cs construtor, você pode criar um simples Button e use 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;
}

Definindo o Content propriedade da página substitui a configuração do Content propriedade no arquivo XAML.
Quando você compila e implanta a nova versão deste programa, um botão aparece na tela. Pressioná-lo navega
para HelloXamlPage . Aqui está a página resultante no iPhone, Android e UWP:

Você pode navegar de volta para MainPage usando o < volta botão no iOS, usando a seta para a esquerda na
parte superior da página ou na parte inferior do telefone no Android, ou na seta à esquerda na parte superior da
página no Windows 10.
Fique à vontade fazer experiências com o XAML para diferentes maneiras renderizar o Label . Se você precisar
inserir quaisquer caracteres Unicode em texto, você pode usar a sintaxe XML padrão. Por exemplo, para colocar a
saudação aspas inglesas, use:
<Label Text="&#x201C;Hello, XAML!&#x201D;" … />
Aqui está o que se parece com:

Interações de código e XAML


O HelloXamlPage exemplo contém um único Label na página, mas isso é muito incomum. A maioria dos
ContentPage derivativos conjunto a Content classificar de propriedade para um layout de alguns, como um
StackLayout . O Children propriedade do StackLayout é definido para ser do tipo IList<View> mas é realmente
um objeto do tipo ElementCollection<View> , e que a coleção pode ser preenchida com várias exibições ou outros
layouts. No XAML, essas relações pai-filho são estabelecidas com a 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á o que se parece com:
No entanto, você provavelmente considere este programa seja funcionalmente deficientes. Talvez o Slider deve
fazer com que o Label para exibir o valor atual e o Button provavelmente se destina a fazer algo dentro do
programa.
Como você verá no parte 4. Noções básicas de vinculação de dados, o trabalho de exibição de um Slider valor
usando um Label possam ser manipulados inteiramente em XAML com uma associação de dados. Mas é útil ver
a solução de código pela primeira vez. Mesmo assim, tratando o Button clique definitivamente requer código.
Isso significa que o arquivo code-behind para XamlPlusCodePage deve conter os manipuladores para o
ValueChanged eventos da 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 é necessário para o público.


Novamente no arquivo XAML, o Slider e Button marcas precisam incluir os atributos para o ValueChanged e
Clicked que fazem referência a esses manipuladores de eventos:
<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 a atribuição de um manipulador a um evento tem a mesma sintaxe atribuindo um valor a uma
propriedade.
Se o manipulador para o ValueChanged eventos do Slider usará o Label para exibir o valor atual, o
manipulador precisa fazer referência a esse objeto de código. O Label precisa de um nome, o que é especificado
com o x:Name atributo.

<Label x:Name="valueLabel"
Text="A simple Label"
Font="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />

O x prefixo do x:Name atributo indica que esse atributo é intrínseco ao XAML.


O nome atribuído para o x:Name atributo tem as mesmas regras que C# nomes de variável. Por exemplo, ele
deve começar com uma letra ou sublinhado e não conter espaços.
Agora o ValueChanged manipulador de eventos pode definir o Label para exibir a nova Slider valor. O novo
valor está disponível de argumentos do evento:

void OnSliderValueChanged(object sender, ValueChangedEventArgs args)


{
valueLabel.Text = args.NewValue.ToString("F3");
}

Ou, o manipulador foi possível obter o Slider objeto que está gerando esse evento do sender argumento e
obter o Value propriedade de que:

void OnSliderValueChanged(object sender, ValueChangedEventArgs args)


{
valueLabel.Text = ((Slider)sender).Value.ToString("F3");
}

Quando você executa o programa, o Label não exibe as Slider valor porque o ValueChanged evento ainda não
foi acionado. Mas qualquer manipulação do Slider faz com que o valor a ser exibido:
Agora, para o Button . Vamos simular uma resposta a um Clicked evento exibindo um alerta com o Text do
botão. O manipulador de eventos pode seguramente os 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 DisplayAlert método é assíncrono e devem ser precedido com o
await operador, que retorna quando o método for concluído. Porque esse método obtém o Button acionar o
evento a partir de sender argumento, o mesmo manipulador pode ser usado para vários botões.
Você já viu que um objeto definido em XAML pode acionar um evento que é processado 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 que interagem de código e XAML.

Algumas informações adicionais em como funciona o XAML pode ser obtida, examinando o recém-gerado
arquivo XamlPlusCode.xaml.g.cs, que agora inclui qualquer nome atribuído a qualquer x:Name atributo como
um campo particular. Aqui está uma versão simplificada do arquivo:

public partial class XamlPlusCodePage : ContentPage {

private Label valueLabel;

private void InitializeComponent() {


this.LoadFromXaml(typeof(XamlPlusCodePage));
valueLabel = this.FindByName<Label>("valueLabel");
}
}

A declaração desse campo permite que a variável para ser usados livremente em qualquer lugar dentro do
XamlPlusCodePage arquivo de classe parcial em sua jurisdição. Em tempo de execução, o campo é atribuído depois
que o XAML foi analisado. Isso significa que o valueLabel campo é null quando o XamlPlusCodePage construtor
começa válido, mas depois InitializeComponent é chamado.
Depois de InitializeComponent retorna controle volta para o construtor, os elementos visuais da página foram
construídos como se eles tinham instanciados e inicializados no código. O arquivo XAML não desempenha
qualquer função na classe. Você pode manipular esses objetos na página de qualquer forma que desejar, por
exemplo, adicionando modos de exibição para o StackLayout , configuração ou o Content propriedade da página
para algo mais inteiramente. Você pode "percorrer a árvore" Examinando o Content propriedade da página e os
itens a Children coleções de layouts. Você pode definir propriedades em modos de exibição acessados dessa
maneira, ou atribuir manipuladores de eventos a elas dinamicamente.
Fique à vontade. É sua página e o XAML é apenas uma ferramenta para criar seu conteúdo.

Resumo
Com essa introdução, você viu como um arquivo XAML e o arquivo de código contribuem para uma definição de
classe, e como os arquivos XAML e código interagem. Mas XAML também tem seus próprios recursos exclusivos
de sintáticos que permitem que ele seja usado de maneira muito flexível. Você pode começar a explorar em parte
2. Sintaxe XAML essencial.

Links relacionados
XamlSamples
Parte 2. Sintaxe essencial de XAML
Parte 3. Extensões de Marcação XAML
Parte 4. Conceitos básicos da associação de dados
Parte 5. De associação de dados a MVVM
Parte 2. Sintaxe XAML essencial
12/04/2019 • 17 minutes to read

baixar o exemplo
XAML é projetado principalmente para instanciar e inicializar objetos. Muitas vezes, mas propriedades devem ser
definidas para objetos complexos que não podem ser facilmente representados como cadeias de caracteres XML
e, às vezes, as propriedades definidas por uma classe devem ser definidas em uma classe filha. Essas duas
necessidades exigem os recursos de sintaxe XAML essencial de elementos de propriedade e propriedades
anexadas.

Elementos de propriedade
No XAML, as propriedades das classes normalmente são definidas como atributos XML:

<Label Text="Hello, XAML!"


VerticalOptions="Center"
FontAttributes="Bold"
FontSize="Large"
TextColor="Aqua" />

No entanto, há uma maneira alternativa de definir uma propriedade em XAML. Para tentar essa alternativa com
TextColor , primeiro exclua o existente TextColor configuração:

<Label Text="Hello, XAML!"


VerticalOptions="Center"
FontAttributes="Bold"
FontSize="Large" />

Abra o elemento vazio Label marca separando-o em marcas de início e término:

<Label Text="Hello, XAML!"


VerticalOptions="Center"
FontAttributes="Bold"
FontSize="Large">

</Label>

Dentro dessas marcas, adicione marcas de início e término que consistem em nome de classe e um nome de
propriedade separados por um período:

<Label Text="Hello, XAML!"


VerticalOptions="Center"
FontAttributes="Bold"
FontSize="Large">
<Label.TextColor>

</Label.TextColor>
</Label>

Defina o valor da propriedade como conteúdo dessas novas marcas, como este:
<Label Text="Hello, XAML!"
VerticalOptions="Center"
FontAttributes="Bold"
FontSize="Large">
<Label.TextColor>
Aqua
</Label.TextColor>
</Label>

Essas duas maneiras para especificar o TextColor propriedade são funcionalmente equivalentes, mas não use as
duas formas para a mesma propriedade, porque que seriam efetivamente ser definindo a propriedade duas vezes
e pode ser ambíguo.
Com essa nova sintaxe, terminologia úteis pode ser introduzida:
Label é um elemento de objeto. Ele é um objeto de xamarin. Forms expressado como um elemento XML.
Text , VerticalOptions , FontAttributes e FontSize são atributos da propriedade. Elas são expressadas como
atributos XML de propriedades de xamarin. Forms.
Esse trecho de código final, TextColor tornou-se um elemento de propriedade. É uma propriedade de
xamarin. Forms, mas agora é um elemento XML.
A definição de propriedade elementos podem parecer a princípio ser uma violação da sintaxe XML, mas não é. O
período não tem nenhum significado especial em XML. Um decodificador de XML, Label.TextColor é
simplesmente um elemento filho normal.
No XAML, no entanto, essa sintaxe é muito especial. Uma das regras para elementos de propriedade é que nada
mais pode aparecer no Label.TextColor marca. O valor da propriedade é sempre definido como o conteúdo
entre o elemento de propriedade marcas de início e término.
Você pode usar a sintaxe de elemento de propriedade em mais de uma propriedade:

<Label Text="Hello, XAML!"


VerticalOptions="Center">
<Label.FontAttributes>
Bold
</Label.FontAttributes>
<Label.FontSize>
Large
</Label.FontSize>
<Label.TextColor>
Aqua
</Label.TextColor>
</Label>

Ou você pode usar a sintaxe de elemento de propriedade para todas as propriedades:


<Label>
<Label.Text>
Hello, XAML!
</Label.Text>
<Label.FontAttributes>
Bold
</Label.FontAttributes>
<Label.FontSize>
Large
</Label.FontSize>
<Label.TextColor>
Aqua
</Label.TextColor>
<Label.VerticalOptions>
Center
</Label.VerticalOptions>
</Label>

A princípio, sintaxe de elemento de propriedade pode parecer uma substituição longos desnecessária para algo
bastante comparativamente simples, e nesses exemplos, certamente, esse é o caso.
No entanto, a sintaxe de elemento de propriedade se torna essencial quando o valor de uma propriedade é muito
complexo para ser expresso como uma cadeia de caracteres simple. Dentro das marcas de elemento de
propriedade, você pode criar uma instância de outro objeto e defina suas propriedades. Por exemplo, você pode
definir explicitamente uma propriedade como VerticalOptions para um LayoutOptions valor com as
configurações de propriedade:

<Label>
...
<Label.VerticalOptions>
<LayoutOptions Alignment="Center" />
</Label.VerticalOptions>
</Label>

Outro exemplo: O Grid tem duas propriedades chamadas RowDefinitions e ColumnDefinitions . Essas duas
propriedades são do tipo RowDefinitionCollection e ColumnDefinitionCollection , que são coleções de
RowDefinition e ColumnDefinition objetos. Você precisa usar a sintaxe de elemento de propriedade para definir
essas coleções.
Aqui está o início do arquivo XAML para um GridDemoPage classe, mostrando as marcas de elemento de
propriedade para o RowDefinitions e ColumnDefinitions coleções:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.GridDemoPage"
Title="Grid Demo Page">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="100" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
...
</Grid>
</ContentPage>

Observe a sintaxe abreviada para a definição de células de dimensionamento automático, as células de


configurações em estrela e alturas e larguras de pixel.

Propriedades anexadas
Você acabou de ver que o Grid exige que os elementos de propriedade para o RowDefinitions e
ColumnDefinitions coleções para definir as linhas e colunas. No entanto, também deve haver alguma forma para
o programador indicar a linha e coluna em que cada filho do Grid reside.
Dentro da marca para cada filho do Grid especifique a linha e coluna dos filho usando os seguintes atributos:
Grid.Row
Grid.Column

Os valores padrão desses atributos são 0. Você também pode indicar se um filho abrange mais de uma linha ou
coluna com esses atributos:
Grid.RowSpan
Grid.ColumnSpan

Esses dois atributos têm valores padrão de 1.


Aqui está o arquivo GridDemoPage.xaml completo:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.GridDemoPage"
Title="Grid Demo Page">

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="100" />
</Grid.RowDefinitions>

<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>

<Label Text="Autosized cell"


Grid.Row="0" Grid.Column="0"
TextColor="White"
BackgroundColor="Blue" />

<BoxView Color="Silver"
HeightRequest="0"
Grid.Row="0" Grid.Column="1" />

<BoxView Color="Teal"
Grid.Row="1" Grid.Column="0" />

<Label Text="Leftover space"


Grid.Row="1" Grid.Column="1"
TextColor="Purple"
BackgroundColor="Aqua"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center" />

<Label Text="Span two rows (or more if you want)"


Grid.Row="0" Grid.Column="2" Grid.RowSpan="2"
TextColor="Yellow"
BackgroundColor="Blue"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center" />

<Label Text="Span two columns"


Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2"
TextColor="Blue"
BackgroundColor="Yellow"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center" />

<Label Text="Fixed 100x100"


Grid.Row="2" Grid.Column="2"
TextColor="Aqua"
BackgroundColor="Red"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center" />

</Grid>
</ContentPage>

O Grid.Row e Grid.Column configurações de 0 não são necessárias, mas são geralmente é incluídas para fins de
esclarecimento.
Aqui está o que se parece com:
A julgar unicamente com a sintaxe, essas Grid.Row , Grid.Column , Grid.RowSpan , e Grid.ColumnSpan atributos
aparecem como campos estáticos ou propriedades de Grid , mas é interessante Grid não define nada chamado
Row , Column , RowSpan , ou ColumnSpan .

Em vez disso, Grid define quatro propriedades vinculáveis chamadas RowProperty , ColumnProperty ,
RowSpanProperty , e ColumnSpanProperty . Estes são tipos especiais de propriedades vinculáveis conhecidos como
propriedades anexadas. Elas são definidas pelo Grid classe definida, mas nos filhos do Grid .
Quando você deseja usar essas propriedades anexadas em código, o Grid classe fornece métodos estáticos
denominados SetRow , GetColumn e assim por diante. Mas no XAML, essas propriedades anexadas são definidas
como atributos nos filhos do Grid usando nomes de propriedades simples.
Propriedades anexadas são sempre reconhecidas em arquivos XAML como atributos, contendo uma classe e um
nome de propriedade separados por um período. Eles são chamados propriedades anexadas porque eles são
definidos por uma classe (nesse caso, Grid ), mas anexado a outros objetos (nesse caso, os filhos do Grid ).
Durante o layout, o Grid pode interrogar os valores dessas propriedades anexadas saber onde colocar cada filho.
O AbsoluteLayout classe define duas propriedades anexadas denominadas LayoutBounds e LayoutFlags . Aqui
está um padrão quadriculado realizados usando o posicionamento proporcional e os recursos de
dimensionamento do AbsoluteLayout :
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.AbsoluteDemoPage"
Title="Absolute Demo Page">

<AbsoluteLayout BackgroundColor="#FF8080">
<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="0.33, 0, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />

<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="1, 0, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />

<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="0, 0.33, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />

<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="0.67, 0.33, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />

<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="0.33, 0.67, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />

<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="1, 0.67, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />

<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="0, 1, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />

<BoxView Color="#8080FF"
AbsoluteLayout.LayoutBounds="0.67, 1, 0.25, 0.25"
AbsoluteLayout.LayoutFlags="All" />

</AbsoluteLayout>
</ContentPage>

E aqui está:
Para algo como isso, você poderá questionar a sabedoria da usando XAML. Certamente, a repetição e
regularidade do LayoutBounds retângulo sugere que ele pode ser melhor realizado no código.
Certamente, que é uma preocupação legítima e não há nenhum problema com o uso de código e marcação de
balanceamento, ao definir as interfaces do usuário. É fácil definir alguns dos elementos visuais em XAML e, em
seguida, use o construtor do arquivo code-behind para adicionar mais alguns visuais que podem ser gerados de
melhor em loops.

Propriedades de Conteúdo
Nos exemplos anteriores, o StackLayout , Grid , e AbsoluteLayout objetos são definidos com o Content
propriedade do ContentPage , e os filhos desses layouts são, na verdade, os itens no Children coleção. Embora
essas Content e Children propriedades estão em nenhum lugar no arquivo XAML.
Você certamente pode incluir a Content e Children propriedades como elementos de propriedade, como na
XamlPlusCode exemplo:
<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">
<ContentPage.Content>
<StackLayout>
<StackLayout.Children>
<Slider VerticalOptions="CenterAndExpand"
ValueChanged="OnSliderValueChanged" />

<Label x:Name="valueLabel"
Text="A simple Label"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />

<Button Text="Click Me!"


HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Clicked="OnButtonClicked" />
</StackLayout.Children>
</StackLayout>
</ContentPage.Content>
</ContentPage>

A pergunta real é: por que são esses elementos de propriedade não necessárias no arquivo XAML?
Os elementos definidos no xamarin. Forms para uso em XAML podem ter uma propriedade sinalizada no
ContentProperty atributo na classe. Se você pesquisar o ContentPage classe na documentação online do xamarin.
Forms, você verá esse atributo:

[Xamarin.Forms.ContentProperty("Content")]
public class ContentPage : TemplatedPage

Isso significa que o Content marcas de elemento de propriedade não são necessárias. Qualquer conteúdo XML
que aparece entre o início e término ContentPage marcas é considerado a ser atribuído ao Content propriedade.
StackLayout , Grid , AbsoluteLayout , e RelativeLayout todos os derivam Layout<View> , e se você pesquisar
Layout<T> na documentação do xamarin. Forms, você verá outra ContentProperty atributo:

[Xamarin.Forms.ContentProperty("Children")]
public abstract class Layout<T> : Layout ...

Que permite que o conteúdo do layout a ser adicionado automaticamente para o Children coleção sem explícita
Children marcas de elemento de propriedade.

Outras classes também têm ContentProperty definições de atributo. Por exemplo, a propriedade de conteúdo do
Label é Text . Verifique a documentação da API para outras pessoas.

Diferenças de plataforma com o OnPlatform


Em aplicativos de única página, é comum para definir o Padding propriedade na página para evitar a substituição
da barra de status do iOS. No código, você pode usar o Device.RuntimePlatform propriedade para essa finalidade:
if (Device.RuntimePlatform == Device.iOS)
{
Padding = new Thickness(0, 20, 0, 0);
}

Você também pode fazer algo semelhante em XAML usando o OnPlatform e On classes. Primeiro, inclua os
elementos de propriedade para o Padding propriedade próximo à parte superior da página:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">

<ContentPage.Padding>

</ContentPage.Padding>
...
</ContentPage>

Dentro dessas marcas incluem um OnPlatform marca. OnPlatform é uma classe genérica. Você precisa especificar
o argumento de tipo genérico, nesse caso, Thickness , que é o tipo de Padding propriedade. Felizmente, há um
atributo XAML especificamente para definir argumentos genéricos chamados x:TypeArguments . Isso deve
corresponder ao tipo da propriedade que você está configurando:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">

<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">

</OnPlatform>
</ContentPage.Padding>
...
</ContentPage>

OnPlatform tem uma propriedade chamada Platforms que é um IList de On objetos. Use as marcas de
elemento de propriedade para essa propriedade:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">

<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<OnPlatform.Platforms>

</OnPlatform.Platforms>
</OnPlatform>
</ContentPage.Padding>
...
</ContentPage>

Agora, adicione On elementos. Para cada um deles definir a Platform propriedade e o Value propriedade a
marcação para o Thickness propriedade:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">

<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<OnPlatform.Platforms>
<On Platform="iOS" Value="0, 20, 0, 0" />
<On Platform="Android" Value="0, 0, 0, 0" />
<On Platform="UWP" Value="0, 0, 0, 0" />
</OnPlatform.Platforms>
</OnPlatform>
</ContentPage.Padding>
...
</ContentPage>

Essa marcação pode ser simplificada. A propriedade de conteúdo do OnPlatform é Platforms , portanto, essas
marcas de elemento de propriedade podem ser removidas:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">

<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="0, 20, 0, 0" />
<On Platform="Android" Value="0, 0, 0, 0" />
<On Platform="UWP" Value="0, 0, 0, 0" />
</OnPlatform>
</ContentPage.Padding>
...
</ContentPage>

O Platform propriedade de On é do tipo IList<string> , portanto, você pode incluir várias plataformas, se os
valores são os mesmos:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">

<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="0, 20, 0, 0" />
<On Platform="Android, UWP" Value="0, 0, 0, 0" />
</OnPlatform>
</ContentPage.Padding>
...
</ContentPage>

Android e UWP estejam definidas para o valor padrão de Padding , que marca pode ser removida:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">

<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="0, 20, 0, 0" />
</OnPlatform>
</ContentPage.Padding>
...
</ContentPage>

Essa é a maneira padrão para definir um dependente de plataforma Padding propriedade em XAML. Se o Value
configuração não pode ser representada por uma única cadeia de caracteres, você pode definir os elementos de
propriedade para ele:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="...">

<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS">
<On.Value>
0, 20, 0, 0
</On.Value>
</On>
</OnPlatform>
</ContentPage.Padding>
...
</ContentPage>

Resumo
Com elementos de propriedade e propriedades anexadas, grande parte da sintaxe XAML básica estabelecida. No
entanto, às vezes, você precisa definir propriedades para objetos de uma maneira indireta, por exemplo, a partir
de um dicionário de recursos. Essa abordagem é abordada na próxima parte, parte 3. Extensões de marcação
XAML.

Links relacionados
XamlSamples
Parte 1. Introdução ao XAML
Parte 3. Extensões de Marcação XAML
Parte 4. Conceitos básicos da associação de dados
Parte 5. De associação de dados a MVVM
Parte 3. Extensões de marcação XAML
12/04/2019 • 21 minutes to read

baixar o exemplo
Extensões de marcação XAML constituem um recurso importante no XAML que permitem que as propriedades
sejam definidas para objetos ou valores que são referenciados indiretamente de outras fontes. Extensões de
marcação XAML são particularmente importantes para compartilhamento de objetos e fazendo referência
constantes usadas em todo um aplicativo, mas que encontrar seu utilitário maior de associações de dados.

Extensões de marcação XAML


Em geral, você deve usar XAML para definir propriedades de um objeto como valores explícitos, como uma
cadeia de caracteres, um número, um membro de enumeração ou uma cadeia de caracteres que é convertida em
um valor em segundo plano.
Às vezes, no entanto, as propriedades em vez disso, devem fazer referência a valores definidos em algum lugar
de outra ou que podem exigir um pouco processamento pelo código em tempo de execução. Para esses fins,
XAML extensões de marcação estão disponíveis.
Essas extensões de marcação XAML não são extensões do XML. XAML é XML inteiramente legal. Eles são
chamados "extensões", porque eles são apoiados por código nas classes que implementam IMarkupExtension .
Você pode escrever suas próprias extensões de marcação personalizada.
Em muitos casos, as extensões de marcação XAML são instantaneamente reconhecíveis nos arquivos XAML
porque eles aparecem como configurações de atributo delimitadas por chaves: {e}, mas, às vezes, extensões de
marcação aparecem na marcação como elementos convencionais.

Recursos compartilhados
Algumas páginas XAML contêm vários modos de exibição com propriedades definidas para os mesmos valores.
Por exemplo, várias das configurações de propriedade para esses Button objetos forem os mesmos:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.SharedResourcesPage"
Title="Shared Resources Page">

<StackLayout>
<Button Text="Do this!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
BorderWidth="3"
Rotation="-15"
TextColor="Red"
FontSize="24" />

<Button Text="Do that!"


HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
BorderWidth="3"
Rotation="-15"
TextColor="Red"
FontSize="24" />

<Button Text="Do the other thing!"


HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
BorderWidth="3"
Rotation="-15"
TextColor="Red"
FontSize="24" />

</StackLayout>
</ContentPage>

Se uma dessas propriedades precisa ser alterado, talvez você prefira fazer a alteração apenas uma vez, em vez de
três vezes. Se esse fosse o código, você provavelmente usarão constantes e os objetos estáticos somente leitura
para ajudar a manter esses valores, consistente e fácil de modificar.
No XAML, uma solução popular é armazenar esses valores ou objetos em um dicionário de recursos. O
VisualElement classe define uma propriedade chamada Resources do tipo ResourceDictionary , que é um
dicionário com chaves de tipo string e valores do tipo object . Você pode colocar os objetos nesse Dictionary
e, em seguida, referenciá-los a partir de marcação, tudo em XAML.
Para usar um dicionário de recursos em uma página, inclua um par de Resources marcas de elemento de
propriedade. É mais conveniente para colocá-las na parte superior da página:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.SharedResourcesPage"
Title="Shared Resources Page">

<ContentPage.Resources>

</ContentPage.Resources>
...
</ContentPage>

Também é necessário incluir explicitamente ResourceDictionary marcas:


<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.SharedResourcesPage"
Title="Shared Resources Page">

<ContentPage.Resources>
<ResourceDictionary>

</ResourceDictionary>
</ContentPage.Resources>
...
</ContentPage>

Agora os objetos e valores de vários tipos podem ser adicionados ao dicionário de recursos. Esses tipos devem
ser instanciáveis. Eles não podem ser classes abstratas, por exemplo. Esses tipos também devem ter um
construtor público sem parâmetros. Cada item requer uma chave de dicionário especificada com o x:Key
atributo. Por exemplo:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.SharedResourcesPage"
Title="Shared Resources Page">

<ContentPage.Resources>
<ResourceDictionary>
<LayoutOptions x:Key="horzOptions"
Alignment="Center" />

<LayoutOptions x:Key="vertOptions"
Alignment="Center"
Expands="True" />
</ResourceDictionary>
</ContentPage.Resources>
...
</ContentPage>

Esses dois itens são valores do tipo estrutura LayoutOptions e cada um tem uma chave exclusiva e uma ou duas
propriedades definidas. No código e marcação, é muito mais comum usar os campos estáticos de LayoutOptions
, mas aqui é mais conveniente definir as propriedades.
Agora, é necessário definir as HorizontalOptions e VerticalOptions propriedades desses botões para esses
recursos, e isso é feito com o StaticResource extensão de marcação XAML:

<Button Text="Do this!"


HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="3"
Rotation="-15"
TextColor="Red"
FontSize="24" />

O StaticResource extensão de marcação é sempre delimitada com chaves e inclui a chave do dicionário.
O nome StaticResourcedistingue de DynamicResource , que o xamarin. Forms também oferece suporte.
DynamicResource é para as chaves de dicionário associadas aos valores que podem ser alterados durante o
tempo de execução, enquanto StaticResource acessa os elementos do dicionário de apenas uma vez quando os
elementos na página são construídos.
Para o BorderWidth propriedade, é necessário armazenar um valor double no dicionário. XAML
convenientemente define marcas para tipos de dados comuns, como x:Double e x:Int32 :

<ContentPage.Resources>
<ResourceDictionary>
<LayoutOptions x:Key="horzOptions"
Alignment="Center" />

<LayoutOptions x:Key="vertOptions"
Alignment="Center"
Expands="True" />

<x:Double x:Key="borderWidth">
3
</x:Double>
</ResourceDictionary>
</ContentPage.Resources>

Você não precisa colocá-lo em três linhas. Essa entrada de dicionário para o ângulo de rotação usa apenas uma
linha para cima:

<ContentPage.Resources>
<ResourceDictionary>
<LayoutOptions x:Key="horzOptions"
Alignment="Center" />

<LayoutOptions x:Key="vertOptions"
Alignment="Center"
Expands="True" />

<x:Double x:Key="borderWidth">
3
</x:Double>

<x:Double x:Key="rotationAngle">-15</x:Double>
</ResourceDictionary>
</ContentPage.Resources>

Esses dois recursos podem ser referenciados da mesma forma como o LayoutOptions valores:

<Button Text="Do this!"


HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="{StaticResource borderWidth}"
Rotation="{StaticResource rotationAngle}"
TextColor="Red"
FontSize="24" />

Para recursos do tipo Color , você pode usar as mesmas representações de cadeia de caracteres que você usa ao
atribuir diretamente atributos desses tipos. Conversores de tipo são invocados quando o recurso é criado. Aqui
está um recurso do tipo Color :

<Color x:Key="textColor">Red</Color>

Programas com frequência, o conjunto de um FontSize propriedade para um membro do NamedSize


enumeração como Large . O FontSizeConverter classe funciona nos bastidores para convertê-lo em um valor
dependente de plataforma usando o Device.GetNamedSized método. No entanto, ao definir um recurso de
tamanho da fonte, faz mais sentido usar um valor numérico, mostrado aqui como um x:Double tipo:
<x:Double x:Key="fontSize">24</x:Double>

Agora todas as propriedades, exceto Text são definidos pelas configurações de recursos:

<Button Text="Do this!"


HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="{StaticResource borderWidth}"
Rotation="{StaticResource rotationAngle}"
TextColor="{StaticResource textColor}"
FontSize="{StaticResource fontSize}" />

Também é possível usar OnPlatform no dicionário de recursos para definir valores diferentes para as
plataformas. Aqui está como um OnPlatform objeto pode ser parte do dicionário de recursos para as cores de
texto diferente:

<OnPlatform x:Key="textColor"
x:TypeArguments="Color">
<On Platform="iOS" Value="Red" />
<On Platform="Android" Value="Aqua" />
<On Platform="UWP" Value="#80FF80" />
</OnPlatform>

Observe que OnPlatform obtém tanto um x:Key porque ele é um objeto no dicionário de atributo e um
x:TypeArguments atributo porque é uma classe genérica. O iOS , Android , e UWP atributos são convertidos em
Color valores quando o objeto é inicializado.

Aqui está o arquivo XAML completo final com três botões acessando seis valores compartilhados:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.SharedResourcesPage"
Title="Shared Resources Page">

<ContentPage.Resources>
<ResourceDictionary>
<LayoutOptions x:Key="horzOptions"
Alignment="Center" />

<LayoutOptions x:Key="vertOptions"
Alignment="Center"
Expands="True" />

<x:Double x:Key="borderWidth">3</x:Double>

<x:Double x:Key="rotationAngle">-15</x:Double>

<OnPlatform x:Key="textColor"
x:TypeArguments="Color">
<On Platform="iOS" Value="Red" />
<On Platform="Android" Value="Aqua" />
<On Platform="UWP" Value="#80FF80" />
</OnPlatform>

<x:Double x:Key="fontSize">24</x:Double>
</ResourceDictionary>
</ContentPage.Resources>

<StackLayout>
<Button Text="Do this!"
HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="{StaticResource borderWidth}"
Rotation="{StaticResource rotationAngle}"
TextColor="{StaticResource textColor}"
FontSize="{StaticResource fontSize}" />

<Button Text="Do that!"


HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="{StaticResource borderWidth}"
Rotation="{StaticResource rotationAngle}"
TextColor="{StaticResource textColor}"
FontSize="{StaticResource fontSize}" />

<Button Text="Do the other thing!"


HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="{StaticResource borderWidth}"
Rotation="{StaticResource rotationAngle}"
TextColor="{StaticResource textColor}"
FontSize="{StaticResource fontSize}" />

</StackLayout>
</ContentPage>

Verifique se as capturas de tela, o estilo consistentes e o estilo de dependente de plataforma:


Embora seja mais comum para definir a Resources coleção na parte superior da página, tenha em mente que o
Resources propriedade é definida por VisualElement , e você pode ter Resources coleções em outros elementos
na página. Por exemplo, tente adicionar um para o StackLayout neste exemplo:

<StackLayout>
<StackLayout.Resources>
<ResourceDictionary>
<Color x:Key="textColor">Blue</Color>
</ResourceDictionary>
</StackLayout.Resources>
...
</StackLayout>

Você descobrirá que a cor do texto dos botões agora é azul. Basicamente, sempre que o analisador XAML
encontra uma StaticResource extensão de marcação, ele pesquisa a árvore visual e usa a primeira
ResourceDictionary encontra contendo essa chave.

Um dos tipos mais comuns de objetos armazenados em dicionários de recursos é o xamarin. Forms Style , que
define uma coleção de configurações de propriedade. Estilos são discutidos neste artigo estilos.
Às vezes, os desenvolvedores de novos no XAML esteja se perguntando se eles podem colocar um elemento
visual, como Label ou Button em um ResourceDictionary . Embora seja certamente possível, ele não faz muito
sentido. A finalidade de ResourceDictionary é compartilhar objetos. Um elemento visual não pode ser
compartilhado. A mesma instância não pode aparecer duas vezes em uma única página.

A extensão de marcação X:Static


Apesar das semelhanças de seus nomes x:Static e StaticResource são muito diferentes. StaticResource
Retorna um objeto de um dicionário de recursos enquanto x:Static acessa um dos seguintes:
um campo estático público
uma propriedade estática pública
um campo constante público
um membro de enumeração.
O StaticResource extensão de marcação é suportada por implementações de XAML que definem um dicionário
de recursos, enquanto x:Static é uma parte intrínseca de XAML, como o x revela de prefixo.
Aqui estão alguns exemplos que demonstram como x:Static pode referenciar explicitamente os campos
estáticos e membros de enumeração:

<Label Text="Hello, XAML!"


VerticalOptions="{x:Static LayoutOptions.Start}"
HorizontalTextAlignment="{x:Static TextAlignment.Center}"
TextColor="{x:Static Color.Aqua}" />

Até agora, isso não seja muito impressionante. Mas o x:Static extensão de marcação pode também fazer
referência a campos estáticos ou propriedades de seu próprio código. Por exemplo, aqui está um AppConstants
classe que contém alguns campos estáticos que você talvez queira usar em várias páginas em um aplicativo:

using System;
using Xamarin.Forms;

namespace XamlSamples
{
static class AppConstants
{
public static readonly Thickness PagePadding;

public static readonly Font TitleFont;

public static readonly Color BackgroundColor = Color.Aqua;

public static readonly Color ForegroundColor = Color.Brown;

static AppConstants()
{
switch (Device.RuntimePlatform)
{
case Device.iOS:
PagePadding = new Thickness(5, 20, 5, 0);
TitleFont = Font.SystemFontOfSize(35, FontAttributes.Bold);
break;

case Device.Android:
PagePadding = new Thickness(5, 0, 5, 0);
TitleFont = Font.SystemFontOfSize(40, FontAttributes.Bold);
break;

case Device.UWP:
PagePadding = new Thickness(5, 0, 5, 0);
TitleFont = Font.SystemFontOfSize(50, FontAttributes.Bold);
break;
}
}
}
}

Para fazer referência os campos estáticos dessa classe no arquivo XAML, você precisará de uma forma de indicar
dentro do arquivo XAML em que esse arquivo está localizado. Você pode fazer isso com uma declaração de
namespace XML.
Lembre-se de que os arquivos XAML criados como parte do modelo de XAML de xamarin. Forms padrão
contêm duas declarações de namespace XML: um para acesso de classes xamarin. Forms e outro para fazer
referência a marcas e atributos intrínsecos ao XAML:

xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
Você precisará de declarações de namespace XML adicionais para acessar outras classes. Cada declaração de
namespace XML adicional define um novo prefixo. Para acessar classes locais para a biblioteca .NET Standard de
aplicativo compartilhado, como AppConstants , os programadores XAML geralmente usam o prefixo local . A
declaração de namespace deve indicar o nome do namespace CLR (Common Language Runtime), também
conhecido como o nome de namespace de .NET, que é o nome que aparece em um C# namespace definição ou
em um using diretiva:

xmlns:local="clr-namespace:XamlSamples"

Você também pode definir as declarações de namespace XML para namespaces do .NET em qualquer assembly
que faz referência a biblioteca .NET Standard. Por exemplo, aqui está uma sys prefixo para o .NET standard
System namespace, que está no mscorlib assembly, que representava uma vez "Microsoft Common Library do
objeto de tempo de execução", mas agora significa "Multilanguage padrão Objeto em tempo de execução
biblioteca comum." Como esse é outro assembly, você deve também especificar o nome do assembly, neste caso
mscorlib:

xmlns:sys="clr-namespace:System;assembly=mscorlib"

Observe que a palavra-chave clr-namespace é seguido por dois-pontos e, em seguida, o nome do namespace
.NET, seguido por um ponto e vírgula, a palavra-chave assembly , um sinal de igual e o nome do assembly.
Sim, seguido por dois pontos clr-namespace , mas o sinal de igual segue assembly . A sintaxe foi definida desta
maneira deliberadamente: A maioria das declarações de namespace XML fazem referência a um URI que
começa um nome de esquema URI, como http , que é sempre seguido por dois-pontos. O clr-namespace parte
dessa cadeia de caracteres destina-se para simular que a convenção.
As duas declarações de namespace esses estão incluídas na StaticConstantsPage exemplo. Observe que o
BoxView dimensões são definidas como Math.PI e Math.E , mas em escala por um fator de 100:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamlSamples"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
x:Class="XamlSamples.StaticConstantsPage"
Title="Static Constants Page"
Padding="{x:Static local:AppConstants.PagePadding}">

<StackLayout>
<Label Text="Hello, XAML!"
TextColor="{x:Static local:AppConstants.BackgroundColor}"
BackgroundColor="{x:Static local:AppConstants.ForegroundColor}"
Font="{x:Static local:AppConstants.TitleFont}"
HorizontalOptions="Center" />

<BoxView WidthRequest="{x:Static sys:Math.PI}"


HeightRequest="{x:Static sys:Math.E}"
Color="{x:Static local:AppConstants.ForegroundColor}"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Scale="100" />
</StackLayout>
</ContentPage>

O tamanho do resultante BoxView em relação à tela é dependente de plataforma:


Outras extensões de marcação padrão
Várias extensões de marcação são intrínsecas para XAML e com suporte em arquivos XAML de xamarin. Forms.
Alguns deles não são usadas com muita frequência, mas são essenciais quando precisar delas:
Se uma propriedade tiver um não - null valor por padrão, mas você deseja defini-lo como null , defina-a
como o {x:Null} extensão de marcação.
Se uma propriedade é do tipo Type , você pode atribuí-la a um Type usando a extensão de marcação do
objeto {x:Type someClass} .
Você pode definir matrizes em XAML usando o x:Array extensão de marcação. Esta extensão de marcação
tem um atributo obrigatório chamado Type que indica o tipo dos elementos na matriz.
O Binding extensão de marcação é discutida em parte 4. Noções básicas de vinculação de dados.

A extensão de marcação ConstraintExpression


Extensões de marcação podem ter propriedades, mas elas não são definidas como atributos XML. Em uma
extensão de marcação, as configurações de propriedade são separadas por vírgulas e sem aspas aparecer entre
chaves.
Isso pode ser ilustrado com a extensão de marcação do xamarin. Forms denominada ConstraintExpression , que
é usado com o RelativeLayout classe. Você pode especificar o local ou o tamanho de um modo de exibição filho
como uma constante, ou em relação a um pai ou de outro modo de exibição nomeado. A sintaxe do
ConstraintExpression permite que você defina a posição ou o tamanho de um modo de exibição usando um
Factor vezes, uma propriedade de outro modo de exibição, além de uma Constant . Algo mais complexo do
que isso requer código.
Aqui está um exemplo:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.RelativeLayoutPage"
Title="RelativeLayout Page">

<RelativeLayout>

<!-- Upper left -->


<BoxView Color="Red"
RelativeLayout.XConstraint=
"{ConstraintExpression Type=Constant,
Constant=0}"
RelativeLayout.YConstraint=
"{ConstraintExpression Type=Constant,
Constant=0}" />
<!-- Upper right -->
<BoxView Color="Green"
RelativeLayout.XConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Width,
Factor=1,
Constant=-40}"
RelativeLayout.YConstraint=
"{ConstraintExpression Type=Constant,
Constant=0}" />
<!-- Lower left -->
<BoxView Color="Blue"
RelativeLayout.XConstraint=
"{ConstraintExpression Type=Constant,
Constant=0}"
RelativeLayout.YConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Height,
Factor=1,
Constant=-40}" />
<!-- Lower right -->
<BoxView Color="Yellow"
RelativeLayout.XConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Width,
Factor=1,
Constant=-40}"
RelativeLayout.YConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Height,
Factor=1,
Constant=-40}" />

<!-- Centered and 1/3 width and height of parent -->


<BoxView x:Name="oneThird"
Color="Red"
RelativeLayout.XConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Width,
Factor=0.33}"
RelativeLayout.YConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Height,
Factor=0.33}"
RelativeLayout.WidthConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Width,
Factor=0.33}"
RelativeLayout.HeightConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Height,
Factor=0.33}" />

<!-- 1/3 width and height of previous -->


<BoxView Color="Blue"
RelativeLayout.XConstraint=
"{ConstraintExpression Type=RelativeToView,
ElementName=oneThird,
Property=X}"
RelativeLayout.YConstraint=
"{ConstraintExpression Type=RelativeToView,
ElementName=oneThird,
Property=Y}"
RelativeLayout.WidthConstraint=
"{ConstraintExpression Type=RelativeToView,
"{ConstraintExpression Type=RelativeToView,
ElementName=oneThird,
Property=Width,
Factor=0.33}"
RelativeLayout.HeightConstraint=
"{ConstraintExpression Type=RelativeToView,
ElementName=oneThird,
Property=Height,
Factor=0.33}" />
</RelativeLayout>
</ContentPage>

Talvez a lição mais importante que você deve executar este exemplo é a sintaxe de extensão de marcação: Sem
aspas devem aparecer dentro das chaves de uma extensão de marcação. Ao digitar a extensão de marcação em
um arquivo XAML, é natural deseja colocar os valores das propriedades entre aspas. Resista à tentação!
Aqui está o programa em execução:

Resumo
As extensões de marcação XAML mostradas aqui oferecem suporte importante para arquivos XAML. Mas talvez
seja a extensão de marcação XAML mais valiosa Binding , que será abordado na próxima parte desta série,
parte 4. Noções básicas de vinculação de dados.

Links relacionados
XamlSamples
Parte 1. Introdução ao XAML
Parte 2. Sintaxe essencial de XAML
Parte 4. Conceitos básicos da associação de dados
Parte 5. De associação de dados a MVVM
Parte 4. Noções básicas de vinculação de dados
12/04/2019 • 21 minutes to read

baixar o exemplo
Associações de dados permitem que as propriedades de dois objetos a serem vinculadas para que a alteração
de uma causa uma alteração no outro. Essa é uma ferramenta muito valiosa, e enquanto as associações de
dados podem ser definidas inteiramente no código, XAML fornece atalhos e conveniência. Consequentemente,
uma das extensões de marcação mais importantes no xamarin. Forms é associação.

Associações de dados
Associações de dados se conectar a propriedades de dois objetos, chamados de fonte e o destino. No código,
são necessárias duas etapas: O BindingContext propriedade do objeto de destino deve ser definida para o
objeto de origem e o SetBinding método (geralmente usado em conjunto com o Binding classe) deve ser
chamado no objeto de destino para associar uma propriedade desse objeto para uma propriedade da fonte
objeto.
A propriedade de destino deve ser uma propriedade vinculável, o que significa que o objeto de destino deve
derivar de BindableObject . A documentação do xamarin. Forms online indica quais propriedades são
propriedades associáveis. Uma propriedade de Label , como Text associado com a propriedade associável
TextProperty .

Na marcação, você também deve executar as mesmas duas etapas que são necessárias no código, exceto pelo
fato do Binding extensão de marcação ocupa o lugar do SetBinding chamar e o Binding classe.
No entanto, quando você define vinculações de dados no XAML, há várias maneiras de definir o
BindingContext do objeto de destino. Às vezes, ele é definido do arquivo code-behind, às vezes, usando um
StaticResource ou x:Static extensão de marcação e às vezes, como o conteúdo de BindingContext marcas
de elemento de propriedade.
Associações são usadas com mais frequência para conectar os elementos visuais de um programa com um
modelo de dados subjacente, geralmente em uma realização da arquitetura MVVM (Model-View -ViewModel)
do aplicativo, conforme discutido em parte 5. De associações de dados a MVVM, mas outros cenários são
possíveis.

Associações de exibição para exibição


Você pode definir associações de dados para vincular as propriedades de dois modos de exibição na mesma
página. Nesse caso, você definir a BindingContext do objeto de destino usando o x:Reference extensão de
marcação.
Aqui está um arquivo XAML que contém um Slider e duas Label modos de exibição, um dos quais é girado,
o Slider valor e outro que exibe o Slider valor:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.SliderBindingsPage"
Title="Slider Bindings Page">

<StackLayout>
<Label Text="ROTATION"
BindingContext="{x:Reference Name=slider}"
Rotation="{Binding Path=Value}"
FontAttributes="Bold"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />

<Slider x:Name="slider"
Maximum="360"
VerticalOptions="CenterAndExpand" />

<Label BindingContext="{x:Reference slider}"


Text="{Binding Value, StringFormat='The angle is {0:F0} degrees'}"
FontAttributes="Bold"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>

O Slider contém uma x:Name atributo que é referenciado pelas duas Label exibições usando o x:Reference
extensão de marcação.
O x:Reference extensão de associação define uma propriedade chamada Name para definir como o nome do
elemento referenciado, nesse caso, slider . No entanto, o ReferenceExtension classe que define o
x:Reference extensão de marcação também define um ContentProperty de atributo para Name , que significa
que não é explicitamente necessário. Apenas para a variedade, a primeira x:Reference inclui "nome =", mas
não o segundo:

BindingContext="{x:Reference Name=slider}"

BindingContext="{x:Reference slider}"

O Binding extensão de marcação em si pode ter várias propriedades, assim como o BindingBase e Binding
classe. O ContentProperty para Binding é Path , mas o "caminho =" parte da extensão de marcação pode ser
omitido se o caminho é o primeiro item no Binding extensão de marcação. O exemplo primeiro tem "caminho
=", mas o segundo exemplo omite a ele:

Rotation="{Binding Path=Value}"

Text="{Binding Value, StringFormat='The angle is {0:F0} degrees'}"

As propriedades podem estar em uma linha ou separados em várias linhas:

Text="{Binding Value,
StringFormat='The angle is {0:F0} degrees'}"

Fazer o que for conveniente.


Observe que o StringFormat propriedade na segunda Binding extensão de marcação. No xamarin. Forms, as
associações não executam as conversões de tipo implícito, e se você precisar exibir um objeto de cadeia de
caracteres não como uma cadeia de caracteres, você deve fornecer um conversor de tipo ou usar StringFormat
. Nos bastidores, estático String.Format método é usado para implementar StringFormat . Que é
potencialmente um problema, porque as especificações de formatação .NET envolvem chaves, que também
são usadas para delimitar as extensões de marcação. Isso cria um risco de confundir o analisador XAML. Para
evitar isso, coloque toda a cadeia de caracteres de formatação em aspas simples:

Text="{Binding Value, StringFormat='The angle is {0:F0} degrees'}"

Aqui está o programa em execução:

O modo de ligação
Uma única exibição pode ter associações de dados em várias de suas propriedades. No entanto, cada modo de
exibição pode ter apenas um BindingContext , portanto, várias associações de dados nessa exibição devem
todas as propriedades do mesmo objeto de referência.
A solução para esse e outros problemas envolve a Mode propriedade, que é definida como um membro do
BindingMode enumeração:

Default
OneWay — valores que são transferidos da origem ao destino
OneWayToSource — valores que são transferidos do destino para a fonte
TwoWay — valores são transferidos ambas as direções entre origem e destino
OneTime — dados vão da fonte para o destino, mas somente quando o BindingContext alterações

O programa a seguir demonstra um uso comum de OneWayToSource e TwoWay modos de ligação. Quatro
Slider modos de exibição destinam -se ao controle de Scale , Rotate , RotateX , e RotateY propriedades de
um Label . A princípio, parece como se essas quatro propriedades do Label deve ser destinos de vinculação
de dados, porque cada um está sendo definida um Slider . No entanto, o BindingContext de Label pode ser
apenas um objeto, e há quatro controles deslizantes diferentes.
Por esse motivo, todas as associações são definidas aparentemente com versões anteriores maneiras: O
BindingContext de cada um dos quatro controles deslizantes é definido como o Label , e as associações são
definidas no Value propriedades dos controles deslizantes. Usando o OneWayToSource e TwoWay modos, essas
Value propriedades podem definir as propriedades da fonte, que são os Scale , Rotate , RotateX , e RotateY
propriedades do Label :
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.SliderTransformsPage"
Padding="5"
Title="Slider Transforms Page">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>

<!-- Scaled and rotated Label -->


<Label x:Name="label"
Text="TEXT"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />

<!-- Slider and identifying Label for Scale -->


<Slider x:Name="scaleSlider"
BindingContext="{x:Reference label}"
Grid.Row="1" Grid.Column="0"
Maximum="10"
Value="{Binding Scale, Mode=TwoWay}" />

<Label BindingContext="{x:Reference scaleSlider}"


Text="{Binding Value, StringFormat='Scale = {0:F1}'}"
Grid.Row="1" Grid.Column="1"
VerticalTextAlignment="Center" />

<!-- Slider and identifying Label for Rotation -->


<Slider x:Name="rotationSlider"
BindingContext="{x:Reference label}"
Grid.Row="2" Grid.Column="0"
Maximum="360"
Value="{Binding Rotation, Mode=OneWayToSource}" />

<Label BindingContext="{x:Reference rotationSlider}"


Text="{Binding Value, StringFormat='Rotation = {0:F0}'}"
Grid.Row="2" Grid.Column="1"
VerticalTextAlignment="Center" />

<!-- Slider and identifying Label for RotationX -->


<Slider x:Name="rotationXSlider"
BindingContext="{x:Reference label}"
Grid.Row="3" Grid.Column="0"
Maximum="360"
Value="{Binding RotationX, Mode=OneWayToSource}" />

<Label BindingContext="{x:Reference rotationXSlider}"


Text="{Binding Value, StringFormat='RotationX = {0:F0}'}"
Grid.Row="3" Grid.Column="1"
VerticalTextAlignment="Center" />

<!-- Slider and identifying Label for RotationY -->


<Slider x:Name="rotationYSlider"
BindingContext="{x:Reference label}"
Grid.Row="4" Grid.Column="0"
Maximum="360"
Value="{Binding RotationY, Mode=OneWayToSource}" />
<Label BindingContext="{x:Reference rotationYSlider}"
Text="{Binding Value, StringFormat='RotationY = {0:F0}'}"
Grid.Row="4" Grid.Column="1"
VerticalTextAlignment="Center" />
</Grid>
</ContentPage>

As associações em três da Slider modos de exibição são OneWayToSource , o que significa que o Slider valor
faz com que uma alteração na propriedade do seu BindingContext , que é o Label chamado label . Esses três
Slider modos de exibição causam alterações para o Rotate , RotateX , e RotateY propriedades do Label .

No entanto, a associação para o Scale é de propriedade TwoWay . Isso ocorre porque o Scale propriedade
tem um valor padrão de 1 e usando um TwoWay associação faz com que o Slider inicial do valor a ser
definido em 1 em vez de 0. Se essa associação foram OneWayToSource , o Scale propriedade inicialmente seria
definida como 0 do Slider valor padrão. O Label não seria visível e que pode causar alguma confusão ao
usuário.

NOTE
O VisualElement classe também tem ScaleX e ScaleY propriedades, que dimensionarem o VisualElement no
eixo x e y respectivamente.

Associações e coleções
Nada ilustra o poder do XAML e associações de dados melhores do que com um modelo ListView .
ListView define uma ItemsSource propriedade do tipo IEnumerable , e exibe os itens dessa coleção. Esses
itens podem ser objetos de qualquer tipo. Por padrão, ListView usa o ToString método de cada item para
exibir o item. Às vezes, é isso que você deseja, mas em muitos casos, ToString retorna somente o nome de
classe totalmente qualificado do objeto.
No entanto, os itens a ListView coleção pode ser exibida como quiser com o uso de um modelo, que envolve
uma classe que deriva de Cell . O modelo for clonado para todos os itens a ListView , e as associações de
dados que foram definidas no modelo são transferidas para os clones individuais.
Com muita frequência, você desejará criar uma célula personalizada para esses itens usando o ViewCell
classe. Esse processo é um pouco confuso no código, mas no XAML torna-se muito simples.
O XamlSamples projeto há também uma classe chamada NamedColor . Cada NamedColor objeto tem Name e
FriendlyName propriedades do tipo string e um Color propriedade do tipo Color . Além disso, NamedColor
tem 141 campos estáticos somente leitura do tipo Color correspondente para as cores definidas no xamarin.
Forms Color classe. Um construtor estático cria um IEnumerable<NamedColor> coleção que contém NamedColor
objetos correspondentes a esses campos estáticos e o atribui a seu público estático All propriedade.
Configuração estática NamedColor.All propriedade para o ItemsSource de uma ListView é fácil usando o
x:Static extensão de marcação:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamlSamples;assembly=XamlSamples"
x:Class="XamlSamples.ListViewDemoPage"
Title="ListView Demo Page">

<ListView ItemsSource="{x:Static local:NamedColor.All}" />

</ContentPage>

A exibição resultante estabelece que os itens são realmente do tipo XamlSamples.NamedColor :

Não é o máximo de informações, mas o ListView é rolável e selecionável.


Para definir um modelo para os itens, você desejará separar a ItemTemplate a propriedade como um elemento
de propriedade e defini-lo como um DataTemplate , que, em seguida, referencia um ViewCell . Para o View
propriedade do ViewCell você pode definir um layout de uma ou mais exibições para exibir cada item. Aqui
está um exemplo simples:

<ListView ItemsSource="{x:Static local:NamedColor.All}">


<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Label Text="{Binding FriendlyName}" />
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
O Label é definido como o View propriedade do ViewCell . (O ViewCell.View marcas não são necessárias
porque o View é a propriedade de conteúdo do ViewCell .) Essa marcação exibe a FriendlyName propriedade
de cada NamedColor objeto:

Muito melhor. Agora tudo o que precisamos é aprimorar o modelo de item com mais informações e a cor real.
Para dar suporte a esse modelo, alguns valores e os objetos foram definidos no dicionário de recursos da
página:

<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.ListViewDemoPage"
Title="ListView Demo Page">

<ContentPage.Resources>
<ResourceDictionary>
<OnPlatform x:Key="boxSize"
x:TypeArguments="x:Double">
<On Platform="iOS, Android, UWP" Value="50" />
</OnPlatform>

<OnPlatform x:Key="rowHeight"
x:TypeArguments="x:Int32">
<On Platform="iOS, Android, UWP" Value="60" />
</OnPlatform>

<local:DoubleToIntConverter x:Key="intConverter" />

</ResourceDictionary>
</ContentPage.Resources>

<ListView ItemsSource="{x:Static local:NamedColor.All}"


RowHeight="{StaticResource rowHeight}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="5, 5, 0, 5"
Orientation="Horizontal"
Spacing="15">

<BoxView WidthRequest="{StaticResource boxSize}"


HeightRequest="{StaticResource boxSize}"
Color="{Binding Color}" />

<StackLayout Padding="5, 0, 0, 0"


VerticalOptions="Center">

<Label Text="{Binding FriendlyName}"


FontAttributes="Bold"
FontSize="Medium" />

<StackLayout Orientation="Horizontal"
Spacing="0">
<Label Text="{Binding Color.R,
Converter={StaticResource intConverter},
ConverterParameter=255,
StringFormat='R={0:X2}'}" />

<Label Text="{Binding Color.G,


Converter={StaticResource intConverter},
ConverterParameter=255,
StringFormat=', G={0:X2}'}" />

<Label Text="{Binding Color.B,


Converter={StaticResource intConverter},
ConverterParameter=255,
StringFormat=', B={0:X2}'}" />
</StackLayout>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>

Observe o uso de OnPlatform para definir o tamanho de um BoxView e a altura do ListView linhas. Embora
os valores para todas as plataformas são os mesmos, a marcação pode facilmente ser adaptada para outros
valores ajustar a exibição.

Conversores de valor de associação


Anterior demonstração de ListView arquivo XAML exibe o indivíduo R , G , e B propriedades do xamarin.
Forms Color estrutura. Essas propriedades são do tipo double e intervalo de 0 a 1. Se você quiser exibir os
valores hexadecimais, você não pode simplesmente usar StringFormat com uma especificação de formatação
"X2". Isso funciona apenas para números inteiros e Além disso, o double valores precisam ser multiplicado
por 255.
Esse pequeno problema foi resolvido com uma conversor de valor, também chamado um conversor de
associação. Essa é uma classe que implementa o IValueConverter interface, o que significa que ele tem dois
métodos chamados Convert e ConvertBack . O Convert método é chamado quando um valor é transferido da
origem para destino; o ConvertBack método é chamado para transferências de destino a fonte no
OneWayToSource ou TwoWay associações:
using System;
using System.Globalization;
using Xamarin.Forms;

namespace XamlSamples
{
class DoubleToIntConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
double multiplier;

if (!Double.TryParse(parameter as string, out multiplier))


multiplier = 1;

return (int)Math.Round(multiplier * (double)value);


}

public object ConvertBack(object value, Type targetType,


object parameter, CultureInfo culture)
{
double divider;

if (!Double.TryParse(parameter as string, out divider))


divider = 1;

return ((double)(int)value) / divider;


}
}
}

O ConvertBack método não desempenham um papel nesse programa porque as associações são apenas uma
maneira de origem ao destino.
Uma associação faz referência a um conversor de associação com o Converter propriedade. Um conversor de
associação também pode aceitar um parâmetro especificado com o ConverterParameter propriedade. Para
alguns versatilidade, isso é como o multiplicador é especificado. O conversor de associação verifica se o
parâmetro de conversor para válido double valor.
O conversor é instanciado no dicionário de recursos para que ele possa ser compartilhado entre várias
associações:

<local:DoubleToIntConverter x:Key="intConverter" />

Associações de dados de três fazer referência a essa única instância. Observe que o Binding extensão de
marcação contém inserida StaticResource extensão de marcação:

<Label Text="{Binding Color.R,


Converter={StaticResource intConverter},
ConverterParameter=255,
StringFormat='R={0:X2}'}" />

Aqui está o resultado:


O ListView é bastante sofisticados em lidar com alterações que podem ocorrer dinamicamente nos dados
subjacentes, mas somente se você seguir etapas específicas. Se a coleção de itens atribuídos à ItemsSource
propriedade do ListView alterações durante o tempo de execução — que, se itens podem ser adicionados a
ou removido da coleção — use um ObservableCollection classe para esses itens. ObservableCollection
implementa o INotifyCollectionChanged interface, e ListView instalará um manipulador para o
CollectionChanged eventos.

Se as propriedades dos itens em si são alteradas durante o tempo de execução, então os itens na coleção
devem implementar o INotifyPropertyChanged alterações de interface e o sinal para valores de propriedade
usando o PropertyChanged eventos. Isso é demonstrado na próxima parte desta série, parte 5. De associação
de dados a MVVM.

Resumo
Associações de dados fornecem um mecanismo poderoso para vincular as propriedades entre dois objetos
dentro de uma página ou entre objetos visuais e os dados subjacentes. Mas quando o aplicativo começa a
trabalhar com fontes de dados, um padrão de arquitetura de aplicativo populares começa a surgir como um
paradigma úteis. Isso é abordado em parte 5. De associações de dados a MVVM.

Links relacionados
XamlSamples
Parte 1. Introdução ao XAML (amostra)
Parte 2. Sintaxe essencial de XAML (amostra)
Parte 3. Extensões de marcação de XAML (amostra)
Parte 5. De associação de dados a MVVM (amostra)
Parte 5. De associações de dados a MVVM
12/04/2019 • 21 minutes to read

baixar o exemplo
O padrão de arquitetura do Model-View -ViewModel (MVVM ) foi inventado com XAML em mente. O padrão
impõe uma separação entre três camadas de software — a interface do usuário XAML, chamada de exibição;
os dados subjacentes, chamados de modelo; e um intermediário entre o modo de exibição e o modelo,
chamado o ViewModel. O View e ViewModel são frequentemente conectadas por meio de ligações de dados
definidas no arquivo XAML. O BindingContext para o modo de exibição geralmente é uma instância do
ViewModel.

Um ViewModel Simple
Como uma introdução aos ViewModels, vamos primeiro examinar um programa sem uma. Anteriormente,
você viu como definir uma nova declaração de namespace XML para permitir que um arquivo XAML para
classes de referência em outros assemblies. Este é um programa que define uma declaração de namespace
XML para o System namespace:

xmlns:sys="clr-namespace:System;assembly=mscorlib"

O programa pode usar x:Static para obter a data e hora atuais do estático DateTime.Now propriedade e
defina-as DateTime de valor para o BindingContext em um StackLayout :

<StackLayout BindingContext="{x:Static sys:DateTime.Now}" …>

BindingContext é uma propriedade muito especial: quando você define o BindingContext em um elemento, ela
é herdada por todos os filhos desse elemento. Isso significa que todos os filhos do StackLayout ter esse
mesmo BindingContext , e podem conter associações simples às propriedades desse objeto.
No DateTime One-Shot programa, dois dos filhos contém associações a propriedades desse DateTime valor,
mas dois outros filhos contenham associações que parecem estar faltando um caminho de associação. Isso
significa que o DateTime próprio valor é usado para o StringFormat :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
x:Class="XamlSamples.OneShotDateTimePage"
Title="One-Shot DateTime Page">

<StackLayout BindingContext="{x:Static sys:DateTime.Now}"


HorizontalOptions="Center"
VerticalOptions="Center">

<Label Text="{Binding Year, StringFormat='The year is {0}'}" />


<Label Text="{Binding StringFormat='The month is {0:MMMM}'}" />
<Label Text="{Binding Day, StringFormat='The day is {0}'}" />
<Label Text="{Binding StringFormat='The time is {0:T}'}" />

</StackLayout>
</ContentPage>
É claro, o grande problema é que a data e hora são definidos após a criação de quando a página é pela primeira
vez e nunca alteração:

Um arquivo XAML pode exibir um relógio que sempre mostra a hora atual, mas ele precisa de algum código
para ajudar. Ao pensar em termos de MVVM, o Model e ViewModel são classes escritas inteiramente no
código. O modo de exibição geralmente é um arquivo XAML que faz referência a propriedades definidas no
ViewModel por meio de ligações de dados.
Um modelo apropriado é com ignorância de ViewModel e um ViewModel adequado é com ignorância da
exibição. No entanto, com muita frequência um programador personalizam os tipos de dados expostos pelo
ViewModel para os tipos de dados associados a interfaces de usuário específico. Por exemplo, se um modelo de
acessar um banco de dados que contém cadeias de caracteres do caractere de 8 bits ASCII, o ViewModel
precisa converter entre essas cadeias de caracteres para cadeias de caracteres Unicode para acomodar o uso
exclusivo do Unicode na interface do usuário.
Nos exemplos simples do MVVM (como aqueles mostrados aqui), geralmente, não há nenhum modelo e o
padrão envolve apenas um modo de exibição e ViewModel vinculado com associações de dados.
Aqui está um ViewModel para um relógio com apenas uma única propriedade chamada DateTime , mas quais
atualizações que DateTime propriedade cada segundo:
using System;
using System.ComponentModel;
using Xamarin.Forms;

namespace XamlSamples
{
class ClockViewModel : INotifyPropertyChanged
{
DateTime dateTime;

public event PropertyChangedEventHandler PropertyChanged;

public ClockViewModel()
{
this.DateTime = DateTime.Now;

Device.StartTimer(TimeSpan.FromSeconds(1), () =>
{
this.DateTime = DateTime.Now;
return true;
});
}

public DateTime DateTime


{
set
{
if (dateTime != value)
{
dateTime = value;

if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("DateTime"));
}
}
}
get
{
return dateTime;
}
}
}
}

ViewModels geralmente implementa o INotifyPropertyChanged interface, o que significa que a classe dispara
um PropertyChanged evento sempre que uma de suas propriedades é alterada. O mecanismo de ligação de
dados no xamarin. Forms anexa um manipulador a este PropertyChanged eventos para que ele possa ser
notificado quando uma propriedade é alterada e mantenha o destino atualizado com o novo valor.
Um relógio com base nesse ViewModel pode ser tão simple como este:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamlSamples;assembly=XamlSamples"
x:Class="XamlSamples.ClockPage"
Title="Clock Page">

<Label Text="{Binding DateTime, StringFormat='{0:T}'}"


FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="Center">
<Label.BindingContext>
<local:ClockViewModel />
</Label.BindingContext>
</Label>
</ContentPage>

Observe como o ClockViewModel é definido como o BindingContext da Label usando marcas de elemento de
propriedade. Como alternativa, você pode instanciar a ClockViewModel em um Resources coleção e defini-lo
como o BindingContext por meio de um StaticResource extensão de marcação. Ou então, o arquivo code-
behind pode instanciar o ViewModel.
O Binding extensão de marcação na Text propriedade da Label formatos o DateTime propriedade. Aqui
está a exibição:

Também é possível acessar as propriedades individuais do DateTime propriedade de ViewModel, separando as


propriedades com períodos:

<Label Text="{Binding DateTime.Second, StringFormat='{0}'}" … >

MVVM interativo
MVVM é frequentemente usada com ligações de dados bidirecional para uma exibição interativa com base em
um modelo de dados subjacente.
Aqui está uma classe chamada HslViewModel que converte um Color valor na Hue , Saturation ,e Luminosity
valores e vice-versa:

using System;
using System.ComponentModel;
using Xamarin.Forms;
using Xamarin.Forms;

namespace XamlSamples
{
public class HslViewModel : INotifyPropertyChanged
{
double hue, saturation, luminosity;
Color color;

public event PropertyChangedEventHandler PropertyChanged;

public double Hue


{
set
{
if (hue != value)
{
hue = value;
OnPropertyChanged("Hue");
SetNewColor();
}
}
get
{
return hue;
}
}

public double Saturation


{
set
{
if (saturation != value)
{
saturation = value;
OnPropertyChanged("Saturation");
SetNewColor();
}
}
get
{
return saturation;
}
}

public double Luminosity


{
set
{
if (luminosity != value)
{
luminosity = value;
OnPropertyChanged("Luminosity");
SetNewColor();
}
}
get
{
return luminosity;
}
}

public Color Color


{
set
{
if (color != value)
{
color = value;
OnPropertyChanged("Color");

Hue = value.Hue;
Saturation = value.Saturation;
Luminosity = value.Luminosity;
}
}
get
{
return color;
}
}

void SetNewColor()
{
Color = Color.FromHsla(Hue, Saturation, Luminosity);
}

protected virtual void OnPropertyChanged(string propertyName)


{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

Altera para o Hue , Saturation , e Luminosity propriedades causa o Color propriedade a ser alterada e as
alterações Color faz com que as outras três propriedades alterar. Isso pode parecer um loop infinito, exceto
que a classe não chamar o PropertyChanged evento, a menos que a propriedade realmente foram alterados.
Isso acaba com o loop de comentários caso contrário incontrolável.
Contém o arquivo XAML a seguir um BoxView cujos Color propriedade está associada a Color propriedade
de ViewModel e três Slider e três Label modos de exibição associado ao Hue , Saturation e Luminosity
propriedades:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamlSamples;assembly=XamlSamples"
x:Class="XamlSamples.HslColorScrollPage"
Title="HSL Color Scroll Page">
<ContentPage.BindingContext>
<local:HslViewModel Color="Aqua" />
</ContentPage.BindingContext>

<StackLayout Padding="10, 0">


<BoxView Color="{Binding Color}"
VerticalOptions="FillAndExpand" />

<Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}"


HorizontalOptions="Center" />

<Slider Value="{Binding Hue, Mode=TwoWay}" />

<Label Text="{Binding Saturation, StringFormat='Saturation = {0:F2}'}"


HorizontalOptions="Center" />

<Slider Value="{Binding Saturation, Mode=TwoWay}" />

<Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}"


HorizontalOptions="Center" />

<Slider Value="{Binding Luminosity, Mode=TwoWay}" />


</StackLayout>
</ContentPage>
A associação em cada Label é o padrão OneWay . Ele só precisa para exibir o valor. Mas a associação em cada
Slider é TwoWay . Isso permite que o Slider ser inicializados do ViewModel. Observe que o Color estiver
definida como Aqua quando o ViewModel é instanciado. Mas uma alteração no Slider também precisa
definir um novo valor para a propriedade no ViewModel, que, em seguida, calcula uma nova cor.

Comandos com ViewModels


Em muitos casos, o padrão MVVM é restrito à manipulação de itens de dados: objetos de interface do usuário
na exibição de objetos de dados no ViewModel em paralelo.
No entanto, às vezes, o modo de exibição precisa conter botões que disparam várias ações no ViewModel. Mas
o ViewModel não deve conter Clicked manipuladores para os botões porque o que seria vincular o
ViewModel para um paradigma de interface de usuário específica.
Para permitir que ViewModels ser mais independente de objetos de interface do usuário específico, mas ainda
permitir que métodos sejam chamados dentro do ViewModel, uma comando interface existe. Essa interface de
comando é suportado pelos seguintes elementos no xamarin. Forms:
Button
MenuItem
ToolbarItem
SearchBar
TextCell (e, portanto, também ImageCell )
ListView
TapGestureRecognizer

Com exceção do SearchBar e ListView elemento, esses elementos definem duas propriedades:
Command do tipo System.Windows.Input.ICommand
CommandParameter do tipo Object

O SearchBar define SearchCommand e SearchCommandParameter propriedades, enquanto o ListView define uma


RefreshCommand propriedade do tipo ICommand .
O ICommand interface define dois métodos e um evento:
void Execute(object arg)
bool CanExecute(object arg)
event EventHandler CanExecuteChanged

O ViewModel pode definir as propriedades de tipo ICommand . Em seguida, você pode associar essas
propriedades para o Command propriedade de cada Button ou outro elemento, ou talvez uma exibição
personalizada que implementa essa interface. Opcionalmente, você pode definir as CommandParameter
propriedade para identificar individuais Button objetos (ou outros elementos) que estão associados a essa
propriedade de ViewModel. Internamente, o Button chamadas a Execute método sempre que o usuário toca
o Button , passando para o Execute método seu CommandParameter .
O CanExecute método e CanExecuteChanged são usados para casos em que um Button tap pode ser válido no
momento, caso em que o Button deve desabilitar em si. O Button chamadas CanExecute quando o Command
propriedade é definida pela primeira vez e sempre que o CanExecuteChanged evento é disparado. Se
CanExecute retorna false , o Button desabilita a mesmo e não gera Execute chamadas.

Para obter ajuda sobre como adicionar comandos aos seus ViewModels, xamarin. Forms define duas classes
que implementam ICommand : Command e Command<T> onde T é o tipo dos argumentos para Execute e
CanExecute . Essas duas classes definem vários construtores além de um ChangeCanExecute método que o
ViewModel pode chamar para forçar o Command objeto para acionar o CanExecuteChanged eventos.
Aqui está um ViewModel para um teclado simple que é destinado para inserir números de telefone. Observe
que o Execute e CanExecute método são definidos como diretamente de funções lambda no construtor:

using System;
using System.ComponentModel;
using System.Windows.Input;
using Xamarin.Forms;

namespace XamlSamples
{
class KeypadViewModel : INotifyPropertyChanged
{
string inputString = "";
string displayText = "";
char[] specialChars = { '*', '#' };

public event PropertyChangedEventHandler PropertyChanged;

// Constructor
public KeypadViewModel()
{
AddCharCommand = new Command<string>((key) =>
{
// Add the key to the input string.
InputString += key;
});

DeleteCharCommand = new Command(() =>


{
// Strip a character from the input string.
InputString = InputString.Substring(0, InputString.Length - 1);
},
() =>
{
// Return true if there's something to delete.
return InputString.Length > 0;
});
}

// Public properties
public string InputString
{
protected set
{
{
if (inputString != value)
{
inputString = value;
OnPropertyChanged("InputString");
DisplayText = FormatText(inputString);

// Perhaps the delete button must be enabled/disabled.


((Command)DeleteCharCommand).ChangeCanExecute();
}
}

get { return inputString; }


}

public string DisplayText


{
protected set
{
if (displayText != value)
{
displayText = value;
OnPropertyChanged("DisplayText");
}
}
get { return displayText; }
}

// ICommand implementations
public ICommand AddCharCommand { protected set; get; }

public ICommand DeleteCharCommand { protected set; get; }

string FormatText(string str)


{
bool hasNonNumbers = str.IndexOfAny(specialChars) != -1;
string formatted = str;

if (hasNonNumbers || str.Length < 4 || str.Length > 10)


{
}
else if (str.Length < 8)
{
formatted = String.Format("{0}-{1}",
str.Substring(0, 3),
str.Substring(3));
}
else
{
formatted = String.Format("({0}) {1}-{2}",
str.Substring(0, 3),
str.Substring(3, 3),
str.Substring(6));
}
return formatted;
}

protected void OnPropertyChanged(string propertyName)


{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

Esse ViewModel supõe que o AddCharCommand propriedade está associada a Command propriedade de vários
botões (ou qualquer outra coisa que tenha uma interface de comando), cada um deles é identificada pelo
CommandParameter . Esses botões adicionam caracteres para um InputString propriedade, que é formatada
como um número de telefone para o DisplayText propriedade.
Também há uma segunda propriedade do tipo ICommand chamado DeleteCharCommand . Isso é associado a um
botão back espaçamento, mas o botão deve ser desabilitado se houver caracteres a serem excluídos.
O teclado a seguir não é tão visualmente sofisticado quanto poderia ser. Em vez disso, a marcação foi reduzida
ao mínimo para demonstrar mais claramente o uso da interface de comando:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamlSamples;assembly=XamlSamples"
x:Class="XamlSamples.KeypadPage"
Title="Keypad Page">

<Grid HorizontalOptions="Center"
VerticalOptions="Center">
<Grid.BindingContext>
<local:KeypadViewModel />
</Grid.BindingContext>

<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

<Grid.ColumnDefinitions>
<ColumnDefinition Width="80" />
<ColumnDefinition Width="80" />
<ColumnDefinition Width="80" />
</Grid.ColumnDefinitions>

<!-- Internal Grid for top row of items -->


<Grid Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>

<Frame Grid.Column="0"
OutlineColor="Accent">
<Label Text="{Binding DisplayText}" />
</Frame>

<Button Text="&#x21E6;"
Command="{Binding DeleteCharCommand}"
Grid.Column="1"
BorderWidth="0" />
</Grid>

<Button Text="1"
Command="{Binding AddCharCommand}"
CommandParameter="1"
Grid.Row="1" Grid.Column="0" />

<Button Text="2"
Command="{Binding AddCharCommand}"
CommandParameter="2"
Grid.Row="1" Grid.Column="1" />

<Button Text="3"
Command="{Binding AddCharCommand}"
CommandParameter="3"
Grid.Row="1" Grid.Column="2" />
<Button Text="4"
Command="{Binding AddCharCommand}"
CommandParameter="4"
Grid.Row="2" Grid.Column="0" />

<Button Text="5"
Command="{Binding AddCharCommand}"
CommandParameter="5"
Grid.Row="2" Grid.Column="1" />

<Button Text="6"
Command="{Binding AddCharCommand}"
CommandParameter="6"
Grid.Row="2" Grid.Column="2" />

<Button Text="7"
Command="{Binding AddCharCommand}"
CommandParameter="7"
Grid.Row="3" Grid.Column="0" />

<Button Text="8"
Command="{Binding AddCharCommand}"
CommandParameter="8"
Grid.Row="3" Grid.Column="1" />

<Button Text="9"
Command="{Binding AddCharCommand}"
CommandParameter="9"
Grid.Row="3" Grid.Column="2" />

<Button Text="*"
Command="{Binding AddCharCommand}"
CommandParameter="*"
Grid.Row="4" Grid.Column="0" />

<Button Text="0"
Command="{Binding AddCharCommand}"
CommandParameter="0"
Grid.Row="4" Grid.Column="1" />

<Button Text="#"
Command="{Binding AddCharCommand}"
CommandParameter="#"
Grid.Row="4" Grid.Column="2" />
</Grid>
</ContentPage>

O Command propriedade do primeiro Button que aparece neste marcação está associada ao DeleteCharCommand
; o restante são associados ao AddCharCommand com um CommandParameter que é o mesmo como o caractere que
aparece no Button face. Aqui está o programa em ação:
Invocar métodos assíncronos
Comandos também podem invocar métodos assíncronos. Isso é feito usando o async e await palavras-chave
ao especificar o Execute método:

DownloadCommand = new Command (async () => await DownloadAsync ());

Isso indica que o DownloadAsync método é um Task e deve ser colocada em espera:

async Task DownloadAsync ()


{
await Task.Run (() => Download ());
}

void Download ()
{
...
}

Implementando um Menu de navegação


O XamlSamples programa que contém o código-fonte desta série de artigos usa um ViewModel para sua
página inicial. Esse ViewModel é uma definição de uma classe curta com três propriedades denominadas Type
, Title , e Description que contém o tipo de cada uma das páginas de exemplo, um título e uma breve
descrição. Além disso, o ViewModel define uma propriedade estática chamada All que é uma coleção de
todas as páginas no programa:

public class PageDataViewModel


{
public PageDataViewModel(Type type, string title, string description)
{
Type = type;
Title = title;
Description = description;
}

public Type Type { private set; get; }

public string Title { private set; get; }

public string Description { private set; get; }


public string Description { private set; get; }

static PageDataViewModel()
{
All = new List<PageDataViewModel>
{
// Part 1. Getting Started with XAML
new PageDataViewModel(typeof(HelloXamlPage), "Hello, XAML",
"Display a Label with many properties set"),

new PageDataViewModel(typeof(XamlPlusCodePage), "XAML + Code",


"Interact with a Slider and Button"),

// Part 2. Essential XAML Syntax


new PageDataViewModel(typeof(GridDemoPage), "Grid Demo",
"Explore XAML syntax with the Grid"),

new PageDataViewModel(typeof(AbsoluteDemoPage), "Absolute Demo",


"Explore XAML syntax with AbsoluteLayout"),

// Part 3. XAML Markup Extensions


new PageDataViewModel(typeof(SharedResourcesPage), "Shared Resources",
"Using resource dictionaries to share resources"),

new PageDataViewModel(typeof(StaticConstantsPage), "Static Constants",


"Using the x:Static markup extensions"),

new PageDataViewModel(typeof(RelativeLayoutPage), "Relative Layout",


"Explore XAML markup extensions"),

// Part 4. Data Binding Basics


new PageDataViewModel(typeof(SliderBindingsPage), "Slider Bindings",
"Bind properties of two views on the page"),

new PageDataViewModel(typeof(SliderTransformsPage), "Slider Transforms",


"Use Sliders with reverse bindings"),

new PageDataViewModel(typeof(ListViewDemoPage), "ListView Demo",


"Use a ListView with data bindings"),

// Part 5. From Data Bindings to MVVM


new PageDataViewModel(typeof(OneShotDateTimePage), "One-Shot DateTime",
"Obtain the current DateTime and display it"),

new PageDataViewModel(typeof(ClockPage), "Clock",


"Dynamically display the current time"),

new PageDataViewModel(typeof(HslColorScrollPage), "HSL Color Scroll",


"Use a view model to select HSL colors"),

new PageDataViewModel(typeof(KeypadPage), "Keypad",


"Use a view model for numeric keypad logic")
};
}

public static IList<PageDataViewModel> All { private set; get; }


}

O arquivo XAML para MainPage define uma ListBox cuja ItemsSource estiver definida como que All
propriedade e que contém um TextCell para exibir o Title e Description propriedades de cada página:
<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"
Padding="5, 0"
Title="XAML Samples">

<ListView ItemsSource="{x:Static local:PageDataViewModel.All}"


ItemSelected="OnListViewItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Title}"
Detail="{Binding Description}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>

As páginas são mostradas em uma lista rolável:

O manipulador no arquivo code-behind é disparado quando o usuário seleciona um item. O manipulador


define o SelectedItem propriedade do ListBox voltar ao null e, em seguida, cria uma instância de página
selecionada e navega até ela:

private async void OnListViewItemSelected(object sender, SelectedItemChangedEventArgs args)


{
(sender as ListView).SelectedItem = null;

if (args.SelectedItem != null)
{
PageDataViewModel pageData = args.SelectedItem as PageDataViewModel;
Page page = (Page)Activator.CreateInstance(pageData.Type);
await Navigation.PushAsync(page);
}
}

Vídeo
Xamarin Evolve 2016: MVVM simplificada com o xamarin. Forms e Prism
Resumo
XAML é uma ferramenta poderosa para a definição de interfaces do usuário em aplicativos xamarin. Forms,
especialmente quando a associação de dados e MVVM são usados. O resultado é uma representação limpa,
elegante e potencialmente editável de uma interface do usuário com todo o suporte de plano de fundo no
código.

Links relacionados
XamlSamples
Parte 1. Introdução ao XAML
Parte 2. Sintaxe essencial de XAML
Parte 3. Extensões de Marcação XAML
Parte 4. Conceitos básicos da associação de dados
Compilação de XAML no xamarin. Forms
12/04/2019 • 2 minutes to read

Pode ser compilado, opcionalmente, o XAML diretamente em linguagem intermediária (IL ) com o compilador
XAML (XAMLC ).
Compilação de XAML oferece vários benefícios:
Executa verificação de tempo de compilação de XAML, notificando o usuário de quaisquer erros.
Elimina parte da carga e do tempo de instanciação para elementos XAML.
Ajuda a reduzir o tamanho do arquivo do assembly final não incluindo mais arquivos .XAML.
Compilação de XAML está desabilitada por padrão, para garantir a compatibilidade com versões anteriores. Ele
pode ser habilitado no nível de classe e do assembly adicionando a XamlCompilation atributo.
O exemplo de código a seguir demonstra como habilitar compilação de XAML no nível de assembly:

using Xamarin.Forms.Xaml;
...
[assembly: XamlCompilation (XamlCompilationOptions.Compile)]
namespace PhotoApp
{
...
}

Neste exemplo, a verificação de todas as do XAML contido dentro do assembly de tempo de compilação será
executado, com erros XAML que está sendo relatados no tempo de compilação em vez de tempo de execução.
Portanto, o assembly de prefixo para o XamlCompilation atributo especifica que o atributo se aplica a todo o
assembly.

NOTE
O XamlCompilation atributo e o XamlCompilationOptions enumeração residem no Xamarin.Forms.Xaml namespace,
que deve ser importado para usá-los.

O exemplo de código a seguir demonstra como habilitar compilação de XAML no nível da classe:

using Xamarin.Forms.Xaml;
...
[XamlCompilation (XamlCompilationOptions.Compile)]
public class HomePage : ContentPage
{
...
}

Neste exemplo, a verificação de que o XAML para o tempo de compilação a HomePage classe será executado e
erros são relatados como parte do processo de compilação.
NOTE
Associações compiladas podem ser habilitadas para melhorar o desempenho de associação de dados em aplicativos
xamarin. Forms. Para obter mais informações, consulte compilado associações.

Links relacionados
XamlCompilation
XamlCompilationOptions
Caixa de ferramentas do xamarin. Forms XAML
12/04/2019 • 2 minutes to read

Visual Studio 2017 versão 15,8 e o Visual Studio para Mac 7.6 agora tem uma caixa de ferramentas está disponível
ao editar arquivos XAML de xamarin. Forms. A caixa de ferramentas contém todos os controles internos do
xamarin. Forms e layouts, que podem ser arrastados para o editor XAML.
Visual Studio
Visual Studio para Mac
No Visual Studio 2017, abra um arquivo XAML de xamarin. Forms para edição. A caixa de ferramentas pode ser
mostrada, pressionando Ctrl + W, X no teclado, ou escolhendo o Exibir > caixa de ferramentas item de menu.

A caixa de ferramentas pode ser ocultada e encaixada como outros painéis no Visual Studio 2017, usando os
ícones no canto superior direito ou o menu de contexto. A caixa de ferramentas do xamarin. Forms XAML tem
opções de modo de exibição personalizado que podem ser alteradas clicando em cada seção. Ativar/desativar a
exibição de lista opção para alternar entre a lista e modos de exibição compactos:

Quando um arquivo XAML de xamarin. Forms é aberto para edição, arraste qualquer controle ou layout da caixa
de ferramentas para o arquivo e, em seguida, aproveitar o Intellisense para personalizar a interface do usuário.
Pré-visualizador XAML para xamarin. Forms
12/04/2019 • 5 minutes to read

Consulte seus layouts do xamarin. Forms renderizados conforme você digita

Visão geral
O pré-visualizador XAML mostra qual será a aparência de sua página XAML de xamarin. Forms no iOS e
Android. Quando você faz alterações em seu XAML, você poderá vê-los imediatamente visualizado junto com seu
código. O pré-visualizador XAML está disponível no Visual Studio e Visual Studio para Mac.

Introdução
Visual Studio 2019
Você pode abrir o pré-visualizador XAML clicando nas setas no painel de exibição de divisão. Se você quiser
alterar o padrão dividir o comportamento do modo de exibição, use o Ferramentas > Opções > Xamarin >
formulários pré-visualizador caixa de diálogo. Nesta caixa de diálogo, você pode selecionar o modo de exibição
de documento padrão e a orientação de divisão.

Quando você abre um arquivo XAML, o editor será aberto em tamanho normal ou Avançar para o pré-
visualizador, com base nas configurações selecionadas na Ferramentas > Opções > Xamarin > formulários
pré-visualizador caixa de diálogo. No entanto, a divisão pode ser alterada para cada arquivo na janela do editor.
Controles de visualização do XAML
Escolha se você quiser ver seu código, o pré-visualizador de XAML, ou ambas selecionando esses botões na
divisão de exibir o painel. O botão do meio alterna o que são o pré-visualizador de lado e seu código em:

Você pode alterar se a tela é dividida verticalmente ou horizontalmente, ou recolher um painel completamente:

Visual Studio para Mac


O visualização botão é exibido no editor quando você abre uma página XAML. Mostrar ou ocultar o pré-
visualizador pressionando a visualização botão no canto superior direito de qualquer janela de documento
XAML:
Opções do Visualizador de XAML
As opções na parte superior do painel de visualização são:
Android – mostrar a versão do Android da tela
iOS – mostra a versão do iOS da tela (Observação: Se você estiver usando o Visual Studio no Windows, você
deve ser emparelhado com um Mac para usar esse modo)
Dispositivo -lista suspensa de dispositivos Android ou iOS, incluindo o tamanho da tela e resolução
Retrato (ícone) – usa a orientação de retrato para a versão prévia
Paisagem (ícone) – usa paisagem orientação para a versão prévia

Detectar modo de design


Estático DesignMode.IsDesignModeEnabled propriedade informa se o aplicativo é executado no visualizador. Usá-lo,
você pode especificar o código que será executado somente quando o aplicativo é ou não está em execução no
pré-visualizador:

if (DesignMode.IsDesignModeEnabled)
{
// Previewer only code
}

if (!DesignMode.IsDesignModeEnabled)
{
// Don't run in the Previewer
}

Essa propriedade é útil se você inicializar uma biblioteca em seu construtor de página que não é possível executar
em tempo de design.

Solução de problemas
Verifique os problemas a seguir e o fóruns do Xamarin, se o pré-visualizador não está funcionando.
Pré -visualizador de XAML não estiver visível ou mostrará um erro
Pode levar algum tempo para que o pré-visualizador iniciar - consulte "Inicializando renderizar" até que ele
esteja pronto.
Tente fechar e reabrir o arquivo XAML.
Certifique-se de que seu App classe tem um construtor sem parâmetros.
Verifique a versão do xamarin. Forms - ele deve ser pelo menos 3.6 do xamarin. Forms. Você pode atualizar
para a versão mais recente do xamarin. Forms por meio do NuGet.
Verifique sua instalação do JDK - visualizando Android requer pelo menos JDK 8.
Tente encapsulamento qualquer inicializado classes na página de C# código por trás
if (!DesignMode.IsDesignModeEnabled) .

Controles personalizados não são de renderização


Tente compilar seu projeto. O pré-visualizador mostra a classe base do controle se ele falhar ao renderizar o
controle, ou se tiver optado-out de criador do controle do processamento em tempo de design. Para obter mais
informações, consulte controles de personalizados renderizar no pré-visualizador XAML.
Usar dados de tempo de Design com o pré-
visualizador XAML
12/04/2019 • 5 minutes to read

Alguns layouts são difíceis de visualizar sem dados. Use estas dicas para fazer o máximo proveito de visualização
de suas páginas com uso intenso de dados no Visualizador de XAML.

Noções básicas de dados de tempo de design


Os dados são dados falsos que você definir para tornar seus controles mais fáceis de visualizar no pré-visualizador
XAML do tempo de design. Para começar, adicione as seguintes linhas de código para o cabeçalho da página
XAML:

xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"

Depois de adicionar os namespaces, você pode colocar d: na frente de qualquer atributo ou o controle para
mostrá-lo no Visualizador de XAML. Elementos com d: não são mostrados em tempo de execução.
Por exemplo, você pode adicionar texto a um rótulo que geralmente tem dados associados a ele.

<Label Text={Binding Name} d:Text="Name" />

Neste exemplo, sem d:Text , pré-visualizador XAML mostraria nada para o rótulo. Em vez disso, ele mostra
"Name" no qual o rótulo terá dados reais no tempo de execução.
Você pode usar d: com qualquer atributo para um controle xamarin. Forms, como cores, tamanhos de fonte e
espaçamento. Você pode até mesmo adicioná-lo ao próprio controle:

<d:Button Text="Design Time Button" />


Neste exemplo, o botão aparece apenas em tempo de design. Use esse método para colocar um espaço reservado
para um controle personalizado não compatível com o pré-visualizador XAML.

Imagens de visualização em tempo de design


Você pode definir um fonte de tempo de design para imagens que está vinculada à página ou carregado na
dinamicamente. Em seu projeto Android, adicione a imagem que você deseja mostrar no pré-visualizador XAML
para o recursos > Drawable pasta. Em seu projeto do iOS, adicione a imagem para o recursos pasta. Em seguida,
você pode mostrar essa imagem no pré-visualizador XAML em tempo de design:

<Image Source={Binding ProfilePicture} d:Source="DesignTimePicture.jpg" />


Dados de tempo de design para ListViews
ListViews são uma maneira popular para exibir dados em um aplicativo móvel. No entanto, eles são difíceis de
visualizar sem dados reais. Para usar dados de tempo de design com eles, você precisará criar uma matriz de
tempo de design para usar como um ItemsSource. O pré-visualizador de XAML exibe o que está na matriz na sua
ListView em tempo de design.

<StackLayout>
<ListView ItemsSource="{Binding Items}">
<d:ListView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Item One</x:String>
<x:String>Item Two</x:String>
<x:String>Item Three</x:String>
</x:Array>
</d:ListView.ItemsSource>
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding ItemName}"
d:Text="{Binding .}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
Este exemplo mostrará um ListView de três TextCells no pré-visualizador XAML. Você pode alterar x:String para
um modelo de dados existente em seu projeto.
Consulte a aplicativo de Hanselman.Forms de James Montemagno para obter um exemplo mais complexo.

Alternativa: Codificar um ViewModel estático


Se você não quiser adicionar dados de tempo de design para controles individuais, você pode configurar um
repositório de dados fictícios para associar à sua página. Consulte de James Montemagno postagem de blog sobre
como adicionar dados de tempo de design para ver como associar a um ViewModel estático em XAML.

Solução de problemas
Requisitos
Dados de tempo de design requer uma versão mínima do xamarin. Forms 3.6.
O IntelliSense mostra linhas onduladas sob os meus dados de tempo de design
Isso é um problema conhecido e será corrigido em uma versão futura do Visual Studio. O projeto ainda será
compilado sem erros.
O pré -visualizador XAML parou de funcionar
Tente fechar e reabrir o arquivo XAML e a limpeza e recriar o projeto.
Renderizar controles personalizados no pré-
visualizador XAML
12/04/2019 • 3 minutes to read

Controles personalizados às vezes, não funcionam conforme o esperado no pré-visualizador XAML. Use as
diretrizes neste artigo para entender as limitações de visualização de seus controles personalizados.

Modo de visualização básico


Mesmo se você ainda não tiver criado seu projeto, o pré-visualizador XAML será renderizado suas páginas. Até
que você cria, qualquer controle que depende de lógica mostrará seu tipo base do xamarin. Forms. Quando seu
projeto é compilado, o pré-visualizador XAML tentar mostrar controles personalizados com processamento em
tempo de design habilitado. Se o processamento falhar, ela mostrará o tipo base do xamarin. Forms.

Habilitar o processamento em tempo de design para controles


personalizados
Se você fazer seus próprios controles personalizados ou use os controles de uma biblioteca de terceiros, o pré-
visualizador pode exibi-los incorretamente. Controles personalizados devem aceitar renderização para aparecer
no visualizador, se você escreveu o controle ou importou de uma biblioteca de tempo de design. Com controles
que você criou, adicione a [DesignTimeVisible(true)] para sua classe do controle para mostrá-lo no visualizador:

namespace MyProject
{
[DesignTimeVisible(true)]
public class MyControl : BaseControl
{
// Your control's code here
}

Use classe de base de ImageCirclePlugin de James Montemagno como exemplo.

Controles de SkiaSharp
Atualmente, os controles de SkiaSharp só têm suporte quando você está visualizando no iOS. Eles não serão
renderizadas na visualização do Android.

Solução de problemas
Verifique a versão do xamarin. Forms
Verifique se você tem pelo menos 3.6 do xamarin. Forms instalado. Você pode atualizar sua versão do xamarin.
Forms no NuGet.
Mesmo com [DesignTimeVisible(true)] , meu controle personalizado não estiver renderizando corretamente.
Controles personalizados que dependem muito do code-behind ou back-end de dados sempre não funcionam no
pré-visualizador XAML. Você pode tentar:
Movendo o controle para que ele não inicializar se o modo de design está habilitado
Configurando dados de tempo de design para mostrar dados fictícios de back-end
O pré -visualizador XAML mostra o erro "Controles personalizados não renderizar corretamente"
Tente limpar e recriar o projeto, ou fechar e reabrir o arquivo XAML.
Namespaces XAML no xamarin. Forms
12/04/2019 • 8 minutes to read

XAML usa o atributo xmlns XML para declarações de namespace. Este artigo apresenta a sintaxe do namespace
XAML e demonstra como declarar um namespace XAML para um tipo de acesso.

Visão geral
Há duas declarações de namespace XAML que sempre estão dentro do elemento raiz de um arquivo XAML. A
primeira define o namespace padrão, conforme mostrado no exemplo de código XAML a seguir:

xmlns="http://xamarin.com/schemas/2014/forms"

O namespace padrão especifica que elementos definidos no arquivo XAML sem prefixo se referem às classes do
xamarin. Forms, tal como ContentPage .
A segunda declaração de namespace usa o x prefixo, conforme mostrado no exemplo de código XAML a seguir:

xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"

XAML usa prefixos de declarar namespaces não-padrão, com o prefixo que está sendo usado ao fazer referência
a tipos no namespace. O x declaração de namespace Especifica que os elementos definidos dentro do XAML
com um prefixo de x são usados para elementos e atributos que são intrínsecos para XAML (especificamente, a
especificação de XAML de 2009).
A tabela a seguir descreve o x atributos de namespace com suporte de xamarin. Forms:

CONSTRUCTO DESCRIÇÃO

x:Arguments Especifica argumentos de construtor para um construtor não


padrão ou para uma declaração de objeto do método de
fábrica.

x:Class Especifica o nome de namespace e classe para uma classe


definida em XAML. O nome da classe deve corresponder ao
nome de classe do arquivo code-behind. Observe que essa
construção só pode aparecer no elemento raiz de um arquivo
XAML.

x:DataType Especifica o tipo do objeto que o elemento XAML e seus


filhos, irá se vincular.

x:FactoryMethod Especifica um método de fábrica que pode ser usado para


inicializar um objeto.

x:FieldModifier Especifica o nível de acesso para os campos gerados para


elementos nomeados do XAML.
CONSTRUCTO DESCRIÇÃO

x:Key Especifica uma chave exclusiva definida pelo usuário para


cada recurso em um ResourceDictionary . O valor da chave
é usado para recuperar o recurso XAML e normalmente é
usado como o argumento para o StaticResource extensão
de marcação.

x:Name Especifica um nome de objeto de tempo de execução para o


elemento XAML. Configuração x:Name é semelhante a
declarar uma variável no código.

x:TypeArguments Especifica os argumentos de tipo genérico para o construtor


de um tipo genérico.

Para obter mais informações sobre o x:DataType atributo, consulte compilado associações. Para obter mais
informações sobre o x:FieldModifier atributo, consulte modificadores de campo. Para obter mais informações
sobre o x:Arguments , x:FactoryMethod , e x:TypeArguments atributos, consulte passando argumentos em XAML.

NOTE
Além dos atributos de namespace listados acima, o xamarin. Forms também inclui extensões de marcação que podem ser
consumidas por meio de x prefixo de namespace. Para obter mais informações, consulte extensões de marcação XAML
consumindo.

No XAML, as declarações de namespace herdam de elemento pai para o elemento filho. Portanto, ao definir um
namespace no elemento raiz de um arquivo XAML, todos os elementos dentro desse arquivo herdam a
declaração de namespace.

Declarando Namespaces para tipos


Tipos podem ser referenciadas em XAML, declarando um namespace XAML com um prefixo, com a declaração
de namespace, especificando o nome do namespace de Common Language Runtime (CLR ) e, opcionalmente,
um nome de assembly. Isso é obtido com a definição de valores para as seguintes palavras-chave na declaração
de namespace:
CLR-namespace: ou usando: – o namespace do CLR declarado dentro do assembly que contém os tipos a
serem expostos como elementos XAML. Essa palavra-chave é necessária.
assembly = – o assembly que contém o namespace CLR referenciado. Esse valor é o nome do assembly, sem
a extensão de arquivo. O caminho para o assembly deve ser estabelecido como uma referência no arquivo de
projeto que contém o arquivo XAML que fazem referência a assembly. Essa palavra-chave pode ser omitido
se o clr-namespace valor está dentro do mesmo assembly que o código do aplicativo que faz referência os
tipos.
Observe que o caractere separando o clr-namespace ou using token de seu valor é um dois-pontos, enquanto o
caractere que separa o assembly token do seu valor é um sinal de igual. O caractere a ser usado entre dois
tokens é um ponto e vírgula.
O exemplo de código a seguir mostra uma declaração de namespace XAML:

<ContentPage ... xmlns:local="clr-namespace:HelloWorld" ...>


...
</ContentPage>
Como alternativa, isso pode ser escrito como:

<ContentPage ... xmlns:local="using:HelloWorld" ...>


...
</ContentPage>

O local prefixo é uma convenção usada para indicar que os tipos no namespace são locais para o aplicativo.
Como alternativa, se os tipos estão em um assembly diferente, o nome do assembly deve também ser definido
na declaração de namespace, conforme demonstrado no exemplo de código XAML a seguir:

<ContentPage ... xmlns:behaviors="clr-namespace:Behaviors;assembly=BehaviorsLibrary" ...>


...
</ContentPage>

O prefixo de namespace é especificado, em seguida, ao declarar uma instância de um tipo de um namespace


importado, como demonstrado no exemplo de código XAML a seguir:

<ListView ...>
<ListView.Behaviors>
<behaviors:EventToCommandBehavior EventName="ItemSelected" ... />
</ListView.Behaviors>
</ListView>

Para obter informações sobre como definir um esquema personalizado de namespace, consulte esquemas
personalizados de Namespace XAML.

Resumo
Este artigo introduziu a sintaxe do namespace XAML e demonstrou como declarar um namespace XAML para
um tipo de acesso. XAML usa a xmlns atributo XML para tipos e declarações de namespace pode ser
referenciado em XAML, declarando um namespace XAML com um prefixo.

Links relacionados
Passando argumentos em XAML
Esquemas de personalizado de Namespace XAML
no xamarin. Forms
12/04/2019 • 6 minutes to read

Baixar o exemplo
Tipos em uma biblioteca podem ser referenciados em XAML, declarando um namespace XAML para a biblioteca,
com a declaração de namespace, especificando o nome do namespace de Common Language Runtime (CLR ) e
um nome de assembly:

<ContentPage ...
xmlns:controls="clr-namespace:MyCompany.Controls;assembly="MyCompany.Controls">
...
</ContentPage>

No entanto, especificando um nome de namespace e assembly do CLR em um xmlns definição pode ser
complicada e sujeito a erros. Além disso, várias declarações de namespace XAML podem ser necessárias se a
biblioteca contém tipos em vários namespaces.
Uma abordagem alternativa é definir um esquema personalizado de namespace, tal como
http://mycompany.com/schemas/controls , que é mapeado para um ou mais namespaces CLR. Isso permite que uma
única declaração de namespace XAML fazer referência a todos os tipos em um assembly, mesmo se eles estão em
namespaces diferentes. Ele também permite que uma única declaração de namespace XAML para tipos de
referência em vários assemblies.
Para obter mais informações sobre namespaces XAML, consulte Namespaces de XAML no xamarin. Forms.

Definir um esquema personalizado de namespace


O aplicativo de exemplo contém uma biblioteca que expõe alguns controles simples, como CircleButton :

using Xamarin.Forms;

namespace MyCompany.Controls
{
public class CircleButton : Button
{
...
}
}

Todos os controles na biblioteca residem no MyCompany.Controls namespace. Esses controles podem ser expostos
a um assembly de chamada por meio de um esquema personalizado de namespace.
Um esquema personalizado de namespace é definido com o XmlnsDefinitionAttribute classe, que especifica o
mapeamento entre um namespace XAML e um ou mais namespaces CLR. O XmlnsDefinitionAttribute leva dois
argumentos: o nome do namespace XAML e o nome do namespace CLR. O nome do namespace XAML é
armazenado na XmlnsDefinitionAttribute.XmlNamespace propriedade e o nome do namespace CLR é armazenada
no XmlnsDefinitionAttribute.ClrNamespace propriedade.
NOTE
O XmlnsDefinitionAttribute classe também tem uma propriedade chamada AssemblyName , que pode ser definido
opcionalmente para o nome do assembly. Isso só é necessário quando um namespace CLR referenciado de um
XmlnsDefinitionAttribute está em um assembly externo.

O XmlnsDefinitionAttribute deve ser definida no nível de assembly no projeto que contém os namespaces CLR
que serão mapeados no esquema do namespace personalizado. A exemplo a seguir mostra a AssemblyInfo.cs
arquivo do aplicativo de exemplo:

using Xamarin.Forms;
using MyCompany.Controls;

[assembly: Preserve]
[assembly: XmlnsDefinition("http://mycompany.com/schemas/controls", "MyCompany.Controls")]

Esse código cria um esquema personalizado de namespace que mapeia o http://mycompany.com/schemas/controls


URL para o MyCompany.Controls namespace CLR. Além disso, o Preserve atributo é especificado no assembly,
para garantir que o vinculador preserva todos os tipos no assembly.

IMPORTANT
O Preserve atributo deve ser aplicado a classes no assembly que são mapeadas por meio do esquema do namespace
personalizado ou aplicado ao assembly inteiro.

O esquema do namespace personalizado, em seguida, pode ser usado para resolução de tipo nos arquivos XAML.

Consumindo um esquema personalizado de namespace


Para consumir tipos do esquema do namespace personalizado, o compilador XAML requer que há uma referência
de código do assembly que consome os tipos, para o assembly que define os tipos. Isso pode ser feito
adicionando uma classe que contém um Init método para o assembly que define os tipos que serão
consumidos por meio de XAML:

namespace MyCompany.Controls
{
public static class Controls
{
public static void Init()
{
}
}
}

O Init método, em seguida, pode ser chamado do assembly que consome os tipos do esquema do namespace
personalizado:
using Xamarin.Forms;
using MyCompany.Controls;

namespace CustomNamespaceSchemaDemo
{
public partial class MainPage : ContentPage
{
public MainPage()
{
Controls.Init();
InitializeComponent();
}
}
}

WARNING
Falha ao incluir uma referência de código desse tipo resultará no compilador XAML sendo não é possível localizar o assembly
que contém os tipos de esquema do namespace personalizado.

Para consumir o CircleButton controle, um namespace XAML é declarado, com a declaração de namespace,
especificando a URL de esquema do namespace personalizado:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="http://mycompany.com/schemas/controls"
x:Class="CustomNamespaceSchemaDemo.MainPage">
<StackLayout Margin="20,35,20,20">
...
<controls:CircleButton Text="+"
BackgroundColor="Fuchsia"
BorderColor="Black"
CircleDiameter="100" />
<controls:CircleButton Text="-"
BackgroundColor="Teal"
BorderColor="Silver"
CircleDiameter="70" />
...
</StackLayout>
</ContentPage>

CircleButton instâncias, em seguida, podem ser adicionadas para o ContentPage declarando-os com o controls
prefixo de namespace.
Para localizar o namespace personalizado os tipos de esquema, o xamarin. Forms pesquisará os assemblies
referenciados para XmlnsDefinitionAttribute instâncias. Se o xmlns corresponde ao atributo de um elemento em
um arquivo XAML a XmlNamespace valor da propriedade em um XmlnsDefinitionAttribute , xamarin. Forms
tentará usar o XmlnsDefinitionAttribute.ClrNamespace para a resolução do tipo de valor da propriedade. Se a
resolução de tipo falhar, xamarin. Forms continuará a tentar a resolução de tipo com base em qualquer
correspondência adicionais XmlnsDefinitionAttribute instâncias.
O resultado é que dois CircleButton instâncias são exibidas:
Links relacionados
Esquemas personalizados de Namespace (amostra)
Recomendado prefixos de Namespace XAML
Namespaces XAML no xamarin. Forms
Namespace XAML recomendado prefixos no
xamarin. Forms
12/04/2019 • 2 minutes to read

O XmlnsPrefixAttribute classe pode ser usada por autores de controle para especificar um prefixo recomendado a
ser associado a um namespace XAML, para uso do XAML. O prefixo é útil quando o suporte à serialização de
árvore de objeto para XAML, ou ao interagir com um ambiente de design que tenha recursos de edição de XAML.
Por exemplo:
Editores de texto XAML pode usar o XmlnsPrefixAttribute como uma dica para um namespace XAML inicial
xmlns mapeamento.
Ambientes de design XAML pode usar o XmlnsPrefixAttribute para adição de mapeamentos para o XAML ao
arrastar objetos para fora de uma caixa de ferramentas e em uma superfície de design visual.
Recomendado prefixos de namespace devem ser definidos no nível de assembly com o XmlnsPrefixAttribute
construtor, que leva dois argumentos: uma cadeia de caracteres que especifica o identificador de um namespace
XAML e uma cadeia de caracteres que especifica um prefixo recomendado:

[assembly: XmlnsPrefix("http://xamarin.com/schemas/2014/forms", "xf")]

Prefixos devem usar cadeias de caracteres curtas, porque, normalmente, o prefixo é aplicado a todos os elementos
serializados que vêm do namespace XAML. Portanto, o comprimento da cadeia de caracteres de prefixo pode ter
um efeito notável no tamanho da saída XAML serializado.

NOTE
Mais de um XmlnsPrefixAttribute pode ser aplicado a um assembly. Por exemplo, se você tiver um assembly que define
os tipos para mais de um namespace XAML, você pode definir valores de prefixo diferente para cada namespace XAML.

Links relacionados
Esquemas Personalizados de Namespace de XAML
Namespaces XAML no xamarin. Forms
Extensões de marcação XAML
12/04/2019 • 2 minutes to read

baixar o exemplo
Extensões de marcação XAML ajudam a estender o poder e flexibilidade do XAML, permitindo que os atributos do
elemento a ser definido de fontes diferentes cadeias de caracteres de texto literal.
Por exemplo, normalmente você defina as Color propriedade de BoxView semelhante a esta:

<BoxView Color="Blue" />

Ou, você pode defini-lo como um valor hexadecimal de cor RGB:

<BoxView Color="#FF0080" />

Em ambos os casos, a cadeia de caracteres de texto é definida como o Color atributo será convertido em um
Color valor pela ColorTypeConverter classe.

Talvez você prefira em vez disso, defina as Color de um valor armazenado em um dicionário de recurso, ou o
valor de uma propriedade estática de uma classe que você criou ou uma propriedade de tipo de atributo Color de
outro elemento na página, ou construídos a partir de Separe os valores de matiz, saturação e luminosidade.
Todas essas opções são possíveis usando extensões de marcação XAML. Mas não deixe que a frase "extensões de
marcação" assustam você: extensões de marcação XAML são não extensões para XML. Mesmo com extensões de
marcação XAML, o XAML é sempre XML legal.
Uma extensão de marcação é realmente apenas uma maneira diferente para expressar um atributo de um
elemento. Extensões de marcação XAML são geralmente identificadas por uma configuração de atributo que é
colocada entre chaves:

<BoxView Color="{StaticResource themeColor}" />

Qualquer configuração de atributo entre chaves é sempre uma extensão de marcação XAML. No entanto, como
você verá, extensões de marcação XAML também podem ser referenciadas sem o uso de chaves.
Este artigo está dividido em duas partes:

Consumo de extensões de marcação XAML


Use as extensões de marcação XAML definidas no xamarin. Forms.

Criação de extensões de marcação XAML


Escreva suas próprias extensões de marcação XAML personalizados.

Links relacionados
Extensões de marcação (amostra)
Capítulo de extensões de marcação XAML do xamarin. Forms book
Dicionários de recurso
Estilos dinâmicos
Associação de dados
Consumo de extensões de marcação XAML
12/04/2019 • 27 minutes to read

baixar o exemplo
Extensões de marcação XAML ajudar a aprimorar o poder e flexibilidade do XAML, permitindo que os atributos
do elemento a ser definido de uma variedade de fontes. Várias extensões de marcação XAML são parte da
especificação do XAML 2009. Eles aparecem nos arquivos XAML com o habitual x prefixo de namespace e são
normalmente chamados para com esse prefixo. Este artigo discute as extensões de marcação a seguir:
x:Static – fazer referência a propriedades estáticas, campos ou membros de enumeração.
x:Reference – chamada elementos na página de referência.
x:Type – definir um atributo para um System.Type objeto.
x:Array – construir uma matriz de objetos de um tipo específico.
x:Null – definir um atributo para um null valor.
OnPlatform – Personalizar a aparência da interface do usuário em uma base por plataforma.
OnIdiom – Personalizar a aparência da interface do usuário com base no idioma do dispositivo em que o
aplicativo está sendo executado.
Extensões de marcação XAML adicionais historicamente são suportadas pelas outras implementações de XAML e
também são suportadas pelo xamarin. Forms. Elas são descritas mais detalhadamente em outros artigos:
StaticResource – fazer referência a objetos de um dicionário de recursos, conforme descrito no artigo
dicionários de recursos.
DynamicResource – responder a alterações em objetos em um dicionário de recursos, conforme descrito no
artigo estilos dinâmicos.
Binding – estabelecer um vínculo entre as propriedades de dois objetos, conforme descrito no artigo
associação de dados.
TemplateBinding – executa a associação de dados de um modelo de controle, conforme discutido no artigo de
um modelo de controle de associação.
O RelativeLayout layout faz uso da extensão de marcação personalizada ConstraintExpression . Esta extensão de
marcação é descrita no artigo RelativeLayout.

Extensão de marcação x:Static


O x:Static extensão de marcação dá suporte a StaticExtension classe. A classe tem uma única propriedade
chamada Member do tipo string que você defina como o nome de uma constante pública, a propriedade estática,
o campo estático ou o membro de enumeração.
Uma maneira comum de usar x:Static deve primeiro definir uma classe com algumas constantes ou variáveis
estáticas, como nesse pequeno AppConstants classe a MarkupExtensions programa:

static class AppConstants


{
public static double NormalFontSize = 18;
}

O demonstração X:Static página demonstra várias maneiras de usar o x:Static extensão de marcação. A
abordagem mais detalhada cria uma instância de StaticExtension classe entre Label.FontSize marcas de
elemento de propriedade:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:MarkupExtensions"
x:Class="MarkupExtensions.StaticDemoPage"
Title="x:Static Demo">
<StackLayout Margin="10, 0">
<Label Text="Label No. 1">
<Label.FontSize>
<x:StaticExtension Member="local:AppConstants.NormalFontSize" />
</Label.FontSize>
</Label>

···

</StackLayout>
</ContentPage>

O analisador XAML também permite que o StaticExtension classe deverá ser abreviado como x:Static :

<Label Text="Label No. 2">


<Label.FontSize>
<x:Static Member="local:AppConstants.NormalFontSize" />
</Label.FontSize>
</Label>

Isso pode ser simplificado ainda mais, mas a alteração apresenta algumas novas sintaxes: Ele consiste em colocar
o StaticExtension classe e o membro definição entre chaves. A expressão resultante é definida diretamente para
o FontSize atributo:

<Label Text="Label No. 3"


FontSize="{x:StaticExtension Member=local:AppConstants.NormalFontSize}" />

Observe que há nenhum aspas dentro das chaves. O Member propriedade de StaticExtension não é mais um
atributo XML. Em vez disso, ele é parte da expressão para a extensão de marcação.
Assim como você pode abreviar x:StaticExtension para x:Static quando você usá-lo como um elemento de
objeto, você também pode abreviá-lo na expressão entre chaves:

<Label Text="Label No. 4"


FontSize="{x:Static Member=local:AppConstants.NormalFontSize}" />

O StaticExtension classe tem um ContentProperty referenciar a propriedade de atributo Member , que marca essa
propriedade como propriedade de conteúdo de padrão da classe. Para extensões de marcação XAML expressadas
com chaves, você pode eliminar o Member= faz parte da expressão:

<Label Text="Label No. 5"


FontSize="{x:Static local:AppConstants.NormalFontSize}" />

Isso é a forma mais comum dos x:Static extensão de marcação.


O demonstração estático página contém dois outros exemplos. A marca de raiz do arquivo XAML contém uma
declaração de namespace XML para o .NET System namespace:
xmlns:sys="clr-namespace:System;assembly=mscorlib"

Isso permite que o Label tamanho da fonte a ser definido para o campo estático Math.PI . Que resulta em texto
em vez disso, pequeno, portanto, o Scale estiver definida como Math.E :

<Label Text="&#x03C0; &#x00D7; E sized text"


FontSize="{x:Static sys:Math.PI}"
Scale="{x:Static sys:Math.E}"
HorizontalOptions="Center" />

O exemplo final exibe o Device.RuntimePlatform valor. O Environment.NewLine propriedade estática é usada para
inserir um caractere de nova linha entre os dois Span objetos:

<Label HorizontalTextAlignment="Center"
FontSize="{x:Static local:AppConstants.NormalFontSize}">
<Label.FormattedText>
<FormattedString>
<Span Text="Runtime Platform: " />
<Span Text="{x:Static sys:Environment.NewLine}" />
<Span Text="{x:Static Device.RuntimePlatform}" />
</FormattedString>
</Label.FormattedText>
</Label>

Aqui está o exemplo em execução:

Extensão de marcação x:Reference


O x:Reference extensão de marcação dá suporte a ReferenceExtension classe. A classe tem uma única
propriedade chamada Name do tipo string que você defina como o nome de um elemento na página que tem
um nome com x:Name . Isso Name é a propriedade de conteúdo do ReferenceExtension , então Name= não é
necessário quando x:Reference aparece entre chaves.
O x:Reference extensão de marcação é usada exclusivamente com associações de dados, que são descritas mais
detalhadamente no artigo Data Binding.
O demonstração X:Reference página mostra dois usos do x:Reference com associações de dados, primeiro
onde ele é usado para definir a Source propriedade do Binding objeto e o segundo em que ele é usado para
definir o BindingContext propriedade associações de dados de dois:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MarkupExtensions.ReferenceDemoPage"
x:Name="page"
Title="x:Reference Demo">

<StackLayout Margin="10, 0">

<Label Text="{Binding Source={x:Reference page},


StringFormat='The type of this page is {0}'}"
FontSize="18"
VerticalOptions="CenterAndExpand"
HorizontalTextAlignment="Center" />

<Slider x:Name="slider"
Maximum="360"
VerticalOptions="Center" />

<Label BindingContext="{x:Reference slider}"


Text="{Binding Value, StringFormat='{0:F0}&#x00B0; rotation'}"
Rotation="{Binding Value}"
FontSize="24"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />

</StackLayout>
</ContentPage>

Ambos expressões usam a versão abreviada do ReferenceExtension nome da classe e eliminar o


x:Reference
Name= faz parte da expressão. No primeiro exemplo, o x:Reference extensão de marcação é inserida no Binding
extensão de marcação. Observe que o Source e StringFormat configurações são separadas por vírgulas. Aqui
está o programa em execução:

Extensão de marcação x:Type


O x:Type extensão de marcação é o equivalente em XAML do C# typeof palavra-chave. Ele dá suporte a
TypeExtension classe, que define uma propriedade chamada TypeName do tipo string que é definido como um
nome de classe ou estrutura. O x:Type retorna da extensão de marcação a System.Type objeto dessa classe ou
estrutura. TypeName é a propriedade de conteúdo do TypeExtension , portanto TypeName= não é necessário
quando x:Type é exibida com as chaves.
Dentro do xamarin. Forms, há várias propriedades que têm argumentos de tipo Type . Os exemplos incluem o
TargetType propriedade do Style e o X:TypeArguments atributo usado para especificar argumentos em classes
genéricas. No entanto, o analisador XAML executa o typeof operação automaticamente e o x:Type extensão de
marcação não é usada nesses casos.
Um único lugar onde x:Type é é necessário com o x:Array extensão de marcação, que é descrito no próxima
seção.
O x:Type extensão de marcação também é útil ao construir um menu no qual cada item de menu corresponde a
um objeto de um tipo específico. Você pode associar um Type de objeto com cada item de menu e, em seguida,
instancie o objeto quando o item de menu é selecionado.
Isso é como o menu de navegação em MainPage no extensões de marcação programa funciona. O MainPage.
XAML arquivo contém uma TableView com cada TextCell correspondente a uma página específica no
programa:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MarkupExtensions"
x:Class="MarkupExtensions.MainPage"
Title="Markup Extensions"
Padding="10">
<TableView Intent="Menu">
<TableRoot>
<TableSection>
<TextCell Text="x:Static Demo"
Detail="Access constants or statics"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:StaticDemoPage}" />

<TextCell Text="x:Reference Demo"


Detail="Reference named elements on the page"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:ReferenceDemoPage}" />

<TextCell Text="x:Type Demo"


Detail="Associate a Button with a Type"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:TypeDemoPage}" />

<TextCell Text="x:Array Demo"


Detail="Use an array to fill a ListView"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:ArrayDemoPage}" />

···

</TableRoot>
</TableView>
</ContentPage>

Aqui está a página principal de abertura extensões de marcação:


Cada CommandParameter estiver definida como um x:Type extensão de marcação que faz referência a uma das
outras páginas. O Command propriedade é associada a uma propriedade chamada NavigateCommand . Essa
propriedade é definida no MainPage arquivo code-behind:

public partial class MainPage : ContentPage


{
public MainPage()
{
InitializeComponent();

NavigateCommand = new Command<Type>(async (Type pageType) =>


{
Page page = (Page)Activator.CreateInstance(pageType);
await Navigation.PushAsync(page);
});

BindingContext = this;
}

public ICommand NavigateCommand { private set; get; }


}

O NavigateCommand propriedade é um Command objeto que implementa um comando execute com um argumento
do tipo Type — o valor de CommandParameter . Usa o método Activator.CreateInstance para instanciar a página e,
em seguida, navega até ela. O construtor é concluído, definindo o BindingContext da página para si mesmo, que
permite que o Binding em Command funcione. Consulte a associação de dados artigo e principalmente o
Commanding artigo para obter mais detalhes sobre esse tipo de código.
O demonstração X:Type página usa uma técnica semelhante para instanciar os elementos de xamarin. Forms e
adicioná-los para um StackLayout . O arquivo XAML inicialmente consiste em três Button elementos com seus
Command as propriedades definidas para um Binding e o CommandParameter propriedades definidas como tipos de
três modos de exibição do xamarin. Forms:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MarkupExtensions.TypeDemoPage"
Title="x:Type Demo">

<StackLayout x:Name="stackLayout"
Padding="10, 0">

<Button Text="Create a Slider"


HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Command="{Binding CreateCommand}"
CommandParameter="{x:Type Slider}" />

<Button Text="Create a Stepper"


HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Command="{Binding CreateCommand}"
CommandParameter="{x:Type Stepper}" />

<Button Text="Create a Switch"


HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Command="{Binding CreateCommand}"
CommandParameter="{x:Type Switch}" />
</StackLayout>
</ContentPage>

O arquivo code-behind define e inicializa o CreateCommand propriedade:

public partial class TypeDemoPage : ContentPage


{
public TypeDemoPage()
{
InitializeComponent();

CreateCommand = new Command<Type>((Type viewType) =>


{
View view = (View)Activator.CreateInstance(viewType);
view.VerticalOptions = LayoutOptions.CenterAndExpand;
stackLayout.Children.Add(view);
});

BindingContext = this;
}

public ICommand CreateCommand { private set; get; }


}

O método que é executado quando um Button é pressionado cria uma nova instância do argumento, define sua
VerticalOptions propriedade e adiciona-o para o StackLayout . Os três Button elementos, em seguida,
compartilhem a página com modos de exibição criados dinamicamente:
Extensão de marcação x:Array
O x:Arrayextensão de marcação permite que você defina uma matriz na marcação. Ele dá suporte a
ArrayExtension classe, que define duas propriedades:

Type do tipo Type , que indica o tipo dos elementos na matriz.


Items do tipo IList , que é uma coleção de itens em si. Essa é a propriedade de conteúdo de ArrayExtension .

O x:Array extensão de marcação em si nunca aparece entre chaves. Em vez disso, x:Array marcas de início e
término delimitam a lista de itens. Defina as Type propriedade para um x:Type extensão de marcação.
O demonstração X:array página mostra como usar x:Array para adicionar itens a um ListView definindo o
ItemsSource propriedade para uma matriz:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MarkupExtensions.ArrayDemoPage"
Title="x:Array Demo Page">
<ListView Margin="10">
<ListView.ItemsSource>
<x:Array Type="{x:Type Color}">
<Color>Aqua</Color>
<Color>Black</Color>
<Color>Blue</Color>
<Color>Fuchsia</Color>
<Color>Gray</Color>
<Color>Green</Color>
<Color>Lime</Color>
<Color>Maroon</Color>
<Color>Navy</Color>
<Color>Olive</Color>
<Color>Pink</Color>
<Color>Purple</Color>
<Color>Red</Color>
<Color>Silver</Color>
<Color>Teal</Color>
<Color>White</Color>
<Color>Yellow</Color>
</x:Array>
</ListView.ItemsSource>

<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<BoxView Color="{Binding}"
Margin="3" />
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>

O ViewCell cria um simples BoxView para cada entrada de cor:

Há várias maneiras para especificar o indivíduo Color itens nessa matriz. Você pode usar um x:Static extensão
de marcação:
<x:Static Member="Color.Blue" />

Ou, você pode usar StaticResource para recuperar uma cor de um dicionário de recursos:

<StaticResource Key="myColor" />

No final deste artigo, você verá uma extensão de marcação XAML personalizada que também cria um novo valor
de cor:

<local:HslColor H="0.5" S="1.0" L="0.5" />

Ao definir matrizes de tipos comuns, como cadeias de caracteres ou números, use as marcas listadas na passar
argumentos de construtor artigo para delimitar os valores.

Extensão de marcação x:Null


O x:Null extensão de marcação dá suporte a NullExtension classe. Ele não tem propriedades e é simplesmente
o equivalente XAML do C# null palavra-chave.
O x:Null extensão de marcação é raramente necessário e raramente usada, mas se você encontrar uma
necessidade para ele, você ficará feliz por isso ele existe.
O demonstração X:Null página ilustra um cenário quando x:Null talvez seja conveniente. Suponhamos que
você defina implícito Style para Label que inclui um Setter que define o FontFamily propriedade para um
nome de família dependente de plataforma:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MarkupExtensions.NullDemoPage"
Title="x:Null Demo">
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Label">
<Setter Property="FontSize" Value="48" />
<Setter Property="FontFamily">
<Setter.Value>
<OnPlatform x:TypeArguments="x:String">
<On Platform="iOS" Value="Times New Roman" />
<On Platform="Android" Value="serif" />
<On Platform="UWP" Value="Times New Roman" />
</OnPlatform>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</ContentPage.Resources>

<ContentPage.Content>
<StackLayout Padding="10, 0">
<Label Text="Text 1" />
<Label Text="Text 2" />

<Label Text="Text 3"


FontFamily="{x:Null}" />

<Label Text="Text 4" />


<Label Text="Text 5" />
</StackLayout>
</ContentPage.Content>
</ContentPage>

Em seguida, você descobre que, para uma da Label elementos, você deseja que todas as configurações de
propriedade na implícito Style , exceto para o FontFamily , que você deseja ser o valor padrão. Você pode definir
outra Style para essa finalidade, mas uma abordagem mais simples é simplesmente definir o FontFamily
propriedade de determinada Label ao x:Null , conforme demonstrado no Centro de Label .
Aqui está o programa em execução:

Observe que quatro dos Label elementos têm uma fonte com serifa, mas o centro Label tem a fonte sem serifa
padrão.
Extensão de marcação OnPlatform
O OnPlatform extensão de marcação permite que você personalize a aparência da interface do usuário em uma
base por plataforma. Ele fornece a mesma funcionalidade que o OnPlatform e On classes, mas com uma
representação mais concisa.
O OnPlatform extensão de marcação dá suporte a OnPlatformExtension classe, que define as propriedades a
seguir:
Default do tipo object , que você defina como um valor padrão a ser aplicado às propriedades que
representam as plataformas.
Android do tipo object , que é definido como um valor a ser aplicado no Android.
GTK do tipo object , que é definido como um valor a ser aplicado em plataformas GTK.
iOS do tipo object , que é definido como um valor a ser aplicado no iOS.
macOS do tipo object , que é definido como um valor a ser aplicado no macOS.
Tizen do tipo object , que é definido como um valor a ser aplicado na plataforma Tizen.
UWP do tipo object , que é definido como um valor a ser aplicado na plataforma Universal do Windows.
WPF do tipo object , que é definido como um valor a ser aplicado na plataforma Windows Presentation
Foundation.
Converter do tipo IValueConverter , que podem ser definidas um IValueConverter implementação.
ConverterParameter do tipo object , que é definido como um valor para passar para o IValueConverter
implementação.

NOTE
O analisador XAML permite que o OnPlatformExtension classe deverá ser abreviado como OnPlatform .

O Default é a propriedade de conteúdo do OnPlatformExtension . Portanto, para expressões de marcação XAML


expressadas com chaves, você pode eliminar o Default= faz parte da expressão fornecida que é o primeiro
argumento.

IMPORTANT
O analisador XAML espera que os valores do tipo correto serão fornecidos às propriedades consumindo o OnPlatform
extensão de marcação. Se a conversão de tipo for necessário, o OnPlatform extensão de marcação tentará executá-lo
usando os conversores de padrão fornecidos pelo xamarin. Forms. No entanto, há algumas conversões de tipo não podem
ser executadas pelos conversores padrão e nesses casos o Converter propriedade deve ser definida como um
IValueConverter implementação.

O demonstração OnPlatform página mostra como usar o OnPlatform extensão de marcação:

<BoxView Color="{OnPlatform Yellow, iOS=Red, Android=Green, UWP=Blue}"


WidthRequest="{OnPlatform 250, iOS=200, Android=300, UWP=400}"
HeightRequest="{OnPlatform 250, iOS=200, Android=300, UWP=400}"
HorizontalOptions="Center" />

Neste exemplo, todos os três OnPlatform expressões usam a versão abreviada do OnPlatformExtension nome de
classe. Os três OnPlatform conjunto de extensões de marcação a Color , WidthRequest , e HeightRequest
propriedades do BoxView como valores diferentes em iOS, Android e UWP. As extensões de marcação também
fornecem valores padrão para essas propriedades nas plataformas que não forem especificadas, eliminando o
Default= faz parte da expressão. Observe que as propriedades de extensão de marcação que são definidas são
separadas por vírgulas.
Aqui está o programa em execução:

Extensão de marcação OnIdiom


O OnIdiom extensões de marcação permite que você personalize a aparência da interface do usuário com base no
idioma do dispositivo em que o aplicativo está sendo executado. Ele dá suporte a OnIdiomExtension classe, que
define as propriedades a seguir:
Default do tipo object , que você defina como um valor padrão a ser aplicado às propriedades que
representam as expressões de dispositivo.
Phone do tipo object , que é definido como um valor a ser aplicado em telefones.
Tablet do tipo object , que é definido como um valor a ser aplicado em tablets.
Desktop do tipo object , que é definido como um valor a ser aplicado em plataformas de desktop.
TV do tipo object , que é definido como um valor a ser aplicado em plataformas de TV.
Watch do tipo object , que é definido como um valor a ser aplicado em plataformas de inspeção.
Converter do tipo IValueConverter , que podem ser definidas um IValueConverter implementação.
ConverterParameter do tipo object , que é definido como um valor para passar para o IValueConverter
implementação.

NOTE
O analisador XAML permite que o OnIdiomExtension classe deverá ser abreviado como OnIdiom .

O Default é a propriedade de conteúdo do OnIdiomExtension . Portanto, para expressões de marcação XAML


expressadas com chaves, você pode eliminar o Default= faz parte da expressão fornecida que é o primeiro
argumento.
IMPORTANT
O analisador XAML espera que os valores do tipo correto serão fornecidos às propriedades consumindo o OnIdiom
extensão de marcação. Se a conversão de tipo for necessário, o OnIdiom extensão de marcação tentará executá-lo usando
os conversores de padrão fornecidos pelo xamarin. Forms. No entanto, há algumas conversões de tipo não podem ser
executadas pelos conversores padrão e nesses casos o Converter propriedade deve ser definida como um
IValueConverter implementação.

O demonstração OnIdiom página mostra como usar o OnIdiom extensão de marcação:

<BoxView Color="{OnIdiom Yellow, Phone=Red, Tablet=Green, Desktop=Blue}"


WidthRequest="{OnIdiom 100, Phone=200, Tablet=300, Desktop=400}"
HeightRequest="{OnIdiom 100, Phone=200, Tablet=300, Desktop=400}"
HorizontalOptions="Center" />

Neste exemplo, todos os três OnIdiom expressões usam a versão abreviada do OnIdiomExtension nome de classe.
Os três OnIdiom conjunto de extensões de marcação a Color , WidthRequest , e HeightRequest propriedades do
BoxView como valores diferentes em telefone, tablet e expressões da área de trabalho. As extensões de marcação
também fornecem valores padrão para essas propriedades em que as linguagens que não forem especificadas,
eliminando o Default= faz parte da expressão. Observe que as propriedades de extensão de marcação que são
definidas são separadas por vírgulas.
Aqui está o programa em execução:

Definir suas próprias extensões de marcação


Se você tiver encontrado uma necessidade de uma extensão de marcação XAML que não está disponível no
xamarin. Forms, você pode criar seu próprio.

Links relacionados
Extensões de marcação (amostra)
Capítulo de extensões de marcação XAML do xamarin. Forms book
Dicionários de recurso
Estilos dinâmicos
Associação de dados
Criando extensões de marcação XAML
12/04/2019 • 10 minutes to read

baixar o exemplo
No nível de programação, uma extensão de marcação XAML é uma classe que implementa o IMarkupExtension
ou IMarkupExtension<T> interface. Você pode explorar o código-fonte das extensões de marcação padrão descrito
abaixo na MarkupExtensions diretório do repositório GitHub do xamarin. Forms.
Também é possível definir suas próprias extensões de marcação XAML personalizados derivando
IMarkupExtension ou IMarkupExtension<T> . Use o formulário genérico se a extensão de marcação obtém um valor
de um tipo específico. Esse é o caso com várias das extensões de marcação do xamarin. Forms:
TypeExtension deriva de IMarkupExtension<Type>
ArrayExtension deriva de IMarkupExtension<Array>
DynamicResourceExtension deriva de IMarkupExtension<DynamicResource>
BindingExtension deriva de IMarkupExtension<BindingBase>
ConstraintExpression deriva de IMarkupExtension<Constraint>

Os dois IMarkupExtension interfaces definir apenas um método de cada um, chamado ProvideValue :

public interface IMarkupExtension


{
object ProvideValue(IServiceProvider serviceProvider);
}

public interface IMarkupExtension<out T> : IMarkupExtension


{
new T ProvideValue(IServiceProvider serviceProvider);
}

Uma vez que IMarkupExtension<T> deriva IMarkupExtension e inclui o new palavra-chave na ProvideValue ,
contém os ProvideValue métodos.
Com muita frequência, extensões de marcação XAML definem propriedades que contribuem para o valor de
retorno. (É a óbvia exceção NullExtension , no qual ProvideValue simplesmente retorna null .) O ProvideValue
método tem um único argumento do tipo IServiceProvider que será discutido neste artigo.

Para especificar a cor de uma extensão de marcação


A seguinte extensão de marcação XAML permite que você construa uma Color usando componentes de matiz,
saturação e luminosidade de valor. Ele define quatro propriedades para os quatro componentes de cor, incluindo
um componente alfa que é inicializado como 1. A classe deriva IMarkupExtension<Color> para indicar um Color
retornar valor:
public class HslColorExtension : IMarkupExtension<Color>
{
public double H { set; get; }

public double S { set; get; }

public double L { set; get; }

public double A { set; get; } = 1.0;

public Color ProvideValue(IServiceProvider serviceProvider)


{
return Color.FromHsla(H, S, L, A);
}

object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider)


{
return (this as IMarkupExtension<Color>).ProvideValue(serviceProvider);
}
}

Porque IMarkupExtension<T> deriva IMarkupExtension , a classe deve conter dois ProvideValue métodos, que
retorna Color e outro que retorna object , mas o segundo método pode simplesmente chamar o primeiro
método.
O demonstração de cor HSL página mostra uma variedade de formas HslColorExtension pode aparecer em um
arquivo XAML para especificar a cor de um BoxView :
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MarkupExtensions"
x:Class="MarkupExtensions.HslColorDemoPage"
Title="HSL Color Demo">

<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="BoxView">
<Setter Property="WidthRequest" Value="80" />
<Setter Property="HeightRequest" Value="80" />
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>

<StackLayout>
<BoxView>
<BoxView.Color>
<local:HslColorExtension H="0" S="1" L="0.5" A="1" />
</BoxView.Color>
</BoxView>

<BoxView>
<BoxView.Color>
<local:HslColor H="0.33" S="1" L="0.5" />
</BoxView.Color>
</BoxView>

<BoxView Color="{local:HslColorExtension H=0.67, S=1, L=0.5}" />

<BoxView Color="{local:HslColor H=0, S=0, L=0.5}" />

<BoxView Color="{local:HslColor A=0.5}" />


</StackLayout>
</ContentPage>

Observe que, quando HslColorExtension é uma marca XML, as quatro propriedades são definidas como atributos,
mas quando ela aparecer entre chaves, as quatro propriedades são separadas por vírgulas sem aspas. Os valores
padrão para H , S , e L são 0 e o valor padrão de A é 1, portanto, essas propriedades podem ser omitidas se
você deseja que eles são definidos como valores padrão. O último exemplo mostra um exemplo onde a
luminosidade é 0, que normalmente resulta em preto, mas o canal alfa é 0,5, para que ele é parcialmente
transparente e aparece cinza o plano de fundo branca da página:
Uma extensão de marcação para acessar os Bitmaps
O argumento ProvideValue é um objeto que implementa o IServiceProvider interface, que é definida no .NET
System namespace. Essa interface tem um membro, um método chamado GetService com um Type argumento.

O ImageResourceExtension classe mostrado a seguir mostra um uso possível dos IServiceProvider e GetService
para obter um IXmlLineInfoProvider objeto que pode fornecer informações de linha e o caractere que indica onde
um determinado erro foi detectado. Nesse caso, uma exceção é gerada quando o Source propriedade não foi
definida:

[ContentProperty("Source")]
class ImageResourceExtension : IMarkupExtension<ImageSource>
{
public string Source { set; get; }

public ImageSource ProvideValue(IServiceProvider serviceProvider)


{
if (String.IsNullOrEmpty(Source))
{
IXmlLineInfoProvider lineInfoProvider = serviceProvider.GetService(typeof(IXmlLineInfoProvider))
as IXmlLineInfoProvider;
IXmlLineInfo lineInfo = (lineInfoProvider != null) ? lineInfoProvider.XmlLineInfo : new
XmlLineInfo();
throw new XamlParseException("ImageResourceExtension requires Source property to be set",
lineInfo);
}

string assemblyName = GetType().GetTypeInfo().Assembly.GetName().Name;


return ImageSource.FromResource(assemblyName + "." + Source,
typeof(ImageResourceExtension).GetTypeInfo().Assembly);
}

object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider)


{
return (this as IMarkupExtension<ImageSource>).ProvideValue(serviceProvider);
}
}

ImageResourceExtension é útil quando um arquivo XAML precisa acessar um arquivo de imagem armazenado
como um recurso incorporado no projeto da biblioteca .NET Standard. Ele usa o Source propriedade para chamar
estático ImageSource.FromResource método. Esse método requer um nome de recurso totalmente qualificado, que
consiste o nome do assembly, o nome da pasta e o nome do arquivo separados por pontos. O segundo
argumento para o ImageSource.FromResource método fornece o nome do assembly e só é necessária para
compilações de versão na UWP. Independentemente disso, ImageSource.FromResource deve ser chamado a partir
do assembly que contém o bitmap, o que significa que essa extensão de recurso XAML não pode ser parte de
uma biblioteca externa, a menos que as imagens também são nessa biblioteca. (Consulte a imagens inseridas
artigo para obter mais informações sobre como acessar os bitmaps armazenados como recursos incorporados.)
Embora ImageResourceExtension exige as Source propriedade seja definida, o Source propriedade é indicada em
um atributo, como a propriedade de conteúdo da classe. Isso significa que o Source= parte da expressão entre
chaves pode ser omitido. No demonstração do recurso de imagem página, o Image elementos buscar duas
imagens usando o nome de pasta e o nome do arquivo separados por pontos:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MarkupExtensions"
x:Class="MarkupExtensions.ImageResourceDemoPage"
Title="Image Resource Demo">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>

<Image Source="{local:ImageResource Images.SeatedMonkey.jpg}"


Grid.Row="0" />

<Image Source="{local:ImageResource Images.FacePalm.jpg}"


Grid.Row="1" />

</Grid>
</ContentPage>

Aqui está o programa em execução:

Provedores de serviço
Usando o IServiceProvider argumento para ProvideValue , extensões de marcação XAML podem obter acesso a
informações úteis sobre o arquivo XAML no qual eles estão sendo usados. Mas, para usar o IServiceProvider
argumento com êxito, você precisa saber que tipo de serviços estão disponíveis em contextos específicos. A
melhor maneira de entender esse recurso está estudando o código-fonte das extensões de marcação XAML
existentes na MarkupExtensions pasta no repositório do xamarin. Forms no GitHub. Lembre-se de que alguns
tipos de serviços são internos ao xamarin. Forms.
Em algumas extensões de marcação XAML, esse serviço pode ser útil:

IProvideValueTarget provideValueTarget = serviceProvider.GetService(typeof(IProvideValueTarget)) as


IProvideValueTarget;

O IProvideValueTarget interface define duas propriedades, TargetObject e TargetProperty . Quando essas


informações são obtidas na ImageResourceExtension classe, TargetObject é o Image e TargetProperty é um
BindableProperty do objeto para o Source propriedade do Image . Essa é a propriedade no qual a extensão de
marcação XAML foi definida.
O GetService chamada com um argumento typeof(IProvideValueTarget) , na verdade, retorna um objeto do tipo
SimpleValueTargetProvider , que é definido no Xamarin.Forms.Xaml.Internals namespace. Se você converter o
valor de retorno GetService a esse tipo, você também pode acessar uma ParentObjects propriedade, que é uma
matriz que contém o Image elemento, o Grid pai e o ImageResourceDemoPage pai do Grid .

Conclusão
Extensões de marcação XAML desempenham um papel vital em XAML ao estender a capacidade de definir os
atributos de uma variedade de fontes. Além disso, se as extensões de marcação XAML existentes não fornecerem
exatamente o que você precisa, você também pode escrever seus próprios.

Links relacionados
Extensões de marcação (amostra)
Capítulo de extensões de marcação XAML do xamarin. Forms book
Modificadores de campo XAML no xamarin. Forms
12/04/2019 • 2 minutes to read

O x:FieldModifier atributo namespace Especifica o nível de acesso para campos gerados para elementos XAML
nomeados.

Visão geral
Os valores válidos do atributo são:
Public – Especifica que o campo gerado para o elemento XAML public .
NotPublic – Especifica que o campo gerado para o elemento XAML internal ao assembly.

Se o valor do atributo não está definido, o campo gerado para o elemento será private .
As seguintes condições devem ser atendidas para uma x:FieldModifier atributo a ser processado:
O elemento de nível superior XAML deve ser um válido x:Class .
O elemento atual XAML tem um x:Name especificado.
O XAML a seguir mostra exemplos de configuração do atributo:

<Label x:Name="privateLabel" />


<Label x:Name="internalLabel" x:FieldModifier="NotPublic" />
<Label x:Name="publicLabel" x:FieldModifier="Public" />

NOTE
O x:FieldModifier atributo não pode ser usado para especificar o nível de acesso de uma classe XAML.
Passando argumentos em XAML
12/04/2019 • 6 minutes to read

baixar o exemplo
Este artigo demonstra como usar os atributos XAML que podem ser usados para passar argumentos para o
construtor não padrão, para chamar métodos de fábrica e para especificar o tipo de um argumento genérico.

Visão geral
Ele geralmente é necessário instanciar objetos com construtores que requerem argumentos, ou chamando um
método de criação estáticos. Isso pode ser obtido em XAML usando o x:Arguments e x:FactoryMethod atributos:
O x:Arguments atributo é usado para especificar argumentos de construtor para um construtor não padrão ou
para uma declaração de objeto do método de fábrica. Para obter mais informações, consulte passar
argumentos de construtor.
O x:FactoryMethod atributo é usado para especificar um método de fábrica que pode ser usado para inicializar
um objeto. Para obter mais informações, consulte chamando métodos de fábrica.
Além disso, o x:TypeArguments atributo pode ser usado para especificar os argumentos de tipo genérico para o
construtor de um tipo genérico. Para obter mais informações, consulte especificando um argumento de tipo
genérico.

Passando argumentos de construtor


Argumentos podem ser passados para um construtor não padrão usando o x:Arguments atributo. Cada
argumento de construtor deve ser delimitado dentro de um elemento XML que representa o tipo do argumento.
Xamarin. Forms dá suporte aos seguintes elementos para tipos básicos:
x:Object
x:Boolean
x:Byte
x:Int16
x:Int32
x:Int64
x:Single
x:Double
x:Decimal
x:Char
x:String
x:TimeSpan
x:Array
x:DateTime

O exemplo de código a seguir demonstra como usar o x:Arguments atributo com três Color construtores:
<BoxView HeightRequest="150" WidthRequest="150" HorizontalOptions="Center">
<BoxView.Color>
<Color>
<x:Arguments>
<x:Double>0.9</x:Double>
</x:Arguments>
</Color>
</BoxView.Color>
</BoxView>
<BoxView HeightRequest="150" WidthRequest="150" HorizontalOptions="Center">
<BoxView.Color>
<Color>
<x:Arguments>
<x:Double>0.25</x:Double>
<x:Double>0.5</x:Double>
<x:Double>0.75</x:Double>
</x:Arguments>
</Color>
</BoxView.Color>
</BoxView>
<BoxView HeightRequest="150" WidthRequest="150" HorizontalOptions="Center">
<BoxView.Color>
<Color>
<x:Arguments>
<x:Double>0.8</x:Double>
<x:Double>0.5</x:Double>
<x:Double>0.2</x:Double>
<x:Double>0.5</x:Double>
</x:Arguments>
</Color>
</BoxView.Color>
</BoxView>

O número de elementos dentro de x:Arguments marca e os tipos desses elementos devem corresponder a um
dos Color construtores. O Color construtor com um único parâmetro requer um valor de escala de cinza de 0
(preto) a 1 (branco). O Color construtor com três parâmetros requer um valor de vermelho, verde e azul,
variando de 0 a 1. O Color construtor com quatro parâmetros adiciona um canal alfa, como o quarto parâmetro.
As capturas de tela a seguir mostram o resultado da chamada a cada Color construtor com os valores de
argumento especificado:
Chamar métodos de fábrica
Métodos de fábrica podem ser chamados em XAML, especificando o método nome usando o x:FactoryMethod
atributo e seus argumentos usando o x:Arguments atributo. Um método de fábrica é um public static método
que retorna os valores do mesmo tipo que a classe ou estrutura que define os métodos ou objetos.
O Color estrutura define vários métodos de fábrica e o exemplo de código a seguir demonstra a chamada três
argumentos:
<BoxView HeightRequest="150" WidthRequest="150" HorizontalOptions="Center">
<BoxView.Color>
<Color x:FactoryMethod="FromRgba">
<x:Arguments>
<x:Int32>192</x:Int32>
<x:Int32>75</x:Int32>
<x:Int32>150</x:Int32>
<x:Int32>128</x:Int32>
</x:Arguments>
</Color>
</BoxView.Color>
</BoxView>
<BoxView HeightRequest="150" WidthRequest="150" HorizontalOptions="Center">
<BoxView.Color>
<Color x:FactoryMethod="FromHsla">
<x:Arguments>
<x:Double>0.23</x:Double>
<x:Double>0.42</x:Double>
<x:Double>0.69</x:Double>
<x:Double>0.7</x:Double>
</x:Arguments>
</Color>
</BoxView.Color>
</BoxView>
<BoxView HeightRequest="150" WidthRequest="150" HorizontalOptions="Center">
<BoxView.Color>
<Color x:FactoryMethod="FromHex">
<x:Arguments>
<x:String>#FF048B9A</x:String>
</x:Arguments>
</Color>
</BoxView.Color>
</BoxView>

O número de elementos dentro de x:Arguments marca e os tipos desses elementos devem coincidir com os
argumentos de método de fábrica que está sendo chamado. O FromRgba método de fábrica exige quatro Int32
parâmetros, que representam os valores de vermelhos, verdes, azuis e alfabéticos, variando de 0 a 255,
respectivamente. O FromHsla método de fábrica exige quatro Double parâmetros, que representam o matiz,
saturação, luminosidade e valores alfa, variando de 0 a 1, respectivamente. O FromHex método de fábrica exige
uma String que representa o hexadecimal (A) de cor RGB.
As capturas de tela a seguir mostram o resultado da chamada a cada Color método de fábrica com os valores de
argumento especificado:
Especificando um argumento de tipo genérico
Argumentos de tipo genérico para o construtor de um tipo genérico podem ser especificados usando o
x:TypeArguments de atributo, conforme demonstrado no exemplo de código a seguir:

<ContentPage ...>
<StackLayout>
<StackLayout.Margin>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="0,20,0,0" />
<On Platform="Android" Value="5, 10" />
<On Platform="UWP" Value="10" />
</OnPlatform>
</StackLayout.Margin>
</StackLayout>
</ContentPage>

O OnPlatform classe é uma classe genérica e deve ser instanciado com um x:TypeArguments atributo que
corresponde ao tipo de destino. No On classe, o Platform atributo pode aceitar um único string valor ou
vários delimitada por vírgula string valores. Neste exemplo, o StackLayout.Margin estiver definida como uma
plataforma específica Thickness .

Resumo
Este artigo demonstrou usando os atributos XAML que podem ser usados para passar argumentos para o
construtor não padrão, para chamar métodos de fábrica e para especificar o tipo de um argumento genérico.

Links relacionados
Namespaces XAML
Passando argumentos de construtor (amostra)
Chamar métodos de fábrica (amostra)
Propriedades vinculáveis
12/04/2019 • 16 minutes to read

baixar o exemplo
No xamarin. Forms, a funcionalidade de propriedades comuns de runtime (CLR ) de linguagem é estendida por
propriedades associáveis. Uma propriedade associável é um tipo especial de propriedade, em que o valor da
propriedade é controlado pelo sistema de propriedades de xamarin. Forms. Este artigo fornece uma introdução a
propriedades associáveis e demonstra como criar e consumi-los.

Visão geral
Propriedades vinculáveis estendem a funcionalidade de propriedade CLR, fazendo uma propriedade com um
BindableProperty tipo, em vez de uma propriedade com um campo de suporte. A finalidade de propriedades
vinculáveis é fornecer um sistema de propriedade que dá suporte à vinculação de dados, estilos, modelos e
valores definidos por meio de relações pai-filho. Além disso, propriedades vinculáveis podem fornecer valores
padrão, validação de valores de propriedade e retornos de chamada que monitoram as alterações de propriedade.
As propriedades devem ser implementadas como propriedades vinculáveis para dar suporte a um ou mais dos
seguintes recursos:
Atuando como uma opção válida destino propriedade para associação de dados.
Definindo a propriedade por meio de um estilo.
Fornecendo um valor de propriedade padrão que é diferente do padrão para o tipo da propriedade.
Validando o valor da propriedade.
Monitoramento de alterações de propriedade.
Exemplos de propriedades vinculáveis do xamarin. Forms Label.Text , Button.BorderRadius , e
StackLayout.Orientation . Cada propriedade associável tem um correspondente public static readonly
propriedade do tipo BindableProperty que é exposto na mesma classe e que é o identificador da propriedade
associável. Por exemplo, o identificador a propriedade associável correspondente para o Label.Text é de
propriedade Label.TextProperty .

Criar e consumir uma propriedade associável


O processo para a criação de uma propriedade associável é da seguinte maneira:
1. Criar uma BindableProperty instância com um dos BindableProperty.Create sobrecargas de método.
2. Definir acessadores de propriedade para o BindableProperty instância.
Observe que todos os BindableProperty instâncias devem ser criadas no thread da interface do usuário. Isso
significa que somente o código que é executado no thread da interface do usuário pode obter ou definir o valor de
uma propriedade associável. No entanto, BindableProperty instâncias podem ser acessadas de outros threads por
marshaling para o thread de interface do usuário com o Device.BeginInvokeOnMainThread método.
Criação de uma propriedade
Para criar uma BindableProperty instância, a classe recipiente deve derivar de BindableObject classe. No entanto,
o BindableObject classe é alta na hierarquia de classe, portanto, a maioria das classes usadas para propriedades
vinculáveis do suporte ao usuário interface funcionalidade.
Uma propriedade vinculável pode ser criada, declarando uma public static readonly propriedade do tipo
BindableProperty . A propriedade associável deve ser definida para o valor retornado de um dos
BindableProperty.Create sobrecargas de método. A declaração deve ser dentro do corpo de BindableObject
derivado da classe, mas fora das definições de membro.
No mínimo, um identificador deve ser especificado durante a criação de um BindableProperty , juntamente com
os seguintes parâmetros:
O nome da BindableProperty .
O tipo da propriedade.
O tipo do objeto proprietário.
O valor padrão para a propriedade. Isso garante que a propriedade sempre retorna um valor padrão específico
quando ele não for definido, e pode ser diferente do valor padrão para o tipo da propriedade. O valor padrão
será restaurado quando o ClearValue método é chamado na propriedade associável.
O código a seguir mostra um exemplo de uma propriedade vinculável, com um identificador e os valores para os
quatro parâmetros obrigatórios:

public static readonly BindableProperty EventNameProperty =


BindableProperty.Create ("EventName", typeof(string), typeof(EventToCommandBehavior), null);

Isso cria uma BindableProperty instância denominada EventName , do tipo string . A propriedade pertencente a
EventToCommandBehavior de classe e tem um valor padrão de null . A convenção de nomenclatura para
propriedades vinculáveis é que o identificador de propriedade associável deve corresponder ao nome de
propriedade especificado no Create método, com "Propriedade" acrescentada a ela. Portanto, no exemplo acima,
o identificador de propriedade associável é EventNameProperty .
Opcionalmente, durante a criação de um BindableProperty da instância, as seguintes parâmetros podem ser
especificados:
O modo de associação. Isso é usado para especificar a direção na qual as alterações de valor de propriedade
serão propagadas. No modo de associação padrão, as alterações sejam propagadas do fonte para o destino.
Um delegado de validação que será chamado quando o valor da propriedade é definido. Para obter mais
informações, consulte retornos de chamada de validação.
Um delegado de alteração de propriedade que será chamado quando o valor da propriedade foi alterada. Para
obter mais informações, consulte detectando alterações de propriedade.
Uma propriedade alterando o delegado que será chamado quando o valor da propriedade será alterada. Esse
delegado tem a mesma assinatura que o delegado de propriedade alterada.
Um delegado de valor de retornos que será chamado quando o valor da propriedade foi alterada. Para obter
mais informações, consulte forçar retornos de chamada de valor.
Um Func que é usado para inicializar um valor de propriedade padrão. Para obter mais informações, consulte
criação de um valor padrão com um Func.
Criação de acessadores
Acessadores de propriedade são necessários para usar a sintaxe de propriedade para acessar uma propriedade
associável. O Get acessador deve retornar o valor contido na propriedade associável correspondente. Isso pode
ser obtido chamando o GetValue método, passando o identificador de propriedade associável no qual obter o
valor e, em seguida, convertendo os resultados para o tipo solicitado. O Set acessador deve definir o valor da
propriedade associável correspondente. Isso pode ser obtido chamando o SetValue método, passando o
identificador de propriedade associável no qual definir o valor e o valor a ser definido.
O exemplo de código a seguir mostra os acessadores para o EventName propriedade associável:
public string EventName {
get { return (string)GetValue (EventNameProperty); }
set { SetValue (EventNameProperty, value); }
}

Consumindo uma propriedade associável


Quando uma propriedade vinculável tiver sido criada, ele pode ser consumido de XAML ou código. No XAML,
isso é feito declarando um namespace com um prefixo, com a declaração de namespace que indica o nome do
namespace CLR e, opcionalmente, um nome de assembly. Para obter mais informações, consulte Namespaces de
XAML.
O exemplo de código a seguir demonstra um namespace XAML para um tipo personalizado que contém uma
propriedade vinculável, que é definida dentro do mesmo assembly como o código do aplicativo que está fazendo
referência ao tipo personalizado:

<ContentPage ... xmlns:local="clr-namespace:EventToCommandBehavior" ...>


...
</ContentPage>

A declaração de namespace é usada ao definir o EventName propriedade associável, conforme demonstrado no


exemplo de código XAML a seguir:

<ListView ...>
<ListView.Behaviors>
<local:EventToCommandBehavior EventName="ItemSelected" ... />
</ListView.Behaviors>
</ListView>

O código C# equivalente é mostrado no exemplo de código a seguir:

var listView = new ListView ();


listView.Behaviors.Add (new EventToCommandBehavior {
EventName = "ItemSelected",
...
});

Cenários avançados
Ao criar uma BindableProperty da instância, há um número de parâmetros opcionais que podem ser definidas
para habilitar cenários avançados de propriedade associável. Essa seção explora esses cenários.
Detectando alterações de propriedade
Um static método de retorno de chamada de propriedade alterada pode ser registrado com uma propriedade
vinculável, especificando as propertyChanged parâmetro para o BindableProperty.Create método. O método de
retorno de chamada especificado será invocado quando o valor da propriedade associável é alterada.
O seguinte exemplo de código mostra como o EventName registra a propriedade associável a OnEventNameChanged
método como um método de retorno de chamada de propriedade alterada:
public static readonly BindableProperty EventNameProperty =
BindableProperty.Create (
"EventName", typeof(string), typeof(EventToCommandBehavior), null, propertyChanged: OnEventNameChanged);
...

static void OnEventNameChanged (BindableObject bindable, object oldValue, object newValue)


{
// Property changed implementation goes here
}

No método de retorno de chamada de propriedade alterada, o BindableObject parâmetro é usado para indicar
qual instância da classe proprietária reportou uma alteração e os valores dos dois object parâmetros
representam os valores novos e antigos de a propriedade associável.
Retornos de chamadas de validação
Um static método de retorno de chamada de validação pode ser registrado com uma propriedade vinculável,
especificando as validateValue parâmetro para o BindableProperty.Create método. O método de retorno de
chamada especificado será chamado quando o valor da propriedade associável é definido.
O seguinte exemplo de código mostra como o Angle registra a propriedade associável a IsValidValue método
como um método de retorno de chamada de validação:

public static readonly BindableProperty AngleProperty =


BindableProperty.Create ("Angle", typeof(double), typeof(HomePage), 0.0, validateValue: IsValidValue);
...

static bool IsValidValue (BindableObject view, object value)


{
double result;
bool isDouble = double.TryParse (value.ToString (), out result);
return (result >= 0 && result <= 360);
}

Retornos de chamada de validação são fornecidos com um valor e deve retornar true se o valor é válido para a
propriedade, caso contrário, false . Uma exceção será gerada se um retorno de chamada de validação retornar
false , que deve ser tratado pelo desenvolvedor. Um uso típico de um método de retorno de chamada de
validação é restringir os valores de números inteiros ou duplos quando a propriedade associável é definida. Por
exemplo, o IsValidValue método verifica que o valor da propriedade é um double dentro do intervalo de 0 a
360.
Forçar retornos de chamada de valor
Um static forçar o valor do método de retorno de chamada pode ser registrado com uma propriedade
vinculável, especificando as coerceValue parâmetro para o BindableProperty.Create método. O método de
retorno de chamada especificado será invocado quando o valor da propriedade associável é alterada.
Forçar retornos de chamada são usados para forçar uma reavaliação de uma propriedade associável quando o
valor da propriedade muda de valor. Por exemplo, um retorno de chamada de valor de retornos pode ser usado
para garantir que o valor de uma propriedade associável não é maior que o valor de outra propriedade associável.
O seguinte exemplo de código mostra como o Angle registra a propriedade associável a CoerceAngle método
como um método de retorno de chamada de valor retornos:
public static readonly BindableProperty AngleProperty = BindableProperty.Create (
"Angle", typeof(double), typeof(HomePage), 0.0, coerceValue: CoerceAngle);
public static readonly BindableProperty MaximumAngleProperty = BindableProperty.Create (
"MaximumAngle", typeof(double), typeof(HomePage), 360.0);
...

static object CoerceAngle (BindableObject bindable, object value)


{
var homePage = bindable as HomePage;
double input = (double)value;

if (input > homePage.MaximumAngle) {


input = homePage.MaximumAngle;
}

return input;
}

O CoerceAngle método verifica o valor da MaximumAngle propriedade e se o Angle o valor da propriedade é


maior do que ele, ele força o valor para o MaximumAngle valor da propriedade.
Criação de um valor padrão com um Func
Um Func pode ser usado para inicializar o valor padrão de uma propriedade vinculável, conforme demonstrado
no exemplo de código a seguir:

public static readonly BindableProperty SizeProperty =


BindableProperty.Create ("Size", typeof(double), typeof(HomePage), 0.0,
defaultValueCreator: bindable => Device.GetNamedSize (NamedSize.Large, (Label)bindable));

O defaultValueCreator parâmetro é definido como um Func que invoca a Device.GetNamedSize método para
retornar uma double que representa o tamanho nomeado para a fonte que é usada em um Label na plataforma
nativa.

Resumo
Este artigo fornece uma introdução para propriedades vinculáveis e demonstrou como criar e consumi-los. Uma
propriedade associável é um tipo especial de propriedade, em que o valor da propriedade é controlado pelo
sistema de propriedades de xamarin. Forms.

Links relacionados
Namespaces XAML
Eventos para comportamento de comando (amostra)
Retorno de chamada de validação (amostra)
Impor o valor de retorno de chamada (exemplo)
BindableProperty
BindableObject
Propriedades anexadas
12/04/2019 • 9 minutes to read

baixar o exemplo
Uma propriedade anexada é um tipo especial de propriedade associável, definido em uma classe, mas anexado
a outros objetos e reconhecível no XAML como um atributo que contém uma classe e um nome de propriedade
separados por um período. Este artigo fornece uma introdução para propriedades anexadas e demonstra como
criar e consumi-los.

Visão geral
Anexado a habilitação de propriedades para atribuir um valor para uma propriedade de sua própria classe não
define um objeto. Por exemplo, filho, elementos podem usar propriedades para informar o usuário de seu
elemento pai como devem ser apresentados na interface do usuário anexadas. O Grid controle permite que a
linha e coluna de um filho seja especificado definindo a Grid.Row e Grid.Column propriedades anexadas.
Grid.Row e Grid.Column são propriedades anexadas, porque eles são definidos em elementos que são filhos de
um Grid , em vez de no Grid em si.
Propriedades vinculáveis devem ser implementadas como propriedades anexadas nos seguintes cenários:
Quando é necessário ter um mecanismo de configuração de propriedade disponível para classes diferentes
da definição de classe.
Quando a classe representa um serviço que precisa ser facilmente integrados com outras classes.
Para obter mais informações sobre propriedades vinculáveis, consulte propriedades vinculáveis.

Criar e consumir uma propriedade anexada


O processo para a criação de uma propriedade anexada é da seguinte maneira:
1. Criar uma BindableProperty instância com um dos CreateAttached sobrecargas de método.
2. Fornecer static Get PropertyName e Set PropertyName métodos como acessadores para a propriedade
anexada.
Criação de uma propriedade
Ao criar uma propriedade anexada para uso em outros tipos, a classe em que a propriedade é criada não precisa
derivar BindableObject . No entanto, o alvo propriedade para acessadores deve ser do ou derivar dele
BindableObject .

Uma propriedade anexada pode ser criada, declarando uma public static readonly propriedade do tipo
BindableProperty . A propriedade associável deve ser definida para o valor retornado de um dos
BindableProperty.CreateAttached sobrecargas de método. A declaração deve ser dentro do corpo da classe
proprietária, mas fora das definições de membro.
O código a seguir mostra um exemplo de uma propriedade anexada:

public static readonly BindableProperty HasShadowProperty =


BindableProperty.CreateAttached ("HasShadow", typeof(bool), typeof(ShadowEffect), false);

Isso cria uma propriedade anexada nomeada HasShadow , do tipo bool . A propriedade pertencente a
ShadowEffect de classe e tem um valor padrão de false . A convenção de nomenclatura para propriedades
anexadas é que o identificador da propriedade anexada deve corresponder ao nome de propriedade especificado
no CreateAttached método, com "Propriedade" acrescentada a ela. Portanto, no exemplo acima, o identificador
da propriedade anexada é HasShadowProperty .
Para obter mais informações sobre como criar propriedades vinculáveis, incluindo os parâmetros que podem ser
especificados durante a criação, consulte criando e consumindo uma propriedade vinculável.
Criação de acessadores
Estática Get PropertyName e Set PropertyName métodos são necessários como acessadores para a
propriedade anexada, caso contrário, o sistema de propriedades não poderá usar o propriedade anexada. O Get
PropertyName acessador deve estar de acordo com a seguinte assinatura:

public static valueType GetPropertyName(BindableObject target)

O Get PropertyName acessador deve retornar o valor contido no correspondente BindableProperty campo
para a propriedade anexada. Isso pode ser obtido chamando o GetValue método, passando o identificador de
propriedade associável no qual obter o valor e, em seguida, converter o valor resultante para o tipo solicitado.
O Set PropertyName acessador deve estar de acordo com a seguinte assinatura:

public static void SetPropertyName(BindableObject target, valueType value)

O Set PropertyName acessador deve definir o valor correspondente BindableProperty campo para a
propriedade anexada. Isso pode ser obtido chamando o SetValue método, passando o identificador de
propriedade associável no qual definir o valor e o valor a ser definido.
Para ambos os acessadores, o alvo objeto deve ser de, ou derivar dele BindableObject .
O exemplo de código a seguir mostra os acessadores para o HasShadow propriedade anexada:

public static bool GetHasShadow (BindableObject view)


{
return (bool)view.GetValue (HasShadowProperty);
}

public static void SetHasShadow (BindableObject view, bool value)


{
view.SetValue (HasShadowProperty, value);
}

Consumindo uma propriedade anexada


Quando uma propriedade anexada tiver sido criada, ele pode ser consumido de XAML ou código. No XAML,
isso é feito declarando um namespace com um prefixo, com a declaração de namespace que indica o nome do
namespace de Common Language Runtime (CLR ) e, opcionalmente, um nome de assembly. Para obter mais
informações, consulte Namespaces de XAML.
O exemplo de código a seguir demonstra um namespace XAML para um tipo personalizado que contém uma
propriedade anexada, que é definida dentro do mesmo assembly como o código do aplicativo que está fazendo
referência ao tipo personalizado:

<ContentPage ... xmlns:local="clr-namespace:EffectsDemo" ...>


...
</ContentPage>
A declaração de namespace é usada ao configurar a propriedade anexada em um controle específico, como
demonstrado no exemplo de código XAML a seguir:

<Label Text="Label Shadow Effect" local:ShadowEffect.HasShadow="true" />

O código C# equivalente é mostrado no exemplo de código a seguir:

var label = new Label { Text = "Label Shadow Effect" };


ShadowEffect.SetHasShadow (label, true);

Consumindo uma propriedade anexada com um estilo


Propriedades anexadas também podem ser adicionadas a um controle por um estilo. Mostra o exemplo de
código XAML abaixo uma explícita estilo que usa o HasShadow anexados a propriedade, que pode ser aplicada a
Label controles:

<Style x:Key="ShadowEffectStyle" TargetType="Label">


<Style.Setters>
<Setter Property="local:ShadowEffect.HasShadow" Value="true" />
</Style.Setters>
</Style>

O Style pode ser aplicado a um Label definindo seu Style propriedade para o Style instância usando o
StaticResource extensão de marcação, conforme demonstrado no exemplo de código a seguir:

<Label Text="Label Shadow Effect" Style="{StaticResource ShadowEffectStyle}" />

Para obter mais informações sobre estilos, consulte estilos.

Cenários avançados
Ao criar uma propriedade anexada, há um número de parâmetros opcionais que podem ser definidas para
habilitar cenários avançados de propriedade anexada. Isso inclui a detecção de alterações de propriedade,
validando valores de propriedade e coerção de valores de propriedade. Para obter mais informações, consulte
cenários avançados de.

Resumo
Este artigo fornece uma introdução para propriedades anexadas e demonstrou como criar e consumi-los. Uma
propriedade anexada é um tipo especial de propriedade associável, definido em uma classe, mas anexado a
outros objetos e reconhecível no XAML como atributos que contêm uma classe e um nome de propriedade
separados por um período.

Links relacionados
Propriedades vinculáveis
Namespaces XAML
Efeito de sombra (amostra)
BindableProperty
BindableObject
Dicionários de recursos
12/04/2019 • 16 minutes to read

baixar o exemplo
Recursos XAML são definições de objetos que podem ser compartilhados e reutilizados em todo um aplicativo
xamarin. Forms.
Esses objetos de recurso são armazenados em um dicionário de recursos. Este artigo descreve como criar e
consumir um dicionário de recursos e como mesclar os dicionários de recursos.

Visão geral
Um ResourceDictionary é um repositório para os recursos que são usados por um aplicativo xamarin. Forms.
Recursos comuns que são armazenados em uma ResourceDictionary incluem estilos, modelos de controle,
modelos de dados, cores e conversores.
No XAML, recursos que são armazenados em uma ResourceDictionary podem ser recuperadas e aplicadas aos
elementos usando o StaticResource extensão de marcação. No c#, os recursos também podem ser definidos em
um ResourceDictionary e, em seguida, recuperados e aplicados aos elementos usando um indexador de cadeia
de caracteres. No entanto, há pouca vantagem em usar um ResourceDictionary no c#, como objetos
compartilhados podem simplesmente ser armazenados como campos ou propriedades e acessados diretamente
sem ter que primeiro recuperá-los de um dicionário.

Criar e consumir um ResourceDictionary


Recursos são definidos em uma ResourceDictionary isto é, em seguida, definido como um dos seguintes
Resources propriedades:

O Resources propriedade de qualquer classe que deriva de Application


O Resources propriedade de qualquer classe que deriva de VisualElement

Um programa do xamarin. Forms contém apenas uma classe que deriva de Application , mas geralmente faz
uso de muitas classes que derivam de VisualElement , incluindo páginas, layouts e controles. Qualquer um
desses objetos podem ter seus Resources propriedade definida como um ResourceDictionary . Escolher onde
colocar um determinado ResourceDictionary impactos onde os recursos podem ser usados:
Recursos em um ResourceDictionary que está anexado a um modo de exibição, como Button ou Label só
pode ser aplicado a esse objeto específico, portanto, isso não é muito útil.
Recursos em um ResourceDictionary anexados a um layout, como StackLayout ou Grid podem ser
aplicadas a todos os filhos do que o layout e de layout.
Recursos em um ResourceDictionary definidos na página do nível pode ser aplicado à página e para todos os
seus filhos.
Recursos em um ResourceDictionary definidos no aplicativo de nível pode ser aplicado em todo o aplicativo.
O XAML a seguir mostra os recursos definidos no nível do aplicativo ResourceDictionary no App. XAML
arquivo criado como parte do programa do xamarin. Forms padrão:
<Application ...>
<Application.Resources>
<ResourceDictionary>
<Color x:Key="PageBackgroundColor">Yellow</Color>
<Color x:Key="HeadingTextColor">Black</Color>
<Color x:Key="NormalTextColor">Blue</Color>
<Style x:Key="LabelPageHeadingStyle" TargetType="Label">
<Setter Property="FontAttributes" Value="Bold" />
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="TextColor" Value="{StaticResource HeadingTextColor}" />
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>

Isso ResourceDictionary define três Color recursos e uma Style recursos. Para obter mais informações sobre
o App classe, consulte classe App.
A partir do xamarin. Forms 3.0, explícito ResourceDictionary marcas não são necessárias. O ResourceDictionary
objeto é criado automaticamente e você pode inserir os recursos diretamente entre o Resources marcas de
elemento de propriedade:

<Application ...>
<Application.Resources>
<Color x:Key="PageBackgroundColor">Yellow</Color>
<Color x:Key="HeadingTextColor">Black</Color>
<Color x:Key="NormalTextColor">Blue</Color>
<Style x:Key="LabelPageHeadingStyle" TargetType="Label">
<Setter Property="FontAttributes" Value="Bold" />
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="TextColor" Value="{StaticResource HeadingTextColor}" />
</Style>
</Application.Resources>
</Application>

Cada recurso tem uma chave que é especificada usando o x:Key atributo, que se torna a chave de dicionário no
ResourceDictionary . A chave é usada para recuperar um recurso do ResourceDictionary pelo StaticResource
extensão de marcação, conforme demonstrado no seguinte exemplo de código XAML que mostra os recursos
adicionais definidos dentro de StackLayout :
<StackLayout Margin="0,20,0,0">
<StackLayout.Resources>
<ResourceDictionary>
<Style x:Key="LabelNormalStyle" TargetType="Label">
<Setter Property="TextColor" Value="{StaticResource NormalTextColor}" />
</Style>
<Style x:Key="MediumBoldText" TargetType="Button">
<Setter Property="FontSize" Value="Medium" />
<Setter Property="FontAttributes" Value="Bold" />
</Style>
</ResourceDictionary>
</StackLayout.Resources>
<Label Text="ResourceDictionary Demo" Style="{StaticResource LabelPageHeadingStyle}" />
<Label Text="This app demonstrates consuming resources that have been defined in resource dictionaries."
Margin="10,20,10,0"
Style="{StaticResource LabelNormalStyle}" />
<Button Text="Navigate"
Clicked="OnNavigateButtonClicked"
TextColor="{StaticResource NormalTextColor}"
Margin="0,20,0,0"
HorizontalOptions="Center"
Style="{StaticResource MediumBoldText}" />
</StackLayout>

A primeira Label instância recupera e consome os LabelPageHeadingStyle recursos definidos no nível do


aplicativo ResourceDictionary , com a segunda Label instância recuperando e consumindo o LabelNormalStyle
definido no nível de controle de recurso ResourceDictionary . Da mesma forma, o Button instância recupera e
consome os NormalTextColor recursos definidos no nível do aplicativo ResourceDictionary e o MediumBoldText
definido no nível de controle de recurso ResourceDictionary . Isso resulta na exibição mostrada nas capturas de
tela seguir:
NOTE
Recursos que são específicos a uma única página não devem ser incluídos em um aplicativo nível dicionário de recursos,
como tal, recursos, em seguida, serão analisados na inicialização do aplicativo em vez de quando exigido por uma página.
Para obter mais informações, consulte reduzir o tamanho de dicionário de recursos do aplicativo.

Substituição de recursos
Quando ResourceDictionary compartilham recursos x:Key valores de atributo definidos inferior na hierarquia
de exibição de recursos terá precedência sobre aquelas definidas superior para cima. Por exemplo, definindo a
PageBackgroundColor recursos para Blue no aplicativo de nível será substituído por um nível de página
PageBackgroundColor conjunto de recursos Yellow . Da mesma forma, um nível de página PageBackgroundColor
recurso será substituído por um nível de controle PageBackgroundColor recursos. Essa precedência é
demonstrada pelo exemplo de código XAML a seguir:

<ContentPage ... BackgroundColor="{StaticResource PageBackgroundColor}">


<ContentPage.Resources>
<ResourceDictionary>
<Color x:Key="PageBackgroundColor">Blue</Color>
<Color x:Key="NormalTextColor">Yellow</Color>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout Margin="0,20,0,0">
...
<Label Text="ResourceDictionary Demo" Style="{StaticResource LabelPageHeadingStyle}" />
<Label Text="This app demonstrates consuming resources that have been defined in resource
dictionaries."
Margin="10,20,10,0"
Style="{StaticResource LabelNormalStyle}" />
<Button Text="Navigate"
Clicked="OnNavigateButtonClicked"
TextColor="{StaticResource NormalTextColor}"
Margin="0,20,0,0"
HorizontalOptions="Center"
Style="{StaticResource MediumBoldText}" />
</StackLayout>
</ContentPage>

O original PageBackgroundColor e NormalTextColor instâncias, definidas no nível do aplicativo, são substituídas


pela PageBackgroundColor e NormalTextColor instâncias definidas no nível da página. Portanto, a cor de plano de
fundo da página torna-se azul e o texto na página se torna amarelo, conforme demonstrado nas capturas de tela
seguir:
No entanto, observe que a barra de plano de fundo do NavigationPage ainda está amarela, porque o
BarBackgroundColor propriedade é definida como o valor da PageBackgroundColor recursos definidos no
aplicativo nível de ResourceDictionary .
Aqui está outra maneira de pensar ResourceDictionary precedência: analisador de XAML a quando encontra um
StaticResource , ele procura por uma chave correspondente, percorrendo-se através da árvore visual, usando a
primeira correspondência que ele encontra. Se essa pesquisa termina na página e a chave ainda não foi
encontrada, o analisador XAML pesquisará o ResourceDictionary anexado ao App objeto. Se a chave ainda não
for encontrada, uma exceção é gerada.

Dicionários de recurso autônomo


Uma classe derivada de ResourceDictionary também pode estar em um arquivo autônomo separado. (Mais
precisamente, uma classe derivada de ResourceDictionary geralmente requer um par de arquivos porque os
recursos são definidos em um arquivo XAML, mas um arquivo code-behind com um InitializeComponent
chamada também é necessária.) O arquivo resultante, em seguida, pode ser compartilhado entre aplicativos.
Para criar esse arquivo, adicione uma nova exibição de conteúdo ou página de conteúdo item ao projeto
(mas não um exibição de conteúdo ou página de conteúdo com apenas um arquivo c#). No arquivo XAML e
para arquivos c#, altere o nome da classe base da ContentView ou ContentPage para ResourceDictionary . No
arquivo XAML, o nome da classe base é o elemento de nível superior.
A exemplo XAML a seguir mostra uma ResourceDictionary denominada MyResourceDictionary :
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ResourceDictionaryDemo.MyResourceDictionary">
<DataTemplate x:Key="PersonDataTemplate">
<ViewCell>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*" />
<ColumnDefinition Width="0.2*" />
<ColumnDefinition Width="0.3*" />
</Grid.ColumnDefinitions>
<Label Text="{Binding Name}" TextColor="{StaticResource NormalTextColor}"
FontAttributes="Bold" />
<Label Grid.Column="1" Text="{Binding Age}" TextColor="{StaticResource NormalTextColor}" />
<Label Grid.Column="2" Text="{Binding Location}" TextColor="{StaticResource NormalTextColor}"
HorizontalTextAlignment="End" />
</Grid>
</ViewCell>
</DataTemplate>
</ResourceDictionary>

Isso ResourceDictionary contém um único recurso, que é um objeto do tipo DataTemplate .


Você pode instanciar MyResourceDictionary colocando-o entre um par de Resources elemento de propriedade
de marcas, por exemplo, em um ContentPage :

<ContentPage ...>
<ContentPage.Resources>
<local:MyResourceDictionary />
</ContentPage.Resources>
...
</ContentPage>

Uma instância do MyResourceDictionary é definido como o Resources propriedade do ContentPage objeto.


No entanto, essa abordagem tem algumas limitações: O Resources propriedade do ContentPage faz referência a
apenas esse um ResourceDictionary . Na maioria dos casos, você deseja que a opção de incluir outros
ResourceDictionary instâncias e talvez outros recursos também.

Esta tarefa exige dicionários de recursos mesclados.

Dicionários de recursos mesclados


Dicionários de recursos mesclados combinam uma ou mais ResourceDictionary instâncias em outro
ResourceDictionary . Você pode fazer isso em um arquivo XAML, definindo o MergedDictionaries propriedade
para um ou mais dicionários de recursos será mesclada com o aplicativo, a página ou o nível de controle
ResourceDictionary .

IMPORTANT
ResourceDictionary também define uma MergedWith propriedade. Não use essa propriedade; ele foi preterido a partir
do xamarin. Forms 3.0.

Uma instância do MyResourceDictionary podem ser mesclados em qualquer aplicativo, a página ou o nível de
controle ResourceDictionary . O exemplo de código XAML a seguir mostra que ele está sendo mesclados em um
nível de página ResourceDictionary usando o MergedDictionaries propriedade:
<ContentPage ...>
<ContentPage.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<local:MyResourceDictionary />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</ContentPage.Resources>
...
</ContentPage>

A marcação mostra apenas uma instância do MyResourceDictionary que está sendo adicionado para o
ResourceDictionary , mas você também pode referenciar outro ResourceDictionary instâncias no
MergedDictionary marcas de elemento de propriedade e outros recursos fora essas marcas:

<ContentPage ...>
<ContentPage.Resources>
<ResourceDictionary>

<!-- Add more resources here -->

<ResourceDictionary.MergedDictionaries>

<!-- Add more resource dictionaries here -->

<local:MyResourceDictionary />

<!-- Add more resource dictionaries here -->

</ResourceDictionary.MergedDictionaries>

<!-- Add more resources here -->

</ResourceDictionary>
</ContentPage.Resources>
...
</ContentPage>

Pode haver apenas um MergedDictionaries seção em um ResourceDictionary , mas você pode colocar quantas
ResourceDictionary instâncias aqui como você deseja.

Quando mescladas ResourceDictionary recursos compartilham idênticos x:Key valores de atributo, xamarin.
Forms usa a precedência de recursos a seguir:
1. Os recursos locais para o dicionário de recursos.
2. Os recursos contidos no dicionário de recursos que foi mesclado via preteridas MergedWith propriedade.
3. Os recursos contidos nos dicionários de recursos que foram mesclados por meio de MergedDictionaries
coleção, na ordem inversa, eles são listados no MergedDictionaries propriedade.

NOTE
Dicionários de recursos de pesquisa pode ser uma tarefa de computação intensa, se um aplicativo contém vários
dicionários de recursos grandes. Portanto, para evitar pesquisas desnecessárias, você deve garantir que cada página em um
aplicativo só usa dicionários de recursos que são apropriados para a página.

Mesclando dicionários no xamarin. Forms 3.0


Começando com o xamarin. Forms 3.0, o processo de mesclagem ResourceDictionary instâncias se tornou um
pouco mais fácil e mais flexível. O MergedDictionaries marcas de elemento de propriedade não são mais
necessárias. Em vez disso, você adiciona ao dicionário de recurso que outro ResourceDictionary marca com o
novo Source propriedade definida como o nome do arquivo do arquivo XAML com os recursos:

<ContentPage ...>
<ContentPage.Resources>
<ResourceDictionary>

<!-- Add more resources here -->

<ResourceDictionary Source="MyResourceDictionary.xaml" />

<!-- Add more resources here -->

</ResourceDictionary>
</ContentPage.Resources>
...
</ContentPage>

Porque o xamarin. Forms 3.0 automaticamente cria uma instância de ResourceDictionary , esses dois externos
ResourceDictionary marcas não são mais necessárias:

<ContentPage ...>
<ContentPage.Resources>

<!-- Add more resources here -->

<ResourceDictionary Source="MyResourceDictionary.xaml" />

<!-- Add more resources here -->

</ContentPage.Resources>
...
</ContentPage>

Essa nova sintaxe faz não instanciar o MyResourceDictionary classe. Em vez disso, ele faz referência ao arquivo
XAML. Por esse motivo que o arquivo code-behind (MyResourceDictionary.xaml.cs) não é mais necessário.
Você também pode remover o x:Class atributo na marca raiz do MyResourceDictionary.xaml arquivo.

Resumo
Este artigo explicou como criar e consumir um ResourceDictionary e como mesclar os dicionários de recursos.
Um ResourceDictionary permite que os recursos sejam definidos em um único local e reutilizadas em todo um
aplicativo xamarin. Forms.

Links relacionados
Dicionários de recursos (amostra)
Estilos
Dicionário de recurso
XAML Standard (visualização)
12/04/2019 • 2 minutes to read

Siga estas etapas para fazer experiências com o padrão de XAML no xamarin. Forms:
Visual Studio
Visual Studio para Mac
1. Baixe o visualizar o pacote do NuGet aqui.
2. Adicione a Xamarin.Forms.Alias pacote do NuGet para seus projetos xamarin. Forms .NET Standard e
plataforma.
3. Inicializar o pacote com Alias.Init()
4. Adicionar um xmlns:a referência xmlns:a="clr-namespace:Xamarin.Forms.Alias;assembly=Xamarin.Forms.Alias"
5. Use os tipos no XAML - consulte o referência controles para obter mais informações.
O XAML a seguir demonstra alguns controles XAML padrão que está sendo usados em um xamarin. Forms
ContentPage :

<?xml version="1.0" encoding="utf-8"?>


<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:a="clr-namespace:Xamarin.Forms.Alias;assembly=Xamarin.Forms.Alias"
x:Class="XAMLStandardSample.ItemsPage"
Title="{Binding Title}" x:Name="BrowseItemsPage">
<ContentPage.ToolbarItems>
<ToolbarItem Text="Add" Clicked="AddItem_Clicked" />
</ContentPage.ToolbarItems>
<ContentPage.Content>
<a:StackPanel>
<ListView x:Name="ItemsListView" ItemsSource="{Binding Items}" VerticalOptions="FillAndExpand"
HasUnevenRows="true" RefreshCommand="{Binding LoadItemsCommand}" IsPullToRefreshEnabled="true" IsRefreshing="
{Binding IsBusy, Mode=OneWay}" CachingStrategy="RecycleElement" ItemSelected="OnItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="10">
<a:TextBlock Text="{Binding Text}" LineBreakMode="NoWrap" Style="{DynamicResource
ListItemTextStyle}" FontSize="16" />
<a:TextBlock Text="{Binding Description}" LineBreakMode="NoWrap" Style="{DynamicResource
ListItemDetailTextStyle}" FontSize="13" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</a:StackPanel>
</ContentPage.Content>
</ContentPage>
NOTE
Exigir que o xmlns a: prefixo em controles XAML padrão é uma limitação da visualização atual.

Links relacionados
NuGet de visualização
Referência de controles
Controles do XAML Standard (visualização)
12/04/2019 • 2 minutes to read

Esta página lista os controles XAML padrão disponíveis na visualização, juntamente com seu controle equivalente
do xamarin. Forms.
Também é uma lista de controles que têm novos nomes de propriedade e de enumeração no XAML padrão.

Controles
XAMARIN.FORMS XAML STANDARD

Quadro Borda

Seletor ComboBox

ActivityIndicator ProgressRing

StackLayout StackPanel

Rotular TextBlock

Entrada TextBox

Alternar ToggleSwitch

ContentView UserControl

Propriedades e enumerações
CONTROLES DO XAMARIN. FORMS COM AS PROPRIEDADE DO XAMARIN. FORMS OU
PROPRIEDADES ATUALIZADAS ENUMERAÇÃO EQUIVALENTE XAML PADRÃO

Botão, entrada, rótulo, DatePicker, TextColor Primeiro plano


Editor, SearchBar, TimePicker

VisualElement BackgroundColor Plano de fundo *

Seletor de botão BorderColor, OutlineColor BorderBrush

Botão BorderWidth BorderThickness

ProgressBar Progresso Valor


CONTROLES DO XAMARIN. FORMS COM AS PROPRIEDADE DO XAMARIN. FORMS OU
PROPRIEDADES ATUALIZADAS ENUMERAÇÃO EQUIVALENTE XAML PADRÃO

Botão, entrada, rótulo, Editor, FontAttributesBold, itálico, None FontStyleItalic, Normal


SearchBar, Span, fonte

Botão, entrada, rótulo, Editor, FontAttributes FontWeights * negrito, Normal


SearchBar, Span, fonte

InputView KeyboardDefault, Url, número, telefone, InputScopeNameValue * padrão, Url,


texto, bate-papo, envie um Email número, TelephoneNumber, texto,
bate-papo, EmailNameOrAddress

StackPanel StackOrientation Orientação *

IMPORTANT
Itens marcados com * estão incompletos na visualização atual

Links relacionados
NuGet de visualização
Carregando XAML em tempo de execução no
xamarin. Forms
12/04/2019 • 4 minutes to read

Baixar o exemplo
O Xamarin.Forms.Xaml namespace inclui dois LoadFromXaml métodos de extensão que podem ser usados para
carregar e analisar o XAML em tempo de execução.

Informações preliminares
Quando uma classe de XAML de xamarin. Forms é construída, o LoadFromXaml método é chamado indiretamente.
Isso ocorre porque o arquivo code-behind para um XAML classe chama o InitializeComponent método de seu
construtor:

public partial class MainPage : ContentPage


{
public MainPage()
{
InitializeComponent();
}
}

Quando o Visual Studio compila um projeto que contém um arquivo XAML, ele analisa o arquivo XAML para
gerar um C# arquivo de código (por exemplo, MainPage.xaml.g.cs) que contém a definição do
InitializeComponent método:

private void InitializeComponent()


{
global::Xamarin.Forms.Xaml.Extensions.LoadFromXaml(this, typeof(MainPage));
...
}

O InitializeComponent chamadas de método de LoadFromXaml método para extrair o arquivo XAML (ou seu
binário compilado) da biblioteca do .NET Standard. Após a extração, ele inicializa todos os objetos definidos no
arquivo XAML, conecta-se-los todos juntos em relações pai-filho, anexa os manipuladores de eventos definidos no
código aos eventos definido no arquivo XAML e define a árvore resultante de objetos que o conteúdo das página.

Carregando XAML em tempo de execução


O LoadFromXaml métodos são public e, portanto, podem ser chamados de aplicativos xamarin. Forms para
carregar e analisar o XAML em tempo de execução. Isso permite cenários como um aplicativo baixando o XAML
de um serviço web, criando a exibição necessária do XAML e exibi-lo no aplicativo.

WARNING
Carregar XAML em tempo de execução tem um custo de desempenho significativo e geralmente deve ser evitado.

O exemplo de código a seguir mostra um uso simple:


using Xamarin.Forms.Xaml;
...

string navigationButtonXAML = "<Button Text=\"Navigate\" />";


Button navigationButton = new Button().LoadFromXaml(navigationButtonXAML);
...
_stackLayout.Children.Add(navigationButton);

Neste exemplo, uma Button instância é criada, com seus Text definido pelo valor da propriedade sendo definida
do XAML no string . O Button é adicionado a um StackLayout que foi definido no XAML para a página.

NOTE
O LoadFromXaml métodos de extensão permitem que um argumento de tipo genérico a ser especificado. No entanto,
raramente é necessário especificar o argumento de tipo, pois ela será inferido do tipo da instância de seu operando.

O LoadFromXaml método pode ser usado para Inflar qualquer XAML, com o exemplo a seguir inflacionando uma
ContentPage e, em seguida, navegando até ele:

using Xamarin.Forms.Xaml;
...

// See the sample for the full XAML string


string pageXAML = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<ContentPage
xmlns=\"http://xamarin.com/schemas/2014/forms\"\nxmlns:x=\"http://schemas.microsoft.com/winfx/2009/xaml\"\nx:C
lass=\"LoadRuntimeXAML.CatalogItemsPage\"\nTitle=\"Catalog Items\">\n</ContentPage>";

ContentPage page = new ContentPage().LoadFromXaml(pageXAML);


await Navigation.PushAsync(page);

Acessando elementos
Carregando XAML em tempo de execução com o LoadFromXaml método não permite acesso fortemente tipado
aos elementos XAML que especificou os nomes de objeto de tempo de execução (usando x:Name ). No entanto,
esses elementos XAML podem ser recuperados usando o FindByName método e, em seguida, acessados conforme
necessário:

// See the sample for the full XAML string


string pageXAML = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<ContentPage
xmlns=\"http://xamarin.com/schemas/2014/forms\"\nxmlns:x=\"http://schemas.microsoft.com/winfx/2009/xaml\"\nx:C
lass=\"LoadRuntimeXAML.CatalogItemsPage\"\nTitle=\"Catalog Items\">\n<StackLayout>\n<Label
x:Name=\"monkeyName\"\n />\n</StackLayout>\n</ContentPage>";
ContentPage page = new ContentPage().LoadFromXaml(pageXAML);

Label monkeyLabel = page.FindByName<Label>("monkeyName");


monkeyLabel.Text = "Seated Monkey";
...

Neste exemplo, o XAML para um ContentPage está inflado. Esse XAML inclui um Label denominada monkeyName ,
que é recuperado usando o FindByName método, antes que ele tenha Text propriedade está definida.

Links relacionados
LoadRuntimeXAML (amostra)
Conceitos básicos de aplicativo Xamarin.Forms
12/04/2019 • 5 minutes to read • Edit Online

Acessibilidade
Dicas para incorporar recursos acessíveis (como dar suporte às ferramentas de leitura de tela) com o
Xamarin.Forms.

Classe de aplicativo
A classe Application é o ponto de partida para o Xamarin.Forms – todo aplicativo precisa implementar uma
subclasse App para definir a página inicial. Ela também fornece a coleta Properties para armazenamento de
dados simples. Ela pode ser definida em C# ou em XAML.

Ciclo de vida do aplicativo


Os métodos OnStart , OnSleep e OnResume da classe Application , bem como eventos de navegação modal,
permitem que você manipule eventos de ciclo de vida do aplicativo com código personalizado.

Indexação de aplicativo e vinculação profunda


A indexação de aplicativo permite que os aplicativos que seriam esquecidos após alguns usos permaneçam
relevantes fazendo com que eles apareçam nos resultados da pesquisa. A vinculação profunda permite que os
aplicativos respondam a um resultado de pesquisa que contém dados de aplicativo, normalmente navegando até
uma página referenciada de um link profundo.

Comportamentos
Controles de interface do usuário podem ser estendidos facilmente sem a criação de subclasses pelo uso de
comportamentos para adicionar funcionalidade.

Renderizadores personalizados
Renderizadores personalizados permitem que os desenvolvedores 'substituam' a renderização padrão de controles
do Xamarin.Forms para personalizar sua aparência e comportamento em cada plataforma (usando SDKs nativos,
se desejado).

Associação de dados
A associação de dados associa as propriedades de dois objetos, permitindo que as alterações em uma propriedade
sejam automaticamente refletidas na outra. A associação de dados é parte integrante da arquitetura do aplicativo
MVVM (Model-View -ViewModel).

Serviço de dependência
O DependencyService fornece um localizador simples para que você possa codificar para interfaces em seu código
compartilhado e fornecer implementações específicas a uma plataforma que são resolvidas automaticamente,
tornando mais fácil fazer referência a funcionalidades específicas a uma plataforma no Xamarin.Forms.
Efeitos
Efeitos permitem que os controles nativos em cada plataforma sejam personalizados e são geralmente usados para
pequenas alterações de estilo.

Arquivos
O tratamento de arquivos com o Xamarin.Forms pode ser alcançado usando código em uma biblioteca .NET
Standard ou usando recursos inseridos.

Gestos
A classe GestureRecognizer do Xamarin.Forms dá suporte a gestos de toque, pinçagem e panorâmica em controles
da interface do usuário.

Localização
A estrutura de localização interna do .NET pode ser usada para criar aplicativos multilíngues multiplataforma com
o Xamarin.Forms.

Bancos de dados locais


O Xamarin.Forms dá suporte a aplicativos controlados por banco de dados usando o mecanismo de banco de
dados SQLite, que torna possível carregar e salvar objetos em código compartilhado.

Centro de mensagens
O MessagingCenter do Xamarin.Forms habilita a exibição de modelos e outros componentes com os quais se
comunicar sem que eles precisem saber nada uns sobre os outros, além de um contrato de mensagem simples.

Navegação
o Xamarin.Forms oferece uma série de experiências de navegação de página diferentes, dependendo do tipo do
Page sendo usado.

Shell
O Shell do Xamarin.Forms é um contêiner para aplicativos, que fornece os recursos fundamentais da interface do
usuário que a maioria dos aplicativos exige, permitindo que você se concentre na carga de trabalho principal do
aplicativo.

Modelos
Modelos de controle fornecem a capacidade de definir e redefinir temas de páginas de aplicativo em tempo de
execução com facilidade, enquanto modelos de dados fornecem a capacidade de definir a apresentação de dados
em controles compatíveis.

Gatilhos
Atualize os controles respondendo a alterações de propriedade e eventos no XAML.
Acessibilidade do Xamarin.Forms
12/04/2019 • 2 minutes to read • Edit Online

Criar um aplicativo acessível garante que o aplicativo seja utilizável por pessoas que abordem a interface do
usuário com uma variedade de necessidades e experiências.
Tornar um aplicativo Xamarin.Forms disponível significa pensar sobre o layout e o design de muitos elementos da
interface do usuário. Para obter diretrizes sobre problemas a serem considerados, consulte a lista de verificação de
acessibilidade. Muitas preocupações de acessibilidade, tais como fontes grandes e configurações de cor e contraste
adequadas, já podem ser tratadas por APIs do Xamarin.Forms.
Os guias Acessibilidade do Android e Acessibilidade iOS contêm detalhes das APIs nativas expostas pelo Xamarin,
enquanto o guia de acessibilidade da Plataforma Universal do Windows no MSDN explica a abordagem nativa
nessa plataforma. Essas APIs são usadas para implementar totalmente aplicativos acessíveis em cada plataforma.
O Xamarin.Forms não tem suporte interno para todas as APIs de acessibilidade disponíveis em cada uma das
plataformas subjacentes. No entanto, ele dá suporte a propriedades de automação de configuração em elementos
de interface do usuário para dar suporte a ferramentas de assistência de navegação e de leitor de tela, uma das
partes mais importantes da criação de aplicativos acessíveis. Para obter mais informações, veja Propriedades de
automação.
Aplicativos Xamarin.Forms também podem ter a ordem de tabulação de controles especificada. Para obter mais
informações, veja Navegação pelo teclado.
Outras APIs de acessibilidade (assim como PostNotification no iOS ) podem ser mais adequadas para uma
implementação de DependencyService ou de renderizador personalizado. Elas não são abordadas neste guia.

Testando a acessibilidade
Aplicativos Xamarin.Forms normalmente são direcionados a várias plataformas, o que significa testar os recursos
de acessibilidade de acordo com a plataforma. Siga estes links para saber como testar a acessibilidade em cada
plataforma:
Testes de iOS
Testes de Android
Windows AccScope (MSDN )

Links relacionados
Acessibilidade multiplataforma
Propriedades de automação
Acessibilidade do teclado
Propriedades de automação no Xamarin.Forms
12/04/2019 • 11 minutes to read • Edit Online

Baixar o exemplo
O Xamarin.Forms permite que valores de acessibilidade sejam definidos em elementos da interface do usuário
usando propriedades anexadas da classe AutomationProperties, que, por sua vez, definem valores de
acessibilidade nativos. Este artigo explica como usar a classe AutomationProperties para que um leitor de tela
possa falar sobre os elementos na página.
O Xamarin.Forms permite que propriedades de automação sejam definidas em elementos da interface do usuário
por meio das propriedades anexadas a seguir:
AutomationProperties.IsInAccessibleTree – indica se o elemento está disponível para um aplicativo acessível.
Para obter mais informações, confira AutomationProperties.IsInAccessibleTree.
AutomationProperties.Name – uma breve descrição do elemento que serve como um identificador falado para o
elemento. Para obter mais informações, confira AutomationProperties.Name.
AutomationProperties.HelpText – uma descrição mais detalhada do elemento, que pode ser considerada como
o texto de dica de ferramenta associado ao elemento. Para obter mais informações, confira
AutomationProperties.HelpText.
AutomationProperties.LabeledBy – permite que outro elemento defina informações de acessibilidade sobre o
elemento atual. Para obter mais informações, confira AutomationProperties.LabeledBy.
Essas propriedades anexadas definem valores de acessibilidade nativos, de modo que um leitor de tela pode falar
sobre o elemento. Para obter mais informações sobre as propriedades anexadas, confira Propriedades anexadas.

IMPORTANT
Usar as propriedades anexadas AutomationProperties pode afetar a execução de testes de interface do usuário no
Android. As propriedades AutomationId , AutomationProperties.Name e AutomationProperties.HelpText definirão a
propriedade ContentDescription nativa, com os valores das propriedades AutomationProperties.Name e
AutomationProperties.HelpText tendo precedência sobre o valor AutomationId (se AutomationProperties.Name e
AutomationProperties.HelpText forem definidos, os valores serão concatenados). Isso significa que testes que
procurarem AutomationId falharão se AutomationProperties.Name ou AutomationProperties.HelpText também
estiverem definidos no elemento. Nesse cenário, testes da interface do usuário deverão ser alterados para procurar pelo
valor de AutomationProperties.Name ou AutomationProperties.HelpText , ou por uma concatenação dos dois.

Cada plataforma tem um leitor de tela diferente para narrar os valores de acessibilidade:
O iOS tem o VoiceOver. Para obter mais informações, confira Test Accessibility on Your Device with VoiceOver
(Testando a acessibilidade em seu dispositivo com o VoiceOver) em developer.apple.com.
O Android tem o TalkBack. Para obter mais informações, confira Testing Your App's Accessibility (Testando a
acessibilidade de seu aplicativo) em developer.android.com.
O Windows tem o Narrador. Para obter mais informações, confira Verificar cenários do aplicativo principal
usando o Narrador.
No entanto, o comportamento exato do leitor de tela depende do software e da configuração que o usuário faz
nele. Por exemplo, a maioria dos leitores de tela lê o texto associado a um controle quando ele entra em foco,
permitindo que os usuários se orientem enquanto percorrem os controles na página. Alguns leitores de tela
também leem toda a interface do usuário do aplicativo quando a página é exibida, o que permite que o usuário
receba todo o conteúdo informativo disponível na página antes de tentar navegar por ela.
Leitores de tela também leem diferentes valores de acessibilidade. No aplicativo de exemplo:
O VoiceOver lê o valor de Placeholder de Entry , seguido por instruções de como usar o controle.
O TalkBack lê o valor de Placeholder de Entry , seguido pelo valor de AutomationProperties.HelpText e por
instruções de como usar o controle.
O Narrador lê o valor de AutomationProperties.LabeledBy de Entry , seguido por instruções de como usar o
controle.
Além disso, o Narrador prioriza AutomationProperties.Name , AutomationProperties.LabeledBy e, em seguida,
AutomationProperties.HelpText . No Android, o TalkBack pode combinar os valores de AutomationProperties.Name
e AutomationProperties.HelpText . Portanto, é recomendável que testes de acessibilidade minuciosos sejam
executados em cada plataforma para garantir a experiência ideal.

AutomationProperties.IsInAccessibleTree
A propriedade anexada AutomationProperties.IsInAccessibleTree é um boolean que determina se o elemento é
acessível e, portanto, visível para leitores de tela. Ela deve ser definida como true para usar outras propriedades
anexadas de acessibilidade. Isso pode ser feito no XAML da seguinte maneira:

<Entry AutomationProperties.IsInAccessibleTree="true" />

Como alternativa, ela pode ser definida em C# da seguinte maneira:

var entry = new Entry();


AutomationProperties.SetIsInAccessibleTree(entry, true);

NOTE
Observe que o método SetValuetambém pode ser usado para definir a propriedade anexada
AutomationProperties.IsInAccessibleTree –
entry.SetValue(AutomationProperties.IsInAccessibleTreeProperty, true);

AutomationProperties.Name
O valor da propriedade anexada AutomationProperties.Name deve ser uma cadeia de caracteres de texto curta e
descritiva que usa de um leitor de tela para anunciar um elemento. Essa propriedade deve ser definida para
elementos cujo significado é importante para entender o conteúdo ou para interagir com a interface do usuário.
Isso pode ser feito no XAML da seguinte maneira:

<ActivityIndicator AutomationProperties.IsInAccessibleTree="true"
AutomationProperties.Name="Progress indicator" />

Como alternativa, ela pode ser definida em C# da seguinte maneira:

var activityIndicator = new ActivityIndicator();


AutomationProperties.SetIsInAccessibleTree(activityIndicator, true);
AutomationProperties.SetName(activityIndicator, "Progress indicator");
NOTE
Observe que o método SetValue também pode ser usado para definir a propriedade anexada
AutomationProperties.Name –
activityIndicator.SetValue(AutomationProperties.NameProperty, "Progress indicator");

AutomationProperties.HelpText
A propriedade anexada AutomationProperties.HelpText deve ser definida como o texto que descreve o elemento
da interface do usuário e pode ser considerada como um texto de dica de ferramenta associado ao elemento. Isso
pode ser feito no XAML da seguinte maneira:

<Button Text="Toggle ActivityIndicator"


AutomationProperties.IsInAccessibleTree="true"
AutomationProperties.HelpText="Tap to toggle the activity indicator" />

Como alternativa, ela pode ser definida em C# da seguinte maneira:

var button = new Button { Text = "Toggle ActivityIndicator" };


AutomationProperties.SetIsInAccessibleTree(button, true);
AutomationProperties.SetHelpText(button, "Tap to toggle the activity indicator");

NOTE
Observe que o método SetValue também pode ser usado para definir a propriedade anexada
AutomationProperties.HelpText –
button.SetValue(AutomationProperties.HelpTextProperty, "Tap to toggle the activity indicator");

Em algumas plataformas, para controles de edição como um Entry , a propriedade HelpText às vezes pode ser
omitida e substituída por um texto de espaço reservado. Por exemplo, "Digite seu nome aqui" é um bom
candidato para a propriedade Entry.Placeholder , que coloca o texto no controle antes da entrada feita pelo
usuário.

AutomationProperties.LabeledBy
A propriedade anexada AutomationProperties.LabeledBy permite que outro elemento defina informações de
acessibilidade sobre o elemento atual. Por exemplo, um Label próximo a um Entry pode ser usado para
descrever o que o Entry representa. Isso pode ser feito no XAML da seguinte maneira:

<Label x:Name="label" Text="Enter your name: " />


<Entry AutomationProperties.IsInAccessibleTree="true"
AutomationProperties.LabeledBy="{x:Reference label}" />

Como alternativa, ela pode ser definida em C# da seguinte maneira:

var nameLabel = new Label { Text = "Enter your name: " };


var entry = new Entry();
AutomationProperties.SetIsInAccessibleTree(entry, true);
AutomationProperties.SetLabeledBy(entry, nameLabel);
NOTE
Observe que o método SetValuetambém pode ser usado para definir a propriedade anexada
AutomationProperties.IsInAccessibleTree –
entry.SetValue(AutomationProperties.LabeledByProperty, nameLabel);

Complexidades de acessibilidade
As seções a seguir descrevem as complexidades da configuração dos valores de acessibilidade em certos
controles.
NavigationPage
No Android, para definir o texto que os leitores de tela lerão para a seta voltar na barra de ação em um
NavigationPage , defina as propriedades AutomationProperties.Name e AutomationProperties.HelpText em um
Page . No entanto, observe que isso não terá um efeito em botões voltar de sistema operacional.

MasterDetailPage
No iOS e UWP (Plataforma Universal do Windows), para definir o texto que os leitores de tela lerão para o botão
de alternância em um MasterDetailPage , defina as propriedades AutomationProperties.Name e
AutomationProperties.HelpText em MasterDetailPage ou na propriedade Icon da página Master .

No Android, para definir o texto que os leitores da tela lerão para o botão de alternância em um MasterDetailPage
, adicione recursos de cadeia de caracteres ao projeto Android:

<resources>
<string name="app_name">Xamarin Forms Control Gallery</string>
<string name="btnMDPAutomationID_open">Open Side Menu message</string>
<string name="btnMDPAutomationID_close">Close Side Menu message</string>
</resources>

Em seguida, defina a propriedade AutomationId da propriedade Icon da página Master na cadeia de caracteres
apropriada:

var master = new ContentPage { ... };


master.Icon.AutomationId = "btnMDPAutomationID";

ToolbarItem
No iOS, Android e UWP, os leitores de tela lerão o valor da propriedade Text das instâncias ToolbarItem ,
contanto que os valores AutomationProperties.Name ou AutomationProperties.HelpText não estejam definidos.
No iOS e UWP, o valor da propriedade AutomationProperties.Name substituirá o valor da propriedade Text que é
lido pelo leitor de tela.
No Android, os valores de propriedade AutomationProperties.Name e/ou AutomationProperties.HelpText
substituirão completamente o valor da propriedade Text que está visível e é lida pelo leitor de tela. Observe que
essa é uma limitação de APIs menores que 26.

Links relacionados
Propriedades anexadas
Acessibilidade (amostra)
Navegação por teclado no Xamarin.Forms
12/04/2019 • 6 minutes to read • Edit Online

Baixar o exemplo
Alguns usuários podem ter dificuldade para usar aplicativos que não fornecem acesso apropriado por teclado.
Especificar uma ordem de tabulação para os controles habilita a navegação por teclado e prepara as páginas do
aplicativo para receber as entradas em uma ordem específica.
Por padrão, a ordem de tabulação dos controles é a mesma ordem em que eles são listados no XAML ou são
adicionados de maneira programática a uma coleção filho. Essa é a ordem em que os controles serão navegados
usando um teclado e geralmente a ordem padrão é a melhor ordem. No entanto, a ordem padrão nem sempre é o
mesmo que a ordem esperada, conforme mostrado no exemplo de código XAML a seguir:

<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*" />
<ColumnDefinition Width="0.5*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Text="You"
HorizontalOptions="Center" />
<Label Grid.Column="1"
Text="Manager"
HorizontalOptions="Center" />
<Entry Grid.Row="1"
Placeholder="Enter forename" />
<Entry Grid.Column="1"
Grid.Row="1"
Placeholder="Enter forename" />
<Entry Grid.Row="2"
Placeholder="Enter surname" />
<Entry Grid.Column="1"
Grid.Row="2"
Placeholder="Enter surname" />
</Grid>

A captura de tela a seguir mostra a ordem de tabulação padrão para este exemplo de código:

A ordem de tabulação aqui é baseada nas linhas e é a ordem em que os controles são listados no XAML. Portanto,
pressionar a tecla Tab navega pelas instâncias de Entry do primeiro nome, seguidas pelas instâncias de Entry do
sobrenome. No entanto, uma experiência mais intuitiva seria usar a navegação com tabulação por colunas, de
modo que pressionar a tecla Tab navegaria pelos pares de primeiro nome e sobrenome. Isso pode ser feito
especificando a ordem de tabulação dos controles de entrada.

NOTE
Na Plataforma Universal do Windows, é possível definir atalhos de teclado que fornecem uma maneira intuitiva para os
usuários navegarem e interagirem rapidamente com a interface do usuário visível do aplicativo usando um teclado em vez
do mouse ou de uma tela de toque. Para obter mais informações, confira Configurando chaves de acesso de VisualElement.

Configurando a ordem de tabulação


A propriedade VisualElement.TabIndex é usada para indicar a ordem na qual as instâncias de VisualElement
recebem foco quando o usuário navega pelos controles pressionando a tecla Tab. O valor padrão da propriedade é
0 e ela pode ser definida como qualquer valor de int .
As seguintes regras se aplicam ao usar a ordem de tabulação padrão ou ao definir a propriedade TabIndex :
Instâncias de VisualElement com um TabIndex igual a 0 são adicionadas à ordem de tabulação com base em
sua ordem de declaração em coleções XAML ou filho.
Instâncias de VisualElement com um TabIndex maior que 0 são adicionadas à ordem de tabulação com base
no valor de TabIndex .
Instâncias de VisualElement com um TabIndex menor que 0 são adicionadas à ordem de tabulação e
aparecem antes de qualquer valor igual a zero.
Conflitos em um TabIndex são resolvidos pela ordem de declaração.
Após definir uma ordem de tabulação, pressionar a tecla Tab passará o foco pelos controles na ordem crescente
de TabIndex , voltando para o início quando o controle final é atingido.
O exemplo de XAML a seguir mostra a propriedade TabIndex definida nos controles de entrada para permitir a
navegação com tabulação baseada na coluna:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*" />
<ColumnDefinition Width="0.5*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Text="You"
HorizontalOptions="Center" />
<Label Grid.Column="1"
Text="Manager"
HorizontalOptions="Center" />
<Entry Grid.Row="1"
Placeholder="Enter forename"
TabIndex="1" />
<Entry Grid.Column="1"
Grid.Row="1"
Placeholder="Enter forename"
TabIndex="3" />
<Entry Grid.Row="2"
Placeholder="Enter surname"
TabIndex="2" />
<Entry Grid.Column="1"
Grid.Row="2"
Placeholder="Enter surname"
TabIndex="4" />
</Grid>

A captura de tela a seguir mostra a ordem de tabulação para este exemplo de código:

A ordem de tabulação aqui é baseada em colunas. Portanto, pressionar a tecla Tab navega pelos pares de Entry
de primeiro nome e sobrenome.

Excluindo controles da ordem de tabulação


Além de definir a ordem de tabulação dos controles, pode ser necessário excluir os controles da ordem de
tabulação. Uma maneira de conseguir isso é definir a propriedade IsEnabled dos controles como false , pois
controles desabilitados são excluídos da ordem de tabulação.
No entanto, pode ser necessário excluir controles da ordem de tabulação, mesmo quando eles não estão
desabilitados. Isso pode ser feito usando a propriedade VisualElement.IsTapStop , que indica se um VisualElement
está incluído na navegação por tabulação. Seu valor padrão é true , e quando o valor é false o controle é
ignorado pela infraestrutura da navegação por tabulação, independentemente de um TabIndex estar definido.

Controles com suporte


As propriedades TabIndex e IsTapStop têm suporte nos seguintes controles, que aceitam entradas com teclado
em uma ou mais plataformas:
Button
DatePicker
Editor
Entry
NavigationPage
Picker
ProgressBar
SearchBar
Slider
Stepper
Switch
TabbedPage
TimePicker

NOTE
Esses controles não são focalizáveis pela tabulação em todas as plataformas.

Links relacionados
Acessibilidade (amostra)
Classe App do Xamarin.Forms
12/04/2019 • 8 minutes to read • Edit Online

A classe base Application oferece os seguintes recursos, que são expostos na subclasse App padrão de seus
projetos:
Uma propriedade MainPage , que é onde a página inicial do aplicativo deve ser definida.
Um dicionário de Properties persistente para armazenar valores simples durante alterações de estado do
ciclo de vida.
Uma propriedade Current estática que contém uma referência ao objeto do aplicativo atual.
Ela também expõe Métodos de ciclo de vida como OnStart , OnSleep e OnResume , bem como eventos de
navegação modal.
Dependendo do modelo escolhido, a classe App poderá ser definida de uma das duas maneiras:
C# ou
XAML e C#
Para criar uma classe App usando XAML, a classe App padrão deve ser substituída por uma classe App XAML e
pelo code-behind associado, conforme mostrado no exemplo de código a seguir:

<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Photos.App">

</Application>

O exemplo de código a seguir mostra o code-behind associado:

public partial class App : Application


{
public App ()
{
InitializeComponent ();
MainPage = new HomePage ();
}
...
}

Além de configurar a propriedade MainPage , o code-behind também deve chamar o método


InitializeComponent para carregar e analisar o XAML associado.

Propriedade MainPage
A propriedade MainPage na classe Application define a página raiz do aplicativo.
Por exemplo, você pode criar a lógica em sua classe App para exibir uma página diferente se o usuário estiver
conectado ou não.
A propriedade MainPage deve ser definida no construtor App ,
public class App : Xamarin.Forms.Application
{
public App ()
{
MainPage = new ContentPage { Title = "App Lifecycle Sample" }; // your page here
}
}

Dicionário de propriedades
A subclasse Application tem um dicionário Properties estático que pode ser usado para armazenar dados, em
particular para uso nos métodos OnStart , OnSleep e OnResume . Ele pode ser acessado de qualquer lugar de seu
código do Xamarin.Forms usando Application.Current.Properties .
O dicionário Properties usa uma chave string e armazena um valor de object .
Por exemplo, você poderia definir uma propriedade "id" persistente em qualquer lugar de seu código (quando
um item é selecionado, no método OnDisappearing de uma página ou no método OnSleep ), da seguinte forma:

Application.Current.Properties ["id"] = someClass.ID;

Nos métodos OnStart ou OnResume , você pode usar esse valor para recriar a experiência do usuário de alguma
forma. O dicionário Properties armazena object s, de modo que você precisa converter seu valor antes de usá-
lo.

if (Application.Current.Properties.ContainsKey("id"))
{
var id = Application.Current.Properties ["id"] as int;
// do something with id
}

Sempre verifique a presença da chave antes de acessá-la para evitar erros inesperados.

NOTE
O dicionário Properties pode serializar apenas tipos primitivos para armazenamento. Tentar armazenar outros tipos
(como List<string> ) pode falhar de modo silencioso.

Persistência
O dicionário Properties é salvo automaticamente no dispositivo. Dados adicionados ao dicionário estarão
disponíveis quando o aplicativo voltar do segundo plano ou até mesmo após ser reiniciado.
O Xamarin.Forms 1.4 introduziu um método adicional na classe Application – SavePropertiesAsync() – que
pode ser chamado para persistir proativamente o dicionário Properties . A finalidade disso é permitir que você
salve propriedades após atualizações importantes, em vez de correr o risco de que elas não sejam serializadas
devido a uma falha ou a uma interrupção do sistema operacional.
Você pode encontrar referências ao uso do dicionário Properties no livro Creating Mobile Apps with
Xamarin.Forms (Criando aplicativos móveis com o Xamarin.Forms), nos capítulos 6, 15 e 20 e nos exemplos
associados.

A classe do aplicativo
Uma implementação completa da classe Application é mostrada abaixo para referência:

public class App : Xamarin.Forms.Application


{
public App ()
{
MainPage = new ContentPage { Title = "App Lifecycle Sample" }; // your page here
}

protected override void OnStart()


{
// Handle when your app starts
Debug.WriteLine ("OnStart");
}

protected override void OnSleep()


{
// Handle when your app sleeps
Debug.WriteLine ("OnSleep");
}

protected override void OnResume()


{
// Handle when your app resumes
Debug.WriteLine ("OnResume");
}
}

Em seguida, essa classe é instanciada em cada projeto específico da plataforma e passada para o método
LoadApplication , em que o MainPage é carregado e exibido para o usuário. O código para cada plataforma é
mostrado nas seções a seguir. Os modelos de solução do Xamarin.Forms mais recentes já contêm todo esse
código pré-configurado para seu aplicativo.
Projeto do iOS
A classe AppDelegate do iOS herda de FormsApplicationDelegate . Ele deve:
Chamar LoadApplication com uma instância da classe App .
Sempre retorna base.FinishedLaunching (app, options); .

[Register ("AppDelegate")]
public partial class AppDelegate :
global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate // superclass new in 1.3
{
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init ();

LoadApplication (new App ()); // method is new in 1.3

return base.FinishedLaunching (app, options);


}
}

Projeto do Android
O MainActivity do Android herda de FormsAppCompatActivity . Na substituição OnCreate , o método
LoadApplication é chamado com uma instância da classe App .
[Activity (Label = "App Lifecycle Sample", Icon = "@drawable/icon", Theme = "@style/MainTheme", MainLauncher
= true,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : FormsAppCompatActivity
{
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);

global::Xamarin.Forms.Forms.Init (this, bundle);

LoadApplication (new App ()); // method is new in 1.3


}
}

UWP (Projeto Universal do Windows) para Windows 10


A página principal no projeto da UWP deve herdar de WindowsPage :

<forms:WindowsPage
...
xmlns:forms="using:Xamarin.Forms.Platform.UWP"
...>
</forms:WindowsPage>

A construção com code-behind de C# deve chamar LoadApplication para criar uma instância de seu App do
Xamarin.Forms. Observe que é uma boa prática usar explicitamente o namespace do aplicativo para qualificar o
App , pois aplicativos da UWP também têm sua própria classe App , não relacionada ao Xamarin.Forms.

public sealed partial class MainPage


{
public MainPage()
{
InitializeComponent();

LoadApplication(new YOUR_NAMESPACE.App());
}
}

Observe que Forms.Init() precisa ser chamado por App.xaml.cs no projeto UWP.
Para obter mais informações, confira Configurar projetos do Windows, que inclui as etapas para adicionar um
projeto UWP a uma solução do Xamarin.Forms existente que não seja direcionada à UWP.
Ciclo de vida do aplicativo no Xamarin.Forms
12/04/2019 • 4 minutes to read • Edit Online

A classe base Application oferece os seguintes recursos:


Métodos de ciclo de vida OnStart , OnSleep e OnResume .
Eventos de navegação de página PageAppearing , PageDisappearing .
Eventos de navegação modal ModalPushing , ModalPushed , ModalPopping e ModalPopped .

Métodos de ciclo de vida


A classe Application contém três métodos virtuais que podem ser substituídos para manipular os métodos de
ciclo de vida:
OnStart – ocorre quando o aplicativo é iniciado.
OnSleep – chamado sempre que o aplicativo vai para segundo plano.
OnResume – chamado quando o aplicativo é retomado, após ser enviado para o segundo plano.
Observe que não há nenhum método de encerramento do aplicativo. Em circunstâncias normais (ou seja, não
uma falha), o encerramento do aplicativo acontecerá do estado OnSleep, sem notificações adicionais em seu
código.
Para observar quando esses métodos são chamados, implemente uma chamada WriteLine em cada um
(conforme mostrado abaixo) e teste em cada plataforma.

protected override void OnStart()


{
Debug.WriteLine ("OnStart");
}
protected override void OnSleep()
{
Debug.WriteLine ("OnSleep");
}
protected override void OnResume()
{
Debug.WriteLine ("OnResume");
}

Ao atualizar aplicativos mais antigos do Xamarin.Forms (por exemplo, criado com o Xamarin.Forms 1.3 ou mais
antigo), verifique se a atividade principal do Android inclui
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation no atributo [Activity()] . Se ele
não estiver presente, você observará que o método OnStart é chamado em rotação e quando o aplicativo é
iniciado pela primeira vez. Esse atributo é incluído automaticamente nos modelos de aplicativo atuais do
Xamarin.Forms.

Eventos de navegação de página


Há dois eventos na classe Application que fornecem notificação quando páginas aparecem e desaparecem:
PageAppearing – gerado quando uma página está prestes a aparecer na tela.
PageDisappearing – gerado quando uma página está prestes a desaparecer da tela.
Esses eventos podem ser usados em cenários em que você deseja controlar páginas à medida que elas aparecem
na tela.

NOTE
Os eventos PageAppearing e PageDisappearing são gerados da classe base Page imediatamente após os eventos
Page.Appearing e Page.Disappearing , respectivamente.

Eventos de navegação modal


Há quatro eventos na classe Application , cada um com seus próprios argumentos de evento, que permitem que
você responda quando páginas modais são mostradas e ignoradas:
ModalPushing - ModalPushingEventArgs
ModalPushed - ModalPushedEventArgs
ModalPopping – a classe ModalPoppingEventArgs contém uma propriedade Cancel . Quando Cancel é
definido como true , a remoção modal é cancelada.
ModalPopped - ModalPoppedEventArgs

NOTE
Para implementar os métodos de ciclo de vida do aplicativo e eventos de navegação modal, todos os métodos pré
Application para criar um aplicativo do Xamarin.Forms (ou seja, aplicativos escritos na versão 1.2 ou mais antiga que
usam um método GetMainPage estático) foram atualizados para criar um Application padrão que é definido como pai
do MainPage .
Aplicativos do Xamarin.Forms que usam esse comportamento herdado devem ser atualizados para uma subclasse de
Application , conforme descrito na página Classe do aplicativo.
Indexação de aplicativo e vinculação profunda
12/04/2019 • 17 minutes to read • Edit Online

Baixar o exemplo
A indexação de aplicativo permite que os aplicativos que seriam esquecidos após alguns usos permaneçam
relevantes fazendo com que eles apareçam nos resultados da pesquisa. A vinculação profunda permite que os
aplicativos respondam a um resultado de pesquisa que contém dados de aplicativo, normalmente navegando até
uma página referenciada de um link profundo. Este artigo explica como usar a indexação de aplicativo e a
vinculação profunda para fazer com que o Xamarin.Forms tenha conteúdo pesquisável em dispositivos iOS e
Android.

Vinculação profunda com o Xamarin.Forms e o Azure, por Xamarin University


A indexação de aplicativo e a vinculação profunda do Xamarin.Forms fornecem uma API para publicar metadados
para indexação de aplicativo à medida que os usuários navegam pelos aplicativos. O conteúdo indexado pode ser
pesquisado no Spotlight Search, na Pesquisa Google ou em uma pesquisa na Web. Tocar em um resultado de
pesquisa que contém um link profundo acionará um evento que poderá ser tratado por um aplicativo. Isso
normalmente é usado para navegar até a página referenciada do link profundo.
Este aplicativo de exemplo demonstra um aplicativo de Lista de tarefas em que os dados são armazenados em um
banco de dados local do SQLite, como mostrado nas seguintes capturas de tela:

Cada instância TodoItem criada pelo usuário é indexada. Então, a pesquisa específica da plataforma pode ser usada
para localizar dados indexados do aplicativo. Quando o usuário toca em um item de resultado de pesquisa para o
aplicativo, o aplicativo é iniciado, o TodoItemPage é navegada e o TodoItem referenciado do link profundo é
exibido.
Para obter mais informações sobre como usar um banco de dados do SQLite, consulte Bancos de Dados Locais do
Xamarin.Forms.

NOTE
A funcionalidade de indexação de aplicativo e vinculação profunda do Xamarin.Forms somente está disponível nas
plataformas Android e iOS e requer um mínimo de iOS 9 e API 23, respectivamente.

Configuração
As seções a seguir fornecem instruções de configuração adicionais para usar esse recurso nas plataformas Android
e iOS.
iOS
Na plataforma iOS, certifique-se de que seu projeto da plataforma iOS defina o arquivo Entitlements.plist como
o arquivo de direitos personalizados para assinar o pacote.
Para usar Links Universais do iOS:
1. Adicione um direito de Domínios Associados ao seu aplicativo, com a chave applinks , incluindo todos os
domínios que seu aplicativo dará suporte.
2. Adicione um arquivo de Associação de Site do Aplicativo da Apple ao seu site.
3. Adicione a chave applinks ao arquivo de Associação de Site do Aplicativo da Apple.
Para obter mais informações, consulte Permitir que aplicativos e sites se vinculem ao seu conteúdo em
developer.apple.com.
Android
Na plataforma Android, há uma série de pré-requisitos que devem ser atendidos para usar a funcionalidade de
indexação de aplicativo e vinculação profunda:
1. Uma versão do seu aplicativo deve estar em tempo real no Google Play.
2. Um site complementar deve ser registrado com o aplicativo no Console do Desenvolvedor do Google. Depois
que o aplicativo é associado a um site, as URLs podem ser indexadas e funcionam para o site e o aplicativo, que
pode ser atendido nos resultados da pesquisa. Para obter mais informações, consulte Indexação de apps na
Pesquisa Google no site do Google.
3. Seu aplicativo deve dar suporte a intenções de URL HTTP na classe MainActivity , que informa à indexação de
aplicativo quais tipos de esquemas de dados de URL o aplicativo pode responder. Para obter mais informações,
consulte Configurar o Filtro de Intenção.
Depois que esses pré-requisitos forem atendidos, a seguinte configuração adicional será necessária para usar a
indexação de aplicativo e a vinculação profunda do Xamarin.Forms na plataforma Android:
1. Instale o pacote do NuGet do Xamarin.Forms.AppLinks no projeto de aplicativo do Android.
2. No arquivo MainActivity.cs, adicione uma declaração para usar o namespace
Xamarin.Forms.Platform.Android.AppLinks .
3. No arquivo MainActivity.cs, adicione uma declaração para usar o namespace Firebase .
4. Em um navegador da Web, crie um projeto por meio do Console do Firebase.
5. No Console do Firebase, adicione o Firebase ao seu aplicativo Android e insira os dados necessários.
6. Baixe o arquivo google-services.json resultante.
7. Adicione o arquivo google-services.json ao diretório raiz do projeto do Android e defina sua Ação de Build
como GoogleServicesJson.
8. Na substituição de MainActivity.OnCreate , adicione a seguinte linha de código abaixo de
Forms.Init(this, bundle) :

FirebaseApp.InitializeApp(this);
AndroidAppLinks.Init(this);

Quando google-services.json é adicionado ao projeto (e a ação de build GoogleServicesJson* é definida), o


processo de build extrai a chave de API e a ID do cliente e, em seguida, adiciona essas credenciais ao arquivo de
manifesto gerado.
Para obter mais informações, consulte Conteúdo de link profundo com navegação de URL do Xamarin.Forms no
blog do Xamarin.

Indexação de uma página


O processo de indexação e exposição de uma página na pesquisa do Google e do Spotlight é da seguinte maneira:
1. Crie um AppLinkEntry que contenha os metadados necessários para indexar a página juntamente com um link
profundo para retornar à página quando o usuário selecionar o conteúdo indexado nos resultados da pesquisa.
2. Registre a instância AppLinkEntry para indexá-la para a pesquisa.

O exemplo de código a seguir demonstra como criar uma instância AppLinkEntry :

AppLinkEntry GetAppLink(TodoItem item)


{
var pageType = GetType().ToString();
var pageLink = new AppLinkEntry
{
Title = item.Name,
Description = item.Notes,
AppLinkUri = new Uri($"http://{App.AppName}/{pageType}?id={item.ID}", UriKind.RelativeOrAbsolute),
IsLinkActive = true,
Thumbnail = ImageSource.FromFile("monkey.png")
};

pageLink.KeyValues.Add("contentType", "TodoItemPage");
pageLink.KeyValues.Add("appName", App.AppName);
pageLink.KeyValues.Add("companyName", "Xamarin");

return pageLink;
}

A instância AppLinkEntry contém uma série de propriedades cujos valores são necessários para indexar a página e
criar um link profundo. As propriedades Title , Description e Thumbnail são usadas para identificar o conteúdo
indexado quando ele for exibido nos resultados da pesquisa. A propriedade IsLinkActive é definida como true
para indicar que o conteúdo indexado está sendo exibido atualmente. A propriedade AppLinkUri é uma Uri que
contém as informações necessárias para retornar à página atual e exibir o TodoItem atual. O exemplo a seguir
mostra um Uri de exemplo para o aplicativo de exemplo:

http://deeplinking/DeepLinking.TodoItemPage?id=2

Esse contém todas as informações necessárias para iniciar o aplicativo


Uri deeplinking . Navegue até
DeepLinking.TodoItemPage e exiba o TodoItem que tem um ID de 2.
Registro do conteúdo para indexação
Assim que a instância AppLinkEntry tiver sido criada, ela deverá ser registrada para a indexação aparecer nos
resultados da pesquisa. Isso é feito com o método RegisterLink , conforme demonstrado no exemplo de código a
seguir:

Application.Current.AppLinks.RegisterLink (appLink);

Isso adiciona a instância AppLinkEntry à coleção AppLinks do aplicativo.

NOTE
O método RegisterLink também pode ser usado para atualizar o conteúdo que foi indexado para uma página.

Assim que uma instância AppLinkEntry tiver sido registrada para indexação, ela poderá aparecer nos resultados da
pesquisa. A captura de tela a seguir mostra o conteúdo indexado que aparece nos resultados da pesquisa na
plataforma iOS:

Cancelar o registro do conteúdo indexado


O método DeregisterLink é usado para remover o conteúdo indexado dos resultados da pesquisa, conforme
demonstrado no exemplo de código a seguir:

Application.Current.AppLinks.DeregisterLink (appLink);

Isso remove a instância AppLinkEntry da coleção AppLinks do aplicativo.


NOTE
No Android, não é possível remover o conteúdo indexado dos resultados da pesquisa.

Responder a um Link Profundo


Quando o conteúdo indexado for exibido nos resultados da pesquisa e for selecionado por um usuário, a classe
App para o aplicativo receberá uma solicitação para lidar com o Uri contido no conteúdo indexado. Essa
solicitação pode ser processada na substituição de OnAppLinkRequestReceived , conforme demonstrado no exemplo
de código a seguir:

public class App : Application


{
...
protected override async void OnAppLinkRequestReceived(Uri uri)
{
string appDomain = "http://" + App.AppName.ToLowerInvariant() + "/";
if (!uri.ToString().ToLowerInvariant().StartsWith(appDomain, StringComparison.Ordinal))
return;

string pageUrl = uri.ToString().Replace(appDomain, string.Empty).Trim();


var parts = pageUrl.Split('?');
string page = parts[0];
string pageParameter = parts[1].Replace("id=", string.Empty);

var formsPage = Activator.CreateInstance(Type.GetType(page));


var todoItemPage = formsPage as TodoItemPage;
if (todoItemPage != null)
{
var todoItem = await App.Database.GetItemAsync(int.Parse(pageParameter));
todoItemPage.BindingContext = todoItem;
await MainPage.Navigation.PushAsync(formsPage as Page);
}
base.OnAppLinkRequestReceived(uri);
}
}

O método OnAppLinkRequestReceived verifica se o Uri recebido destina-se ao aplicativo antes da análise de Uri
em uma página que será navegada e do parâmetro que será passado para a página. Uma instância da página que
será navegada é criada e o TodoItem representado pelo parâmetro da página é recuperado. O BindingContext da
página que será navegada é definido como TodoItem . Isso garante que, quando o TodoItemPage for exibido pelo
método PushAsync , ele estará mostrando o TodoItem cujo ID está contido no link profundo.

Disponibilizar o conteúdo disponível para indexação de pesquisa


Sempre que a página representada por um link profundo for exibida, a propriedade AppLinkEntry.IsLinkActive
poderá ser definida como true . No iOS e no Android, isso torna a instância AppLinkEntry disponível para a
indexação de pesquisa. No iOS, isso também torna a instância AppLinkEntry disponível para entrega. Para obter
mais informações sobre a entrega, consulte Introdução à entrega.
O exemplo de código a seguir demonstra a configuração da propriedade AppLinkEntry.IsLinkActive como true
na substituição de Page.OnAppearing :
protected override void OnAppearing()
{
appLink = GetAppLink(BindingContext as TodoItem);
if (appLink != null)
{
appLink.IsLinkActive = true;
}
}

Da mesma forma, quando a página representada por um link profundo for retirada da navegação, a propriedade
AppLinkEntry.IsLinkActive poderá ser definida como false . No iOS e no Android, isso interrompe a instância
AppLinkEntry que está sendo anunciada para indexação de pesquisa. No iOS, isso também interrompe o anúncio
da instância AppLinkEntry para entrega. Isso pode ser feito na substituição de Page.OnDisappearing , conforme
demonstrado no exemplo de código a seguir:

protected override void OnDisappearing()


{
if (appLink != null)
{
appLink.IsLinkActive = false;
}
}

Fornecer dados para entrega


No iOS, os dados específicos do aplicativo podem ser armazenados durante a indexação de página. Isso é feito
pela adição de dados para à coleção KeyValues , que é um Dictionary<string, string> para armazenar pares
chave-valor que são usados na entrega. A entrega é uma maneira para o usuário iniciar uma atividade em um dos
seus dispositivos e continuar essa atividade em outro de seus dispositivos (conforme identificado pela conta do
iCloud do usuário). O código a seguir mostra um exemplo de armazenamento de pares chave-valor específicos do
aplicativo:

var pageLink = new AppLinkEntry


{
...
};
pageLink.KeyValues.Add("appName", App.AppName);
pageLink.KeyValues.Add("companyName", "Xamarin");

Os valores armazenados na coleção KeyValues serão armazenados nos metadados para a página indexada e serão
restaurados quando o usuário tocar em um resultado de pesquisa que contém um link profundo (ou quando a
entrega for usada para exibir o conteúdo em outro dispositivo conectado).
Além disso, os valores para as seguintes chaves podem ser especificados:
contentType – um string que especifica o identificador de tipo uniforme do conteúdo indexado. A convenção
recomendada para uso para esse valor é o nome do tipo da página com o conteúdo indexado.
associatedWebPage – um string que representa a página da Web a ser visitada se o conteúdo indexado
também puder ser exibido na Web ou se o aplicativo der suporte a links profundos do Safari.
shouldAddToPublicIndex – um string de true ou false que controla a necessidade de adição de conteúdo
indexado ao índice de nuvem pública da Apple, que, em seguida, pode ser apresentado aos usuários que ainda
não instalaram o aplicativo em seu dispositivo iOS. No entanto, o conteúdo ter sido definido para indexação
pública não significa que ele será automaticamente adicionado ao índice de nuvem pública da Apple. Para obter
mais informações, consulte Indexação de pesquisa pública. Observe que essa chave deve ser definida como
false ao adicionar dados pessoais à coleção KeyValues .

NOTE
A coleção KeyValues não é usada na plataforma Android.

Para obter mais informações sobre a entrega, consulte Introdução à entrega.

Resumo
Este artigo explicou como usar a indexação de aplicativo e a vinculação profunda para tornar o conteúdo do
aplicativo Xamarin.Forms pesquisável em dispositivos iOS e Android. A indexação de aplicativo permite que os
aplicativos que seriam esquecidos após alguns usos permaneçam relevantes fazendo com que eles apareçam nos
resultados da pesquisa.

Links relacionados
Vinculação profunda (amostra)
APIs de pesquisa do iOS
Vinculação de aplicativo no Android 6.0
AppLinkEntry
IAppLinkEntry
IAppLinks
Comportamentos do Xamarin.Forms
12/04/2019 • 2 minutes to read • Edit Online

Comportamentos permitem adicionar funcionalidade a controles de interface do usuário sem precisar dividi-los
em subclasses. Comportamentos são escritos em código e adicionados aos controles em XAML ou em código.

Introdução aos comportamentos


Os comportamentos permitem que você implemente código que normalmente precisaria escrever como code-
behind, porque ele interage diretamente com a API do controle de forma que ele pode ser anexado de forma
concisa ao controle. Este artigo fornece uma introdução a comportamentos.

Comportamentos anexados
Comportamentos anexados são classes static com uma ou mais propriedades anexadas. Este artigo demonstra
como criar e consumir comportamentos anexados.

Comportamentos do Xamarin.Forms
Comportamentos do Xamarin.Forms são criados derivando da classe Behavior ou Behavior<T> . Este artigo
demonstra como criar e consumir comportamentos do Xamarin.Forms.

Comportamentos reutilizáveis
Comportamentos são reutilizáveis em mais de um aplicativo. Estes artigos explicam como criar comportamentos
úteis para executar a funcionalidade comumente usada.
Introdução aos comportamentos
12/04/2019 • 2 minutes to read • Edit Online

Comportamentos permitem adicionar funcionalidade a controles de interface do usuário sem precisar dividi-los
em subclasses. Em vez disso, a funcionalidade é implementada em uma classe de comportamento e anexada ao
controle como se fizesse parte do próprio controle. Este artigo fornece uma introdução a comportamentos.
Os comportamentos permitem que você implemente código que normalmente precisaria escrever como code-
behind, porque interagem diretamente com a API do controle, de forma que podem ser anexados de forma
concisa ao controle e empacotados para reutilização em mais de um aplicativo. Eles podem ser usados para
fornecer uma ampla gama de funcionalidade para controles, como:
Adicionar um validador de email a um Entry .
Criar um controle de classificação usando um reconhecedor de gesto de toque.
Controlar uma animação.
Adicionar um efeito a um controle.
Os comportamentos também permitem cenários mais avançados. No contexto dos comandos, os
comportamentos são uma abordagem útil para conectar um controle a um comando. Além disso, eles podem ser
usados para associar comandos a controles que não foram projetados para interagir com comandos. Por exemplo,
podem ser usados para invocar um comando em resposta ao acionamento de um evento.
O Xamarin.Forms dá suporte a dois estilos diferentes de comportamentos:
Comportamentos do Xamarin.Forms – as classes que derivam da classe Behavior ou Behavior<T> , em que
T é o tipo do controle ao qual o comportamento deve ser aplicado. Para obter mais informações sobre
comportamentos no Xamarin.Forms, confira Comportamentos do Xamarin.Forms e Comportamentos
reutilizáveis.
Comportamentos anexados – classes static com uma ou mais propriedades anexadas. Para obter mais
informações sobre comportamentos anexados, confira Comportamentos anexados.
Este guia se concentra em comportamentos do Xamarin.Forms porque eles são a abordagem preferida para
construção de comportamentos.

Links relacionados
Comportamento
Comportamento<T>
Comportamentos anexados
12/04/2019 • 7 minutes to read • Edit Online

Baixar o exemplo
Comportamentos anexados são classes estáticas com uma ou mais propriedades anexadas. Este artigo demonstra
como criar e consumir comportamentos anexados.

Visão geral
Uma propriedade anexada é um tipo especial de propriedade associável. Elas são definidas em uma classe, mas
são anexadas a outros objetos e reconhecíveis no XAML como atributos que contêm uma classe e um nome de
propriedade separados por um ponto.
Uma propriedade anexada pode definir um delegado propertyChanged que será executado quando o valor da
propriedade for alterado, por exemplo, quando a propriedade for definida em um controle. Quando o delegado
propertyChanged é executado, é passada a ele uma referência ao controle a que ele está sendo anexado, bem como
parâmetros que contêm os valores antigo e novo da propriedade. Esse delegado pode ser usado para adicionar
uma nova funcionalidade ao controle a que a propriedade está anexada manipulando a referência que é passada,
da seguinte maneira:
1. O delegado propertyChanged converte a referência do controle, que é recebida como um BindableObject , para
o tipo de comportamento que o controle deve melhorar.
2. O delegado propertyChanged modifica as propriedades do controle, chama os métodos do controle ou registra
manipuladores de eventos para eventos expostos pelo controle, a fim de implementar a funcionalidade do
comportamento de núcleo.
Um problema com comportamentos anexados é que eles são definidos em uma classe static , com propriedades
static e métodos. Isso dificulta a criação de comportamentos anexados com estado. Além disso, os
comportamentos do Xamarin.Forms substituíram os comportamentos anexados como a abordagem preferencial
para a construção de comportamentos. Para obter mais informações sobre comportamentos no Xamarin.Forms,
confira Comportamentos do Xamarin.Forms e Comportamentos reutilizáveis.

Criando um comportamento anexado


O aplicativo de exemplo demonstra um NumericValidationBehavior , que destaca o valor inserido pelo usuário em
um controle Entry em vermelho, caso ele não seja um double . Esse comportamento é mostrado no exemplo de
código a seguir:
public static class NumericValidationBehavior
{
public static readonly BindableProperty AttachBehaviorProperty =
BindableProperty.CreateAttached (
"AttachBehavior",
typeof(bool),
typeof(NumericValidationBehavior),
false,
propertyChanged:OnAttachBehaviorChanged);

public static bool GetAttachBehavior (BindableObject view)


{
return (bool)view.GetValue (AttachBehaviorProperty);
}

public static void SetAttachBehavior (BindableObject view, bool value)


{
view.SetValue (AttachBehaviorProperty, value);
}

static void OnAttachBehaviorChanged (BindableObject view, object oldValue, object newValue)


{
var entry = view as Entry;
if (entry == null) {
return;
}

bool attachBehavior = (bool)newValue;


if (attachBehavior) {
entry.TextChanged += OnEntryTextChanged;
} else {
entry.TextChanged -= OnEntryTextChanged;
}
}

static void OnEntryTextChanged (object sender, TextChangedEventArgs args)


{
double result;
bool isValid = double.TryParse (args.NewTextValue, out result);
((Entry)sender).TextColor = isValid ? Color.Default : Color.Red;
}
}

A classe NumericValidationBehavior contém uma propriedade anexada chamada AttachBehavior , com um getter e
setter static , que controla a adição ou remoção do comportamento do controle a que ele será anexado. Essa
propriedade anexada registra o método OnAttachBehaviorChanged que será executado quando o valor da
propriedade for alterado. Esse método registra ou cancela o registra de um manipulador de eventos para o evento
TextChanged , com base no valor da propriedade anexada AttachBehavior . A funcionalidade núcleo do
comportamento é fornecida pelo método OnEntryTextChanged , que analisa o valor inserido no Entry pelo usuário
e define a propriedade TextColor como vermelha caso o valor não seja um double .

Consumindo um comportamento anexado


A classe NumericValidationBehavior pode ser consumida adicionando a propriedade anexada AttachBehavior a
um controle Entry , conforme demonstrado no exemplo de código XAML a seguir:

<ContentPage ... xmlns:local="clr-namespace:WorkingWithBehaviors;assembly=WorkingWithBehaviors" ...>


...
<Entry Placeholder="Enter a System.Double" local:NumericValidationBehavior.AttachBehavior="true" />
...
</ContentPage>
O Entry equivalente em C# é mostrado no exemplo de código a seguir:

var entry = new Entry { Placeholder = "Enter a System.Double" };


NumericValidationBehavior.SetAttachBehavior (entry, true);

Em tempo de execução, o comportamento responderá à interação com o controle, de acordo com a


implementação do comportamento. As capturas de tela a seguir demonstram o comportamento anexado
respondendo a uma entrada inválida:

NOTE
Comportamentos anexados são escritos para um tipo de controle específico (ou uma superclasse que pode ser aplicada a
muitos controles) e só devem ser adicionados a um controle compatível. Tentar anexar um comportamento a um controle
incompatível resultará em um comportamento desconhecido e depende da implementação do comportamento.

Removendo um comportamento anexado de um controle


A classe NumericValidationBehavior pode ser removida de um controle definindo a propriedade anexada
AttachBehavior como false , conforme demonstrado no exemplo de código XAML a seguir:

<Entry Placeholder="Enter a System.Double" local:NumericValidationBehavior.AttachBehavior="false" />

O Entry equivalente em C# é mostrado no exemplo de código a seguir:

var entry = new Entry { Placeholder = "Enter a System.Double" };


NumericValidationBehavior.SetAttachBehavior (entry, false);

No tempo de execução, o método OnAttachBehaviorChanged será executado quando o valor da propriedade


anexada AttachBehavior for definida como false . O método OnAttachBehaviorChanged , então, cancelará o
registro do manipulador de eventos para o evento TextChanged , garantindo que o comportamento não seja
executado conforme o usuário interagir com o controle.

Resumo
Este artigo demonstrou como criar e consumir comportamentos anexados. Comportamentos anexados são
classes static com uma ou mais propriedades anexadas.
Links relacionados
Comportamentos anexados (amostra)
Criar comportamentos do Xamarin.Forms
12/04/2019 • 10 minutes to read • Edit Online

Baixar o exemplo
Os comportamentos do Xamarin.Forms são criados pela derivação da classe Behavior ou Behavior<T>. Este
artigo demonstra como criar e consumir comportamentos do Xamarin.Forms.

Visão geral
O processo para criar um comportamento do Xamarin.Forms é o seguinte:
1. Criar uma classe que herda da classe Behavior ou Behavior<T> , em que T é o tipo do controle ao qual o
comportamento deve ser aplicado.
2. Substituir o método OnAttachedTo para executar qualquer configuração necessária.
3. Substituir o método OnDetachingFrom para executar qualquer limpeza necessária.
4. Implementar a funcionalidade principal do comportamento.
Isso resulta na estrutura mostrada no exemplo de código a seguir:

public class CustomBehavior : Behavior<View>


{
protected override void OnAttachedTo (View bindable)
{
base.OnAttachedTo (bindable);
// Perform setup
}

protected override void OnDetachingFrom (View bindable)


{
base.OnDetachingFrom (bindable);
// Perform clean up
}

// Behavior implementation
}

O método OnAttachedTo será acionado imediatamente após o comportamento ser anexado a um controle. Esse
método recebe uma referência ao controle ao qual ele está anexado e pode ser usado para registrar
manipuladores de eventos ou para realizar outra configuração necessária para dar suporte à funcionalidade do
comportamento. Por exemplo, você pode assinar um evento em um controle. A funcionalidade do
comportamento, então, seria implementada no manipulador do evento.
O método OnDetachingFrom é acionado quando o comportamento é removido do controle. Esse método recebe
uma referência ao controle ao qual ele está anexado e é usado para executar qualquer limpeza necessária. Por
exemplo, você poderia cancelar a assinatura de um evento em um controle para evitar perdas de memória.
O comportamento, em seguida, poderá ser consumido sendo anexado à coleção Behaviors do controle
apropriado.

Criando um comportamento do Xamarin.Forms


O aplicativo de exemplo demonstra um NumericValidationBehavior , que destaca o valor inserido pelo usuário em
um controle Entry em vermelho, caso ele não seja um double . O comportamento é mostrado no exemplo de
código a seguir:

public class NumericValidationBehavior : Behavior<Entry>


{
protected override void OnAttachedTo(Entry entry)
{
entry.TextChanged += OnEntryTextChanged;
base.OnAttachedTo(entry);
}

protected override void OnDetachingFrom(Entry entry)


{
entry.TextChanged -= OnEntryTextChanged;
base.OnDetachingFrom(entry);
}

void OnEntryTextChanged(object sender, TextChangedEventArgs args)


{
double result;
bool isValid = double.TryParse (args.NewTextValue, out result);
((Entry)sender).TextColor = isValid ? Color.Default : Color.Red;
}
}

O NumericValidationBehavior deriva da classe Behavior<T> , em que T é um Entry . O método OnAttachedTo


registra um manipulador de eventos para o evento TextChanged , com o método OnDetachingFrom cancelando o
registro do evento TextChanged para evitar perdas de memória. A funcionalidade principal do comportamento é
fornecida pelo método OnEntryTextChanged , que analisa o valor inserido pelo usuário no Entry e define a
propriedade TextColor como vermelha caso o valor não seja um double .

NOTE
O Xamarin.Forms não define o BindingContext de um comportamento, porque os comportamentos podem ser
compartilhados e aplicados a vários controles por meio dos estilos.

Consumindo um comportamento do Xamarin.Forms


Cada controle do Xamarin.Forms tem uma coleção Behaviors , à qual um ou mais comportamentos podem ser
adicionados, conforme demonstrado no exemplo de código XAML a seguir:

<Entry Placeholder="Enter a System.Double">


<Entry.Behaviors>
<local:NumericValidationBehavior />
</Entry.Behaviors>
</Entry>

O Entry equivalente em C# é mostrado no exemplo de código a seguir:

var entry = new Entry { Placeholder = "Enter a System.Double" };


entry.Behaviors.Add (new NumericValidationBehavior ());

Em tempo de execução, o comportamento responderá à interação com o controle, de acordo com a


implementação do comportamento. As capturas de tela a seguir demonstram o comportamento respondendo a
uma entrada inválida:
NOTE
Comportamentos são escritos para um tipo de controle específico (ou uma superclasse que pode ser aplicada a muitos
controles) e só devem ser adicionados a um controle compatível. Tentar anexar um comportamento a um controle
incompatível fará com que uma exceção seja lançada.

Consumindo um comportamento do Xamarin.Forms com um estilo


Comportamentos também podem ser consumidos por um estilo explícito ou implícito. No entanto, não é possível
criar um estilo que define a propriedade Behaviors de um controle porque a propriedade é somente leitura. A
solução é adicionar uma propriedade anexada à classe do comportamento que controla a adição e a remoção do
comportamento. O processo é o seguinte:
1. Adicione uma propriedade anexada à classe do comportamento que será usado para controlar a adição ou
remoção do comportamento do controle a que o comportamento será anexado. Certifique-se de que a
propriedade anexada registre um delegado propertyChanged que será executado quando o valor da
propriedade for alterado.
2. Crie um getter e setter static para a propriedade anexada.
3. Implemente a lógica no delegado propertyChanged para adicionar e remover o comportamento.

O exemplo de código a seguir mostra uma propriedade anexada que controla a adição e a remoção de
NumericValidationBehavior :
public class NumericValidationBehavior : Behavior<Entry>
{
public static readonly BindableProperty AttachBehaviorProperty =
BindableProperty.CreateAttached ("AttachBehavior", typeof(bool), typeof(NumericValidationBehavior),
false, propertyChanged: OnAttachBehaviorChanged);

public static bool GetAttachBehavior (BindableObject view)


{
return (bool)view.GetValue (AttachBehaviorProperty);
}

public static void SetAttachBehavior (BindableObject view, bool value)


{
view.SetValue (AttachBehaviorProperty, value);
}

static void OnAttachBehaviorChanged (BindableObject view, object oldValue, object newValue)


{
var entry = view as Entry;
if (entry == null) {
return;
}

bool attachBehavior = (bool)newValue;


if (attachBehavior) {
entry.Behaviors.Add (new NumericValidationBehavior ());
} else {
var toRemove = entry.Behaviors.FirstOrDefault (b => b is NumericValidationBehavior);
if (toRemove != null) {
entry.Behaviors.Remove (toRemove);
}
}
}
...
}

A classe NumericValidationBehavior contém uma propriedade anexada chamada AttachBehavior , com um getter
e setter static , que controla a adição ou remoção do comportamento do controle a que ele será anexado. Essa
propriedade anexada registra o método OnAttachBehaviorChanged que será executado quando o valor da
propriedade for alterado. Esse método adiciona ou remove o comportamento do controle com base no valor da
propriedade anexada AttachBehavior .
O seguinte exemplo de código mostra um estilo explícito para o NumericValidationBehavior que usa a
propriedade anexada AttachBehavior e que pode ser aplicado a controles Entry :

<Style x:Key="NumericValidationStyle" TargetType="Entry">


<Style.Setters>
<Setter Property="local:NumericValidationBehavior.AttachBehavior" Value="true" />
</Style.Setters>
</Style>

O Style pode ser aplicado a um controle Entry definindo sua propriedade Style para a instância de Style
usando a extensão de marcação StaticResource , conforme demonstrado no exemplo de código a seguir:

<Entry Placeholder="Enter a System.Double" Style="{StaticResource NumericValidationStyle}">

Para mais informações sobre estilos, confira Estilos.


NOTE
Embora seja possível adicionar propriedades vinculáveis a um comportamento definido ou consultado no XAML, se você
criar comportamentos com estado, eles não deverão ser compartilhados entre os controles em um Style em um
ResourceDictionary .

Removendo um comportamento de um controle


O método OnDetachingFrom é acionado quando um comportamento é removido de um controle e é usado para
executar qualquer limpeza necessária, como cancelar a assinatura de um evento para evitar uma perda de
memória. No entanto, comportamentos não são removidos implicitamente dos controles a menos que a coleção
Behaviors do controle seja modificada por um método Remove ou Clear . O exemplo de código a seguir
demonstra como remover um comportamento específico da coleção Behaviors de um controle:

var toRemove = entry.Behaviors.FirstOrDefault (b => b is NumericValidationBehavior);


if (toRemove != null) {
entry.Behaviors.Remove (toRemove);
}

Como alternativa, a coleção Behaviors do controle pode ser limpa, conforme demonstrado no exemplo de código
a seguir:

entry.Behaviors.Clear();

Além disso, observe que os comportamentos não serão removidos implicitamente dos controles quando páginas
forem removidas da pilha de navegação. Em vez disso, eles devem ser removidos explicitamente antes que
páginas saiam do escopo.

Resumo
Este artigo demonstrou como criar e consumir comportamentos do Xamarin.Forms. Comportamentos do
Xamarin.Forms são criados derivando da classe Behavior ou Behavior<T> .

Links relacionados
Comportamento do Xamarin.Forms (amostra)
Comportamento de Xamarin.Forms aplicado com um estilo (amostra)
Comportamento
Comportamento
Comportamentos reutilizáveis
12/04/2019 • 2 minutes to read • Edit Online

Comportamentos são reutilizáveis em mais de um aplicativo. Estes artigos explicam como criar comportamentos
úteis para executar a funcionalidade comumente usada.

EffectBehavior reutilizável
Os comportamentos são uma abordagem útil para adicionar um efeito a um controle, removendo o código de
texto clichê de tratamento de efeito dos arquivos code-behind. Este artigo demonstra como criar e consumir um
comportamento de Xamarin.Forms para adicionar um efeito a um controle.

EventToCommandBehavior reutilizável
Comportamentos podem ser usados para associar comandos a controles que não foram projetados para interagir
com comandos. Este artigo demonstra como criar e consumir um comportamento de Xamarin.Forms para
invocar um comando quando um evento é disparado.
EffectBehavior reutilizável
12/04/2019 • 7 minutes to read • Edit Online

[![DBaixar a amostra](~/media/shared/download.png) Baixar a amostra]


(https://developer.xamarin.com/samples/xamarin-forms/behaviors/effectbehavior/)
Os comportamentos são uma abordagem útil para adicionar um efeito a um controle, removendo o código de
texto clichê de tratamento de efeito dos arquivos code-behind. Este artigo demonstra como criar e consumir um
comportamento de Xamarin.Forms para adicionar um efeito a um controle.

Visão geral
A classe EffectBehavior é um comportamento personalizado do Xamarin.Forms reutilizável que adiciona uma
instância Effect a um controle quando o comportamento é anexado ao controle e remove a instância Effect
quando o comportamento é desanexado do controle.
As seguintes propriedades de comportamento precisam ser definidas para que o comportamento seja usado:
Grupo – o valor do atributo ResolutionGroupName para a classe de efeito.
Name – o valor do atributo ExportEffect para a classe de efeito.
Para obter mais informações sobre efeitos, confira Efeitos.

NOTE
O EffectBehavior é uma classe personalizada que pode estar localizada no exemplo de Comportamento de efeito, e não
faz parte do Xamarin.Forms.

Criação do comportamento
A classe EffectBehaviorderiva da classe Behavior<T> , em que T é um View . Isso significa que a classe
EffectBehavior pode ser anexada a qualquer controle do Xamarin.Forms.
Implementação de propriedades associáveis
A classe EffectBehavior define duas instâncias BindableProperty , usadas para adicionar um Effect a um
controle quando o comportamento é anexado ao controle. Essas propriedades são mostradas no seguinte
exemplo de código:
public class EffectBehavior : Behavior<View>
{
public static readonly BindableProperty GroupProperty =
BindableProperty.Create ("Group", typeof(string), typeof(EffectBehavior), null);
public static readonly BindableProperty NameProperty =
BindableProperty.Create ("Name", typeof(string), typeof(EffectBehavior), null);

public string Group {


get { return (string)GetValue (GroupProperty); }
set { SetValue (GroupProperty, value); }
}

public string Name {


get { return(string)GetValue (NameProperty); }
set { SetValue (NameProperty, value); }
}
...
}

Quando o EffectBehavior é consumido, a propriedade Group deve ser definida como o valor do atributo
ResolutionGroupName para o efeito. Além disso, a propriedade Name deve ser definida como o valor do atributo
ExportEffect para o efeito.
Implementação de substituições
A classe EffectBehavior substitui os métodos OnAttachedTo e OnDetachingFrom da classe Behavior<T> , conforme
mostrado no seguinte exemplo de código:

public class EffectBehavior : Behavior<View>


{
...
protected override void OnAttachedTo (BindableObject bindable)
{
base.OnAttachedTo (bindable);
AddEffect (bindable as View);
}

protected override void OnDetachingFrom (BindableObject bindable)


{
RemoveEffect (bindable as View);
base.OnDetachingFrom (bindable);
}
...
}

O método OnAttachedTo realiza a instalação chamando o método AddEffect , passando o controle anexado como
parâmetro. O método OnDetachingFrom realiza a limpeza chamando o método RemoveEffect , passando o controle
anexado como um parâmetro.
Implementação da funcionalidade de comportamento
A finalidade do comportamento é adicionar o Effect definido nas propriedades Group e Name a um controle
quando o comportamento é anexado ao controle e remover o Effect quando o comportamento é desanexado do
controle. A principal funcionalidade de comportamento é mostrada no seguinte exemplo de código:
public class EffectBehavior : Behavior<View>
{
...
void AddEffect (View view)
{
var effect = GetEffect ();
if (effect != null) {
view.Effects.Add (GetEffect ());
}
}

void RemoveEffect (View view)


{
var effect = GetEffect ();
if (effect != null) {
view.Effects.Remove (GetEffect ());
}
}

Effect GetEffect ()
{
if (!string.IsNullOrWhiteSpace (Group) && !string.IsNullOrWhiteSpace (Name)) {
return Effect.Resolve (string.Format ("{0}.{1}", Group, Name));
}
return null;
}
}

O método AddEffect é executado em resposta ao EffectBehavior ser anexado a um controle e ele recebe o
controle anexado como um parâmetro. O método, então, adiciona o efeito recuperado à coleção Effects do
controle. O método RemoveEffect é executado em resposta ao EffectBehavior ser desanexado de um controle e
ele recebe o controle anexado como um parâmetro. O método, então, remove o efeito da coleção Effects do
controle.
O método GetEffect usa o método Effect.Resolve para recuperar o Effect . O efeito é localizado por meio de
uma concatenação dos valores de propriedade Group e Name . Se uma plataforma não fornecer o efeito, o método
Effect.Resolve retornará um valor não null .

Consumo do comportamento
A classe EffectBehavior pode ser anexada à coleção Behaviors de um controle, conforme demonstrado no
seguinte exemplo de código XAML:

<Label Text="Label Shadow Effect" ...>


<Label.Behaviors>
<local:EffectBehavior Group="Xamarin" Name="LabelShadowEffect" />
</Label.Behaviors>
</Label>

O código C# equivalente é mostrado no exemplo de código a seguir:

var label = new Label {


Text = "Label Shadow Effect",
...
};
label.Behaviors.Add (new EffectBehavior {
Group = "Xamarin",
Name = "LabelShadowEffect"
});
As propriedades Group e do comportamento são definidas como os valores dos atributos
Name
ResolutionGroupName e ExportEffect para a classe de efeito em cada projeto específico à plataforma.
No tempo de execução, quando o comportamento é anexado ao controle Label , o Xamarin.LabelShadowEffect
será anexado à coleção Effects do controle. Isso faz com que uma sombra seja adicionada ao texto exibido pelo
controle Label , conforme mostrado nas capturas de tela seguir:

A vantagem de usar esse comportamento para adicionar e remover efeitos de controles é que o código de
manipulação de efeito clichê pode ser removido de arquivos code-behind.

Resumo
Este artigo demonstrou o uso de um comportamento para adicionar um efeito a um controle. A classe
EffectBehavior é um comportamento personalizado do Xamarin.Forms reutilizável que adiciona uma instância
Effect a um controle quando o comportamento é anexado ao controle e remove a instância Effect quando o
comportamento é desanexado do controle.

Links relacionados
Efeitos
Comportamento de efeito (exemplo)
Comportamento
Comportamento<T>
EventToCommandBehavior reutilizável
12/04/2019 • 11 minutes to read • Edit Online

Baixar o exemplo
Comportamentos podem ser usados para associar comandos a controles que não foram projetados para interagir
com comandos. Este artigo demonstra como criar e consumir um comportamento do Xamarin.Forms para
invocar um comando quando um evento é disparado.

Visão geral
A classe EventToCommandBehavior é um comportamento personalizado reutilizável do Xamarin.Forms que executa
um comando em resposta a qualquer acionamento de evento. Por padrão, os argumentos de evento para o evento
serão passados para o comando e podem ser opcionalmente convertidos por uma implementação de
IValueConverter .

As seguintes propriedades de comportamento precisam ser definidas para que o comportamento seja usado:
EventName – o nome do evento que o comportamento escuta.
Command – o ICommand a ser executado. O comportamento espera encontrar a instância ICommand do
BindingContext do controle anexado, que pode ser herdada de um elemento pai.

As seguintes propriedades de comportamento opcionais também podem ser definidas:


CommandParameter – um object que será passado para o comando.
Converter – uma implementação de IValueConverter que alterará o formato dos dados de argumento do
evento conforme eles são passados entre a origem e o destino pelo mecanismo de associação.

NOTE
O EventToCommandBehavior é uma classe personalizada que pode estar localizada na amostra de Comportamento de
EventToCommand, não fazendo parte do Xamarin.Forms.

Criação do comportamento
A classe EventToCommandBehavior deriva da classe BehaviorBase<T> , que, por sua vez, deriva da classe Behavior<T> .
A finalidade da classe BehaviorBase<T> é fornecer uma classe base para todos os comportamentos do
Xamarin.Forms que exigem que o BindingContext do comportamento seja definido como o controle anexado. Isso
garante que o comportamento possa ser associado ao ICommand especificado pela propriedade Command e possa
executá-lo quando o comportamento for consumido.
A classe BehaviorBase<T> fornece um método OnAttachedTo substituível que define o BindingContext do
comportamento e um método OnDetachingFrom substituível que limpa o BindingContext . Além disso, a classe
armazena uma referência ao controle anexado na propriedade AssociatedObject .
Implementação de propriedades associáveis
A classe EventToCommandBehavior define quatro instâncias de BindableProperty , que executam um comando
definido pelo usuário quando um evento é disparado. Essas propriedades são mostradas no seguinte exemplo de
código:
public class EventToCommandBehavior : BehaviorBase<View>
{
public static readonly BindableProperty EventNameProperty =
BindableProperty.Create ("EventName", typeof(string), typeof(EventToCommandBehavior), null,
propertyChanged: OnEventNameChanged);
public static readonly BindableProperty CommandProperty =
BindableProperty.Create ("Command", typeof(ICommand), typeof(EventToCommandBehavior), null);
public static readonly BindableProperty CommandParameterProperty =
BindableProperty.Create ("CommandParameter", typeof(object), typeof(EventToCommandBehavior), null);
public static readonly BindableProperty InputConverterProperty =
BindableProperty.Create ("Converter", typeof(IValueConverter), typeof(EventToCommandBehavior), null);

public string EventName { ... }


public ICommand Command { ... }
public object CommandParameter { ... }
public IValueConverter Converter { ... }
...
}

Quando a classe EventToCommandBehavior é consumida, a propriedade Command deve ser associada a um ICommand ,
a ser executado em resposta ao acionamento do evento definido na propriedade EventName . O comportamento
esperará encontrar o ICommand no BindingContext do controle anexado.
Por padrão, os argumentos do evento para o evento serão passados para o comando. Esses dados podem ser
opcionalmente convertidos conforme são passados entre a origem e o destino pelo mecanismo de associação,
especificando uma implementação de IValueConverter como o valor da propriedade Converter . Como
alternativa, um parâmetro pode ser passado para o comando especificando o valor da propriedade
CommandParameter .

Implementação de substituições
A classe EventToCommandBehavior substitui os métodos OnAttachedTo e OnDetachingFrom da classe
BehaviorBase<T> , conforme mostrado no seguinte exemplo de código:

public class EventToCommandBehavior : BehaviorBase<View>


{
...
protected override void OnAttachedTo (View bindable)
{
base.OnAttachedTo (bindable);
RegisterEvent (EventName);
}

protected override void OnDetachingFrom (View bindable)


{
DeregisterEvent (EventName);
base.OnDetachingFrom (bindable);
}
...
}

O método OnAttachedTo executa a instalação por meio da chamada ao método RegisterEvent , passando o valor
da propriedade EventName como um parâmetro. O método OnDetachingFrom executa a limpeza por meio da
chamada ao método DeregisterEvent , passando o valor da propriedade EventName como um parâmetro.
Implementação da funcionalidade de comportamento
A finalidade do comportamento é executar o comando definido pela propriedade Command em resposta ao
acionamento do evento definido pela propriedade EventName . A principal funcionalidade de comportamento é
mostrada no seguinte exemplo de código:
public class EventToCommandBehavior : BehaviorBase<View>
{
...
void RegisterEvent (string name)
{
if (string.IsNullOrWhiteSpace (name)) {
return;
}

EventInfo eventInfo = AssociatedObject.GetType ().GetRuntimeEvent (name);


if (eventInfo == null) {
throw new ArgumentException (string.Format ("EventToCommandBehavior: Can't register the '{0}' event.",
EventName));
}
MethodInfo methodInfo = typeof(EventToCommandBehavior).GetTypeInfo ().GetDeclaredMethod ("OnEvent");
eventHandler = methodInfo.CreateDelegate (eventInfo.EventHandlerType, this);
eventInfo.AddEventHandler (AssociatedObject, eventHandler);
}

void OnEvent (object sender, object eventArgs)


{
if (Command == null) {
return;
}

object resolvedParameter;
if (CommandParameter != null) {
resolvedParameter = CommandParameter;
} else if (Converter != null) {
resolvedParameter = Converter.Convert (eventArgs, typeof(object), null, null);
} else {
resolvedParameter = eventArgs;
}

if (Command.CanExecute (resolvedParameter)) {
Command.Execute (resolvedParameter);
}
}
...
}

O método RegisterEvent é executado em resposta ao EventToCommandBehavior ser anexado a um controle e recebe


o valor da propriedade EventName como um parâmetro. Em seguida, o método tenta localizar no controle anexado
o evento definido na propriedade EventName . Desde que o evento possa ser localizado, o método OnEvent é
registrado para ser o método de manipulador para o evento.
O método OnEvent é executado em resposta ao acionamento do evento definido na propriedade EventName .
Desde que a propriedade Command referencie um ICommand válido, o método tenta recuperar um parâmetro para
passá-lo para o ICommand da seguinte maneira:
Se a propriedade CommandParameter define um parâmetro, ela é recuperada.
Caso contrário, se a propriedade Converter define uma implementação de IValueConverter , o conversor é
executado e converte os dados de argumento do evento conforme eles são passados entre a origem e o destino
pelo mecanismo de associação.
Caso contrário, os argumentos do evento deverão ser o parâmetro.
Em seguida, o ICommand associado a dados é executado, passando o parâmetro para o comando, desde que o
método CanExecute retorne true .
Embora não seja mostrado aqui, o EventToCommandBehavior também inclui um método DeregisterEvent que é
executado pelo método OnDetachingFrom . O método DeregisterEvent é usado para localizar e cancelar o registro
do evento definido na propriedade EventName , para limpar possíveis perdas de memória.

Consumo do comportamento
A classe EventToCommandBehavior pode ser anexada à coleção Behaviors de um controle, conforme demonstrado
no seguinte exemplo de código XAML:

<ListView ItemsSource="{Binding People}">


<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Name}" />
</DataTemplate>
</ListView.ItemTemplate>
<ListView.Behaviors>
<local:EventToCommandBehavior EventName="ItemSelected" Command="{Binding OutputAgeCommand}"
Converter="{StaticResource SelectedItemConverter}" />
</ListView.Behaviors>
</ListView>
<Label Text="{Binding SelectedItemText}" />

O código C# equivalente é mostrado no exemplo de código a seguir:

var listView = new ListView();


listView.SetBinding(ItemsView<Cell>.ItemsSourceProperty, "People");
listView.ItemTemplate = new DataTemplate(() =>
{
var textCell = new TextCell();
textCell.SetBinding(TextCell.TextProperty, "Name");
return textCell;
});
listView.Behaviors.Add(new EventToCommandBehavior
{
EventName = "ItemSelected",
Command = ((HomePageViewModel)BindingContext).OutputAgeCommand,
Converter = new SelectedItemEventArgsToSelectedItemConverter()
});

var selectedItemLabel = new Label();


selectedItemLabel.SetBinding(Label.TextProperty, "SelectedItemText");

A propriedade Command do comportamento é associado a dados à propriedade OutputAgeCommand do ViewModel


associado, enquanto a propriedade Converter é definida como a instância SelectedItemConverter , que retorna o
SelectedItem da ListView nos SelectedItemChangedEventArgs .

Em tempo de execução, o comportamento responderá à interação com o controle. Quando um item for
selecionado na ListView , o evento ItemSelected será disparado, o que executará o OutputAgeCommand no
ViewModel. Isso, por sua vez, atualiza a propriedade SelectedItemText do ViewModel à qual o Label está
associado, conforme mostrado nas seguintes capturas de tela:
A vantagem de usar esse comportamento para executar um comando quando um evento é disparado é que os
comandos podem ser associados a controles que não foram projetados para interagir com comandos. Além disso,
isso remove o código de manipulação de eventos de texto clichê dos arquivos code-behind.

Resumo
Este artigo demonstrou como usar um comportamento do Xamarin.Forms para invocar um comando quando um
evento é disparado. Comportamentos podem ser usados para associar comandos a controles que não foram
projetados para interagir com comandos.

Links relacionados
Comportamento de EventToCommand (amostra)
Comportamento
Comportamento<T>
Renderizadores personalizados do Xamarin.Forms
12/04/2019 • 5 minutes to read • Edit Online

As interfaces do usuário do Xamarin.Forms são renderizadas usando controles nativos da plataforma de


destino, permitindo que os aplicativos Xamarin.Forms mantenham a aparência apropriada para cada
plataforma. Renderizadores personalizados permitem que os usuários substituam esse processo para
personalizar a aparência e o comportamento de controles do Xamarin.Forms em cada plataforma.

Introdução a renderizadores personalizados


Renderizadores personalizados fornecem uma abordagem eficiente para personalizar a aparência e o
comportamento de controles do Xamarin.Forms. Eles podem ser usados para pequenas alterações de estilo ou
personalização sofisticada de comportamento e de layout específico da plataforma. Este artigo fornece uma
introdução aos renderizadores personalizados e descreve o processo de criação de um renderizador
personalizado.

Classes base do renderizador e controles nativos


Cada um dos controles do Xamarin.Forms tem um renderizador que o acompanha para cada plataforma que
cria uma instância de um controle nativo. Este artigo lista as classes de renderizador e controle nativo que
implementam cada página, layout, exibição e célula do Xamarin.Forms.

Personalizar uma entrada


O controle Entry do Xamarin.Forms permite que uma única linha de texto seja editada. Este artigo demonstra
como criar um renderizador personalizado para o controle Entry , permitindo que os desenvolvedores
substituam a renderização nativa padrão com sua própria personalização específica a uma plataforma.

Personalizar um ContentPage
Um ContentPage é um elemento visual que mostra uma única exibição e ocupa a maior parte da tela. Este
artigo demonstra como criar um renderizador personalizado para a página ContentPage , permitindo que os
desenvolvedores substituam a renderização nativa padrão com sua própria personalização específica a uma
plataforma.

Personalizar uma mapa


O Xamarin.Forms.Maps fornece uma abstração multiplataforma para a exibição de mapas que usam as APIs
de mapa nativo em cada plataforma, a fim de fornecer uma experiência de mapa rápida e familiar para os
usuários. Este tópico demonstra como criar renderizadores personalizados para o controle Map , permitindo
que os desenvolvedores substituam a renderização nativa padrão com sua própria personalização específica a
uma plataforma.

Personalizar uma ListView


Um ListView do Xamarin.Forms é uma exibição que mostra uma coleção de dados como uma lista vertical.
Este artigo demonstra como criar um renderizador personalizado que encapsula os controles de lista e layouts
de célula nativa específicos a uma plataforma, permitindo mais controle sobre o desempenho do controle de
lista nativo.
Personalizar uma ViewCell
Um ViewCell do Xamarin.Forms é uma célula que pode ser adicionada a um ListView ou TableView , que
contém uma exibição definida pelo desenvolvedor. Este artigo demonstra como criar um renderizador
personalizado para um ViewCell hospedado dentro de um controle ListView do Xamarin.Forms. Isso impede
que os cálculos de layout do Xamarin.Forms sejam chamados repetidamente durante a rolagem de ListView .

Implementar uma exibição


Controles de interfaces do usuário personalizadas do Xamarin.Forms devem derivar da classe View , que é
usada para colocar os layouts e controles na tela. Este artigo demonstra como criar um renderizador
personalizado para um controle personalizado do Xamarin.Forms, que é usado para exibir uma transmissão de
vídeo de prévia com a câmera do dispositivo.

Implementar um HybridWebView
Este artigo demonstra como criar um renderizador personalizado para um controle personalizado
HybridWebView , que demonstra como aprimorar os controles da Web específicos a uma plataforma para
permitir que código C# seja invocado do JavaScript.

Implementar um player de vídeo


Este artigo mostra como gravar renderizadores para implementar um controle personalizado VideoPlayer que
pode reproduzir vídeos da Web, vídeos inseridos como recursos de aplicativo ou vídeos armazenados na
biblioteca de vídeos no dispositivo do usuário. Várias técnicas são demonstradas, incluindo a implementação de
métodos e de propriedades vinculáveis somente leitura.

Links relacionados
Efeitos
Renderizadores personalizados (vídeo do Xamarin University)
Introdução a renderizadores personalizados
12/04/2019 • 9 minutes to read • Edit Online

Renderizadores personalizados fornecem uma abordagem eficiente para personalizar a aparência e o


comportamento de controles do Xamarin.Forms. Eles podem ser usados para pequenas alterações de estilo ou
personalização sofisticada de comportamento e de layout específico da plataforma. Este artigo fornece uma
introdução aos renderizadores personalizados e descreve o processo de criação de um renderizador
personalizado.
Páginas, Layouts e Controles do Xamarin.Forms apresenta uma API comum para descrever interfaces do usuário
móveis multiplataforma. Cada página, layout e controle é renderizado de maneira diferente em cada plataforma
usando uma classe Renderer , que por sua vez cria um controle nativo (correspondente à representação no
Xamarin.Forms), organiza sua disposição na tela e adiciona o comportamento especificado no código
compartilhado.
Os desenvolvedores podem implementar suas próprias classes Renderer personalizadas para personalizar a
aparência e/ou o comportamento de um controle. Renderizadores personalizados de um determinado tipo podem
ser adicionados ao projeto de um aplicativo para personalizar o controle em um lugar enquanto permite o
comportamento padrão em outras plataformas; ou renderizadores personalizados diferentes podem ser
adicionados a cada projeto de aplicativo para criar uma aparência diferente no iOS, no Android e na UWP
(Plataforma Universal do Windows). No entanto, implementar uma classe de renderizador personalizado para
executar uma personalização de controle simples geralmente gera uma resposta pesada. Os efeitos simplificam
esse processo e normalmente são usados para pequenas alterações de estilo. Para obter mais informações, veja
Efeitos.

Examinando por que renderizadores personalizados são necessários


Alterar a aparência de um controle do Xamarin.Forms sem usar um renderizador personalizado é um processo de
duas etapas que envolve criar um controle personalizado por meio de subclasses e, em seguida, consumir o
controle personalizado no lugar do controle original. O código a seguir mostra um exemplo da criação de
subclasses do controle Entry :

public class MyEntry : Entry


{
public MyEntry ()
{
BackgroundColor = Color.Gray;
}
}

O controle MyEntry é um controle Entry em que o BackgroundColor é definido como cinza, que pode ser
referenciado no XAML declarando um namespace para sua localização e usando o prefixo do namespace no
elemento de controle. O seguinte exemplo de código mostra como o controle personalizado MyEntry pode ser
consumido por um ContentPage :
<ContentPage
...
xmlns:local="clr-namespace:CustomRenderer;assembly=CustomRenderer"
...>
...
<local:MyEntry Text="In Shared Code" />
...
</ContentPage>

O prefixo do namespace local pode ser qualquer coisa. No entanto, os valores de namespace e assembly devem
corresponder aos detalhes do controle personalizado. Quando o namespace é declarado, o prefixo é usado para
referenciar o controle personalizado.

NOTE
Definir o xmlns é muito mais simples em projetos de biblioteca do .NET Standard do que em projetos compartilhados. Uma
biblioteca do .NET Standard é compilada em um assembly e, portanto, é fácil determinar qual deveria ser o valor de
assembly=CustomRenderer . Ao usar Projetos compartilhados, todos os ativos compartilhados (incluindo o XAML) são
compilados em cada um dos projetos de referência, o que significa que, se os projetos do iOS, do Android e da UWP tiverem
seus próprios nomes de assembly, será impossível escrever a declaração xmlns porque o valor deverá ser diferente para
cada aplicativo. Controles personalizados em XAML para Projetos compartilhados exigirão que cada projeto de aplicativo seja
configurado com o mesmo nome de assembly.

O controle personalizado MyEntry é renderizado em cada plataforma, com uma tela de fundo cinza, conforme
mostrado nas capturas de tela seguir:

A alteração da cor da tela de fundo do controle em cada plataforma foi feira usando apenas subclasses do controle.
No entanto, há limites para o que é possível realizar com essa técnica, pois não é possível tirar proveito dos
aprimoramentos e personalizações específicos da plataforma. Quando são necessários, renderizadores
personalizados devem ser implementados.

Criando uma classe de renderizador personalizado


O processo para criar uma classe de renderizador personalizado é a seguinte:
1. Criar uma subclasse da classe do renderizador que renderiza o controle nativo.
2. Substitua o método que renderiza o controle nativo e escreva a lógica para personalizá-lo. Frequentemente, o
método OnElementChanged é usado para renderizar o controle nativo, que é chamado quando um controle do
Xamarin.Forms correspondente é criado.
3. Adicionar um atributo ExportRenderer à classe do renderizador personalizado para especificar que ele será
usado para renderizar o controle do Xamarin.Forms. Esse atributo é usado para registrar o renderizador
personalizado no Xamarin.Forms.
NOTE
Para a maioria dos elementos do Xamarin.Forms, o fornecimento de um renderizador personalizado em cada projeto de
plataforma é opcional. Se um renderizador personalizado não estiver registrado, será usado o renderizador padrão da classe
base do controle. No entanto, são necessários renderizadores personalizados em cada projeto da plataforma durante a
renderização de um elemento View ou ViewCell.

Os tópicos desta série fornecem demonstrações e explicações sobre esse processo para diferentes elementos do
Xamarin.Forms.

Solução de problemas
Se um controle personalizado estiver em um projeto de biblioteca do .NET Standard que foi adicionado à solução
(ou seja, não na biblioteca do .NET Standard criada pelo modelo de projeto de aplicativo do Xamarin.Forms para
Visual Studio para Mac/Visual Studio), poderá ocorrer uma exceção no iOS ao tentar acessar o controle
personalizado. Se esse problema ocorrer, ele poderá ser resolvido criando uma referência ao controle
personalizado usando a classe AppDelegate :

var temp = new ClassInPCL(); // in AppDelegate, but temp not used anywhere

Isso força o compilador a reconhecer o tipo ClassInPCL resolvendo-o. Como alternativa, o atributo Preserve pode
ser adicionado à classe AppDelegate para alcançar o mesmo resultado:

[assembly: Preserve (typeof (ClassInPCL))]

Isso cria uma referência ao tipo ClassInPCL , indicando que ele é necessário no tempo de execução. Para obter
mais informações, confira Preservando o código.

Resumo
Este artigo forneceu uma introdução aos renderizadores personalizados e descreveu o processo de criação de um
renderizador personalizado. Renderizadores personalizados fornecem uma abordagem eficiente para personalizar
a aparência e o comportamento de controles do Xamarin.Forms. Eles podem ser usados para pequenas alterações
de estilo ou personalização sofisticada de comportamento e de layout específico da plataforma.

Links relacionados
Efeitos
Classes base de renderizador e controles nativos
12/04/2019 • 5 minutes to read • Edit Online

Cada controle do Xamarin.Forms tem um renderizador que o acompanha para cada plataforma que cria uma
instância de um controle nativo. Este artigo lista as classes de renderizador e controle nativo que implementam
cada página, layout, exibição e célula do Xamarin.Forms.
Com exceção da classe MapRenderer , os renderizadores específicos da plataforma podem ser encontrados nos
seguintes namespaces:
iOS – Xamarin.Forms.Platform.iOS
Android – Xamarin.Forms.Platform.Android
Android (AppCompat) – Xamarin.Forms.Platform.Android.AppCompat
UWP (Plataforma Universal do Windows) – Xamarin.Forms.Platform.UWP
A classe MapRenderer pode ser encontrada nos seguintes namespaces:
iOS – Xamarin.Forms.Maps.iOS
Android – Xamarin.Forms.Maps.Android
UWP (Plataforma Universal do Windows) – Xamarin.Forms.Maps.UWP

Pages (Páginas)
A seguinte tabela lista as classes de renderizador e controle nativo que implementam cada tipo Page do
Xamarin.Forms:

ANDROID
PÁGINA RENDERIZADOR IOS ANDROID (APPCOMPAT) UWP

ContentPage PageRenderer UIViewController ViewGroup FrameworkEleme


nt

MasterDetailPage PhoneMasterDet UIViewController DrawerLayout DrawerLayout FrameworkEleme


ailRenderer (iOS (Telefone), (v4) (v4) nt (Controle
– Telefone), UISplitViewContr Personalizado)
TabletMasterDet oller (Tablet)
ailPageRenderer
(iOS – Tablet),
MasterDetailRen
derer (Android),
MasterDetailPag
eRenderer
(Android
AppCompat),
MasterDetailPag
eRenderer (UWP)
ANDROID
PÁGINA RENDERIZADOR IOS ANDROID (APPCOMPAT) UWP

NavigationPage NavigationRende UIToolbar ViewGroup ViewGroup FrameworkEleme


rer (iOS e nt (Controle
Android), Personalizado)
NavigationPageR
enderer (Android
AppCompat),
NavigationPageR
enderer (UWP)

TabbedPage TabbedRenderer UIView ViewPager ViewPager FrameworkEleme


(iOS e Android), nt (Pivô)
TabbedPageRend
erer (Android
AppCompat),
TabbedPageRend
erer (UWP)

TemplatedPage PageRenderer UIViewController ViewGroup FrameworkEleme


nt

CarouselPage CarouselPageRen UIScrollView ViewPager ViewPager FrameworkEleme


derer nt (FlipView)

Layouts
A seguinte tabela lista as classes de renderizador e controle nativo que implementam cada tipo Layout do
Xamarin.Forms:

LAYOUT RENDERIZADOR IOS ANDROID UWP

ContentPresenter ViewRenderer UIView Exibir FrameworkElement

ContentView ViewRenderer UIView Exibir FrameworkElement

FlexLayout ViewRenderer UIView Exibir FrameworkElement

Frame FrameRenderer UIView ViewGroup Borda

ScrollView ScrollViewRenderer UIScrollView ScrollView ScrollViewer

TemplatedView ViewRenderer UIView Exibir FrameworkElement

AbsoluteLayout ViewRenderer UIView Exibir FrameworkElement

Grid ViewRenderer UIView Exibir FrameworkElement

RelativeLayout ViewRenderer UIView Exibir FrameworkElement

StackLayout ViewRenderer UIView Exibir FrameworkElement

Exibições
A seguinte tabela lista as classes de renderizador e controle nativo que implementam cada tipo View do
Xamarin.Forms:

ANDROID
EXIBIÇÕES RENDERIZADOR IOS ANDROID (APPCOMPAT) UWP

ActivityIndicator ActivityIndicator UIActivityIndicat ProgressBar ProgressBar


Renderer or

BoxView BoxRenderer (iOS UIView ViewGroup Retângulo


e Android),
BoxViewRenderer
(UWP)

Button ButtonRenderer UIButton Botão AppCompatButt Botão


on

CollectionView CollectionViewRe UICollectionView RecyclerView


nderer

DatePicker DatePickerRende UITextField EditText DatePicker


rer

Editor EditorRenderer UITextView EditText TextBox

Entry EntryRenderer UITextField EditText TextBox

Image ImageRenderer UIImageView ImageView Image

ImageButton ImageButtonRen UIButton AppCompatImag Botão


derer eButton

Label LabelRenderer UILabel TextView TextBlock

ListView ListViewRenderer UITableView ListView ListView

Map MapRenderer MKMapView MapView MapControl

Picker PickerRenderer UITextField EditText EditText ComboBox

ProgressBar ProgressBarRend UIProgressView ProgressBar ProgressBar


erer

SearchBar SearchBarRender UISearchBar SearchView AutoSuggestBox


er

Slider SliderRenderer UISlider SeekBar Controle


deslizante

Stepper StepperRenderer UIStepper LinearLayout Controle

Switch SwitchRenderer UISwitch Alternar SwitchCompat ToggleSwitch


ANDROID
EXIBIÇÕES RENDERIZADOR IOS ANDROID (APPCOMPAT) UWP

TableView TableViewRender UITableView ListView ListView


er

TimePicker TimePickerRende UITextField EditText TimePicker


rer

WebView WebViewRender UIWebView WebView WebView


er

Células
A seguinte tabela lista as classes de renderizador e controle nativo que implementam cada tipo Cell do
Xamarin.Forms:

CÉLULAS RENDERIZADOR IOS ANDROID UWP

EntryCell EntryCellRenderer UITableViewCell com LinearLayout com DataTemplate com


um UITextField uma TextView e um uma TextBox
EditText

SwitchCell SwitchCellRenderer UITableViewCell com Alternar DataTemplate com


um UISwitch uma Grid contendo
um TextBlock e um
ToggleSwitch

TextCell TextCellRenderer UITableViewCell LinearLayout com DataTemplate com


duas TextViews um StackPanel
contendo dois
TextBlocks

ImageCell ImageCellRenderer UITableViewCell com LinearLayout com DataTemplate com


uma UIImage duas TextViews e uma Grade contendo
uma ImageView uma Imagem e dois
TextBlocks

ViewCell ViewCellRenderer UITableViewCell Exibir DataTemplate com


um ContentPresenter

Resumo
Este artigo listou as classes de renderizador e controle nativo que implementam cada página, layout, exibição e
célula do Xamarin.Forms. Cada controle do Xamarin.Forms tem um renderizador que o acompanha para cada
plataforma que cria uma instância de um controle nativo.

Links relacionados
Renderizadores personalizados (vídeo do Xamarin University)
Personalizando uma entrada
12/04/2019 • 12 minutes to read • Edit Online

Baixar o exemplo
O controle Entry do Xamarin.Forms permite a edição de uma única linha de texto. Este artigo demonstra como
criar um renderizador personalizado para o controle Entry, permitindo que os desenvolvedores substituam a
renderização nativa padrão por sua própria personalização específica da plataforma.
Cada controle do Xamarin.Forms tem um renderizador que o acompanha para cada plataforma que cria uma
instância de um controle nativo. Quando um controle Entry é renderizado por um aplicativo Xamarin.Forms, no
iOS, é criada uma instância da classe EntryRenderer , que, por sua vez, cria uma instância de um controle
UITextField nativo. Na plataforma Android, a classe EntryRenderer cria uma instância de um controle EditText .
No UWP (Plataforma Universal do Windows), a classe EntryRenderer cria uma instância de um controle TextBox .
Para obter mais informações sobre as classes de renderizador e de controle nativo para as quais os controles do
Xamarin.Forms são mapeadas, confira Classes base do renderizador e controles nativos.
O diagrama a seguir ilustra a relação entre o controle Entry e os controles nativos correspondentes que o
implementam:

É possível aproveitar o processo de renderização para implementar personalizações específicas da plataforma


criando um renderizador personalizado para o controle Entry em cada plataforma. O processo para fazer isso é o
seguinte:
1. Criar um controle personalizado do Xamarin.Forms.
2. Consumir o controle personalizado do Xamarin.Forms.
3. Criar o renderizador personalizado para o controle em cada plataforma.
Cada item agora será abordado um por vez, para implementar um controle Entry que tenha uma cor da tela de
fundo diferente em cada plataforma.
IMPORTANT
Este artigo explica como criar um renderizador personalizado simples. No entanto, não é necessário criar um renderizador
personalizado para implementar uma Entry que tenha uma cor da tela de fundo diferente em cada plataforma. Isso pode
ser feito com mais facilidade usando a classe Device , ou a extensão de marcação OnPlatform , para fornecer valores
específicos da plataforma. Para obter mais informações, confira Fornecendo valores específicos da plataforma e Extensão de
marcação OnPlatform.

Criando o controle de entrada personalizado


É possível criar um controle Entry personalizado criando subclasses da classe Entry , conforme mostrado no
seguinte exemplo de código:

public class MyEntry : Entry


{
}

O controle MyEntry é criado no projeto da biblioteca do .NET Standard e é apenas um controle Entry . A
personalização do controle será realizada no renderizador personalizado. Portanto, nenhuma implementação
adicional é necessária no controle MyEntry .

Consumindo o controle personalizado


O controle MyEntry pode ser referenciado em XAML no projeto da biblioteca do .NET Standard declarando um
namespace para sua localização e usando o prefixo do namespace no elemento de controle. O seguinte exemplo
de código mostra como o controle MyEntry pode ser consumido por uma página XAML:

<ContentPage ...
xmlns:local="clr-namespace:CustomRenderer;assembly=CustomRenderer"
...>
...
<local:MyEntry Text="In Shared Code" />
...
</ContentPage>

O prefixo do namespace local pode ter qualquer nome. No entanto, os valores de clr-namespace e assembly
devem corresponder aos detalhes do controle personalizado. Quando o namespace é declarado, o prefixo é usado
para referenciar o controle personalizado.
O seguinte exemplo de código mostra como o controle MyEntry pode ser consumido por uma página em C#:
public class MainPage : ContentPage
{
public MainPage ()
{
Content = new StackLayout {
Children = {
new Label {
Text = "Hello, Custom Renderer !",
},
new MyEntry {
Text = "In Shared Code",
}
},
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.CenterAndExpand,
};
}
}

Esse código cria uma instância de um novo objeto ContentPage que exibirá um Label e um controle MyEntry ,
centralizado vertical e horizontalmente na página.
Agora, um renderizador personalizado pode ser adicionado a cada projeto de aplicativo para personalizar a
aparência do controle em cada plataforma.

Criando o renderizador personalizado em cada plataforma


O processo para criar a classe do renderizador personalizado é o seguinte:
1. Criar uma subclasse da classe EntryRenderer que renderiza o controle nativo.
2. Substituir o método OnElementChanged que renderiza o controle nativo e escrever a lógica para personalizá-lo.
Esse método é chamado quando o controle do Xamarin.Forms correspondente é criado.
3. Adicionar um atributo ExportRenderer à classe do renderizador personalizado para especificar que ele será
usado para renderizar o controle do Xamarin.Forms. Esse atributo é usado para registrar o renderizador
personalizado no Xamarin.Forms.

NOTE
O fornecimento de um renderizador personalizado em cada projeto da plataforma é opcional. Se um renderizador
personalizado não estiver registrado, será usado o renderizador padrão da classe base do controle.

O seguinte diagrama ilustra as responsabilidades de cada projeto no aplicativo de exemplo, bem como as relações
entre elas:

O controle MyEntry é renderizado por classes MyEntryRenderer específicas da plataforma, que derivam da classe
EntryRenderer para cada plataforma. Isso faz com que cada controle MyEntry seja renderizado com a cor da tela
de fundo específica da plataforma, conforme mostrado nas seguintes capturas de tela:
A classe EntryRenderer expõe o método OnElementChanged , que é chamado quando um controle do
Xamarin.Forms é criado para renderizar o controle nativo correspondente. Esse método usa um parâmetro
ElementChangedEventArgs , que contém as propriedades OldElement e NewElement . Essas propriedades
representam o elemento do Xamarin.Forms ao qual o renderizador estava anexado e o elemento do
Xamarin.Forms ao qual o renderizador está anexado, respectivamente. No aplicativo de exemplo, a propriedade
OldElement será null e a propriedade NewElement conterá uma referência ao controle MyEntry .

Uma versão de substituição do método OnElementChanged na classe MyEntryRenderer é o lugar para realizar a
personalização do controle nativo. Uma referência tipada ao controle nativo que está sendo usado na plataforma
pode ser acessada por meio da propriedade Control . Além disso, é possível obter uma referência ao controle do
Xamarin.Forms que está sendo renderizado por meio da propriedade Element , embora ela não seja usada no
aplicativo de exemplo.
Cada classe de renderizador personalizado é decorada com um atributo ExportRenderer que registra o
renderizador no Xamarin.Forms. O atributo usa dois parâmetros – o nome do tipo do controle do Xamarin.Forms
que está sendo renderizado e o nome do tipo do renderizador personalizado. O prefixo assembly do atributo
especifica que o atributo se aplica a todo o assembly.
As seções a seguir abordam a implementação de cada classe de renderizador personalizado MyEntryRenderer
específica da plataforma.
Criando o renderizador personalizado no iOS
O seguinte exemplo de código mostra o renderizador personalizado para a plataforma iOS:

using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer (typeof(MyEntry), typeof(MyEntryRenderer))]


namespace CustomRenderer.iOS
{
public class MyEntryRenderer : EntryRenderer
{
protected override void OnElementChanged (ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged (e);

if (Control != null) {
// do whatever you want to the UITextField here!
Control.BackgroundColor = UIColor.FromRGB (204, 153, 255);
Control.BorderStyle = UITextBorderStyle.Line;
}
}
}
}

A chamada ao método OnElementChanged da classe base cria uma instância de um controle UITextField do iOS,
com uma referência ao controle que está sendo atribuído à propriedade Control do renderizador. A cor da tela de
fundo é definida como roxo-claro com o método UIColor.FromRGB .
Criando o renderizador personalizado no Android
O seguinte exemplo de código mostra o renderizador personalizado para a plataforma Android:

using Xamarin.Forms.Platform.Android;

[assembly: ExportRenderer(typeof(MyEntry), typeof(MyEntryRenderer))]


namespace CustomRenderer.Android
{
class MyEntryRenderer : EntryRenderer
{
public MyEntryRenderer(Context context) : base(context)
{
}

protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)


{
base.OnElementChanged(e);

if (Control != null)
{
Control.SetBackgroundColor(global::Android.Graphics.Color.LightGreen);
}
}
}
}

A chamada ao método OnElementChanged da classe base cria uma instância de um controle EditText do Android,
com uma referência ao controle que está sendo atribuído à propriedade Control do renderizador. A cor da tela de
fundo é definida como verde-claro com o método Control.SetBackgroundColor .
Criando o renderizador personalizado na UWP
O seguinte exemplo de código mostra o renderizador personalizado para o UWP:

[assembly: ExportRenderer(typeof(MyEntry), typeof(MyEntryRenderer))]


namespace CustomRenderer.UWP
{
public class MyEntryRenderer : EntryRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);

if (Control != null)
{
Control.Background = new SolidColorBrush(Colors.Cyan);
}
}
}
}

A chamada ao método OnElementChanged da classe base cria uma instância de um controle TextBox , com uma
referência ao controle que está sendo atribuído à propriedade Control do renderizador. A cor da tela de fundo é
então definida como ciano pela criação de uma instância SolidColorBrush .

Resumo
Este artigo demonstrou como criar um renderizador de controle personalizado para o controle Entry do
Xamarin.Forms, permitindo que os desenvolvedores substituam a renderização nativa padrão por sua própria
personalização específica da plataforma. Os renderizadores personalizados fornecem uma abordagem eficiente
para personalizar a aparência de controles do Xamarin.Forms. Eles podem ser usados para pequenas alterações de
estilo ou personalização sofisticada de comportamento e de layout específico da plataforma.

Links relacionados
CustomRendererEntry (amostra)
Personalizando uma ContentPage
12/04/2019 • 13 minutes to read • Edit Online

Baixar o exemplo
Uma ContentPage é um elemento visual que mostra uma única exibição e ocupa a maior parte da tela. Este
artigo mostra como criar um renderizador personalizado para a página ContentPage, permitindo que os
desenvolvedores substituam a renderização nativa padrão por sua própria personalização específica a uma
plataforma.
Cada um dos controles do Xamarin.Forms tem um renderizador que o acompanha para cada plataforma que cria
uma instância de um controle nativo. Quando um ContentPage é renderizado por um aplicativo Xamarin.Forms,
no iOS é criada uma instância da classe PageRenderer , o que por sua vez cria uma instância de um controle
UIViewController nativo. Na plataforma Android, a classe PageRenderer cria uma instância de um controle
ViewGroup . Na UWP ( Plataforma Universal do Windows), a classe PageRenderer cria uma instância de um
controle FrameworkElement . Para obter mais informações sobre as classes de renderizador e de controle nativo
para as quais os controles do Xamarin.Forms são mapeadas, confira Classes base do renderizador e controles
nativos.
O diagrama a seguir ilustra a relação entre o ContentPage e os controles nativos correspondentes que o
implementam:

E possível aproveitar o processo de renderização para implementar personalizações específicas da plataforma


criando um renderizador personalizado para um ContentPage em cada plataforma. O processo para fazer isso é o
seguinte:
1. Criar uma página no Xamarin.Forms.
2. Consumir a página do Xamarin.Forms.
3. Criar o renderizador personalizado para a página em cada plataforma.
Agora, cada item será abordado separadamente, a fim de implementar um CameraPage que fornece um feed de
câmera em tempo real e a capacidade de tirar uma foto.

Criando a página do Xamarin.Forms


Um ContentPage inalterado pode ser adicionado ao projeto do Xamarin.Forms compartilhado, conforme
mostrado no exemplo de código XAML a seguir:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="CustomRenderer.CameraPage">
<ContentPage.Content>
</ContentPage.Content>
</ContentPage>

De forma semelhante, o arquivo code-behind do ContentPage também deve permanecer inalterado, conforme
mostrado no exemplo de código a seguir:

public partial class CameraPage : ContentPage


{
public CameraPage ()
{
// A custom renderer is used to display the camera UI
InitializeComponent ();
}
}

O exemplo de código a seguir mostra como a página pode ser criada em C#:

public class CameraPageCS : ContentPage


{
public CameraPageCS ()
{
}
}

Uma instância do CameraPage será usada para exibir o feed de câmera em tempo real em cada plataforma. A
personalização do controle será realizada no renderizador personalizado, portanto, nenhuma implementação
adicional é necessária na classe CameraPage .

Consumindo a página do Xamarin.Forms


O CameraPage vazio deve ser exibido pelo aplicativo do Xamarin.Forms. Isso ocorre quando um botão na instância
de MainPage é tocado, o que por sua vez executa o método OnTakePhotoButtonClicked , conforme mostrado no
exemplo de código a seguir:

async void OnTakePhotoButtonClicked (object sender, EventArgs e)


{
await Navigation.PushAsync (new CameraPage ());
}

Esse código simplesmente navega para o CameraPage , em que os renderizadores personalizados personalizarão a
aparência da página em cada plataforma.

Criando o renderizador da página em cada plataforma


O processo para criar a classe do renderizador personalizado é a seguinte:
1. Crie uma subclasse da classe PageRenderer .
2. Substitua o método OnElementChanged que renderiza a página nativa e escreva a lógica para personalizá-la. O
método OnElementChanged é chamado quando o controle do Xamarin.Forms correspondente é criado.
3. Adicione um atributo ExportRenderer à classe do renderizador da página para especificar que ele será usado
para renderizar a página do Xamarin.Forms. Este atributo é usado para registrar o renderizador personalizado
no Xamarin.Forms.

NOTE
O fornecimento de um renderizador de página em cada projeto de plataforma é opcional. Se um renderizador de página não
estiver registrado, será usado o renderizador de página padrão.

O diagrama a seguir ilustra as responsabilidades de cada projeto no aplicativo de exemplo, bem como a relação
entre elas:

A instância de CameraPage é renderizada por classes de CameraPageRenderer específicas da plataforma, que


derivam da classe PageRenderer para cada plataforma. Isso faz com que cada instância de CameraPage seja
renderizada com um feed de câmera em tempo real, conforme mostrado nas capturas de tela seguir:

A classe PageRenderer expõe o método OnElementChanged , que é chamado quando a página do Xamarin.Forms é
criada para renderizar o controle nativo correspondente. Esse método usa um parâmetro ElementChangedEventArgs
, que contém as propriedades OldElement e NewElement . Essas propriedades representam o elemento do
Xamarin.Forms ao qual o renderizador estava anexado e o elemento do Xamarin.Forms ao qual o renderizador
está anexado, respectivamente. No aplicativo de exemplo, a propriedade OldElement será null e a propriedade
NewElement conterá uma referência à instância de CameraPage .

Uma versão de substituição do método OnElementChanged na classe CameraPageRenderer é o lugar para realização
da personalização da página nativa. É possível obter uma referência para a instância da página do Xamarin.Forms
que está sendo renderizada por meio da propriedade Element .
Cada classe de renderizador personalizado é decorada com um atributo ExportRenderer que registra o
renderizador no Xamarin.Forms. O atributo aceita dois parâmetros – o nome do tipo de página do Xamarin.Forms
que está sendo renderizada e o nome do tipo de renderizador personalizado. O prefixo assembly do atributo
especifica que o atributo se aplica a todo o assembly.
As seções a seguir abordam a implementação do renderizador personalizado CameraPageRenderer para cada
plataforma.
Criando o renderizador de página no iOS
O exemplo de código a seguir mostra o renderizador de página para a plataforma iOS:

[assembly:ExportRenderer (typeof(CameraPage), typeof(CameraPageRenderer))]


namespace CustomRenderer.iOS
{
public class CameraPageRenderer : PageRenderer
{
...

protected override void OnElementChanged (VisualElementChangedEventArgs e)


{
base.OnElementChanged (e);

if (e.OldElement != null || Element == null) {


return;
}

try {
SetupUserInterface ();
SetupEventHandlers ();
SetupLiveCameraStream ();
AuthorizeCameraUse ();
} catch (Exception ex) {
System.Diagnostics.Debug.WriteLine (@" ERROR: ", ex.Message);
}
}
...
}
}

A chamada para o método OnElementChanged da classe base cria uma instância do controle UIViewController do
iOS. O fluxo da câmera em tempo real será renderizado somente se o renderizador ainda não estiver anexado a
um elemento existente do Xamarin.Forms e se houver uma instância da página sendo renderizada pelo
renderizador personalizado.
A página, então, é personalizada por uma série de métodos que usam as APIs AVCapture para fornecer o -fluxo
em tempo real da câmera e a capacidade de tirar uma foto.
Criando o renderizador de página no Android
O exemplo de código a seguir mostra o renderizador de página para a plataforma Android:
[assembly: ExportRenderer(typeof(CameraPage), typeof(CameraPageRenderer))]
namespace CustomRenderer.Droid
{
public class CameraPageRenderer : PageRenderer, TextureView.ISurfaceTextureListener
{
...
public CameraPageRenderer(Context context) : base(context)
{
}

protected override void OnElementChanged(ElementChangedEventArgs<Page> e)


{
base.OnElementChanged(e);

if (e.OldElement != null || Element == null)


{
return;
}

try
{
SetupUserInterface();
SetupEventHandlers();
AddView(view);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(@" ERROR: ", ex.Message);
}
}
...
}
}

A chamada para o método OnElementChanged da classe base cria uma instância de um controle ViewGroup do
Android, que é um grupo de exibições. O fluxo da câmera em tempo real será renderizado somente se o
renderizador ainda não estiver anexado a um elemento existente do Xamarin.Forms e se houver uma instância da
página sendo renderizada pelo renderizador personalizado.
A página, então, é personalizada invocando uma série de métodos que usam a API Camera para fornecer o fluxo
em tempo real da câmera e a capacidade de tirar uma foto, antes que o método AddView seja invocado para
adicionar a interface do usuário de fluxo em tempo real da câmera ao ViewGroup . Observe que, no Android,
também é necessário substituir o método OnLayout para executar operações de medida e layout na exibição. Para
obter mais informações, confira o Exemplo de renderizador de ContentPage.
Criando o renderizador de página na UWP
O exemplo de código a seguir mostra o renderizador de página para a UWP:
[assembly: ExportRenderer(typeof(CameraPage), typeof(CameraPageRenderer))]
namespace CustomRenderer.UWP
{
public class CameraPageRenderer : PageRenderer
{
...
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Page> e)
{
base.OnElementChanged(e);

if (e.OldElement != null || Element == null)


{
return;
}

try
{
...
SetupUserInterface();
SetupBasedOnStateAsync();

this.Children.Add(page);
}
...
}

protected override Size ArrangeOverride(Size finalSize)


{
page.Arrange(new Windows.Foundation.Rect(0, 0, finalSize.Width, finalSize.Height));
return finalSize;
}
...
}
}

A chamada para o método OnElementChanged da classe base instancia um controle FrameworkElement , em que a
página é renderizada. O fluxo da câmera em tempo real será renderizado somente se o renderizador ainda não
estiver anexado a um elemento existente do Xamarin.Forms e se houver uma instância da página sendo
renderizada pelo renderizador personalizado. A página, então, é personalizada invocando uma série de métodos
que usam a API MediaCapture para fornecer o fluxo em tempo real da câmera e a capacidade de tirar uma foto,
antes que a página personalizada seja adicionada à coleção Children para exibição.
Ao implementar um renderizador personalizado que deriva de PageRenderer na UWP, o método ArrangeOverride
também deve ser implementado para organizar os controles da página, porque o renderizador de base não sabe o
que fazer com eles. Caso contrário, será gerada uma página em branco. Portanto, neste exemplo, o método
ArrangeOverride chamada o método Arrange na instância de Page .

NOTE
É importante parar e descartar os objetos que fornecem acesso à câmera em um aplicativo da UWP. Deixar de fazer isso
pode interferir em outros aplicativos que tentam acessar a câmera do dispositivo. Para obter mais informações, confira Exibir
a visualização da câmera.

Resumo
Este artigo demonstrou como criar um renderizador personalizado para a página ContentPage , permitindo que os
desenvolvedores substituam a renderização nativa padrão com sua própria personalização específica a uma
plataforma. Um ContentPage é um elemento visual que mostra uma única exibição e ocupa a maior parte da tela.
Links relacionados
CustomRendererContentPage (amostra)
Personalizar um mapa do Xamarin.Forms
12/04/2019 • 2 minutes to read • Edit Online

O Xamarin.Forms.Maps fornece uma abstração multiplataforma para a exibição de mapas que usam as APIs de
mapa nativo em cada plataforma, a fim de fornecer uma experiência de mapa rápida e familiar para os usuários.

Personalizar um Pin de mapa


Este artigo explica como criar um renderizador personalizado para o controle Map , que exibe um mapa nativo
com um marcador personalizado e uma exibição personalizada dos dados de marcador em cada plataforma.

Realçar uma área circular em um mapa


Este artigo explica como adicionar uma sobreposição circular a um mapa a fim de realçar uma área circular nele.

Realçar uma região em um mapa


Este artigo explica como adicionar uma sobreposição poligonal a um mapa a fim de realçar uma determinada
região dele. Polígonos são uma forma fechada e têm seus interiores preenchidos.

Realçar uma rota em um mapa


Este artigo explica como adicionar uma sobreposição de polilinha a um mapa. Uma sobreposição de polilinha é
uma série de segmentos de linha conectados que normalmente são usados para mostrar uma rota em um mapa
ou para formar qualquer forma que seja necessária.
Personalizando um marcador de mapa
12/04/2019 • 38 minutes to read • Edit Online

[![DBaixar a amostra](~/media/shared/download.png) Baixar a amostra]


(https://developer.xamarin.com/samples/xamarin-forms/customrenderers/map/pin/)
Este artigo demonstra como criar um renderizador personalizado para o Controle de Mapeamento, que exibe
um mapa nativo com um marcador personalizado e uma exibição personalizada dos dados de marcador em
cada plataforma.
Cada exibição do Xamarin.Forms tem um renderizador que o acompanha para cada plataforma que cria uma
instância de um controle nativo. Quando um Map é renderizado por um aplicativo Xamarin.Forms no iOS, é
criada uma instância da classe MapRenderer , que, por sua vez, cria uma instância de um controle MKMapView
nativo. Na plataforma Android, a classe MapRenderer cria uma instância de um controle MapView nativo. Na UWP
(Plataforma Universal do Windows), a classe MapRenderer cria uma instância de um MapControl nativo. Para
obter mais informações sobre as classes de renderizador e de controle nativo para as quais os controles do
Xamarin.Forms são mapeadas, confira Classes base do renderizador e controles nativos.
O seguinte diagrama ilustra a relação entre o Map e os controles nativos correspondentes que o implementam:

E possível usar o processo de renderização para implementar personalizações específicas da plataforma criando
um renderizador personalizado para um Map em cada plataforma. O processo para fazer isso é o seguinte:
1. Criar um mapa personalizado do Xamarin.Forms.
2. Consumir o mapa personalizado do Xamarin.Forms.
3. Criar o renderizador personalizado para o mapa em cada plataforma.
Cada item agora será abordado por vez, para implementar um renderizador CustomMap que exibe um mapa
nativo com um marcador personalizado e uma exibição personalizada dos dados do marcador em cada
plataforma.

NOTE
Xamarin.Forms.Maps precisa ser inicializado e configurado antes do uso. Para obter mais informações, consulte
Maps Control .

Criando o mapa personalizado


É possível criar um Controle de Mapeamento personalizado criando subclasses da classe Map , conforme
mostrado no seguinte exemplo de código:

public class CustomMap : Map


{
public List<CustomPin> CustomPins { get; set; }
}

O controle CustomMap é criado no projeto da biblioteca do .NET Standard e define a API para o mapa
personalizado. O mapa personalizado expõe a propriedade CustomPins que representa a coleção de objetos
CustomPin que serão renderizados pelo Controle de Mapeamento nativo em cada plataforma. A classe
CustomPin é mostrada no seguinte exemplo de código:

public class CustomPin : Pin


{
public string Url { get; set; }
}

Essa classe define um CustomPin como herdando as propriedades da classe Pin e adicionando uma propriedade
Url .

Consumindo o mapa personalizado


O controle CustomMap pode ser referenciado em XAML no projeto da biblioteca do .NET Standard declarando um
namespace para sua localização e usando o prefixo do namespace no Controle de Mapeamento personalizado. O
seguinte exemplo de código mostra como o controle CustomMap pode ser consumido por uma página XAML:

<ContentPage ...
xmlns:local="clr-namespace:CustomRenderer;assembly=CustomRenderer">
<ContentPage.Content>
<local:CustomMap x:Name="myMap" MapType="Street"
WidthRequest="{x:Static local:App.ScreenWidth}"
HeightRequest="{x:Static local:App.ScreenHeight}" />
</ContentPage.Content>
</ContentPage>

O prefixo do namespace local pode ter qualquer nome. No entanto, os valores de clr-namespace e assembly
devem corresponder aos detalhes do mapa personalizado. Quando o namespace é declarado, o prefixo é usado
para referenciar o mapa personalizado.
O seguinte exemplo de código mostra como o controle CustomMap pode ser consumido por uma página em C#:

public class MapPageCS : ContentPage


{
public MapPageCS ()
{
var customMap = new CustomMap {
MapType = MapType.Street,
WidthRequest = App.ScreenWidth,
HeightRequest = App.ScreenHeight
};
...

Content = customMap;
}
}
A instância CustomMap será usada para exibir o mapa nativo em cada plataforma. Sua propriedade MapType
define o estilo de exibição do Map , com os valores possíveis sendo definidos na enumeração MapType . Para o iOS
e o Android, a largura e a altura do mapa são definidas por meio das propriedades da classe App são
inicializadas nos projetos específicos da plataforma.
A localização do mapa e os marcadores que ele contém são inicializados conforme mostrado no seguinte
exemplo de código:

public MapPage ()
{
...
var pin = new CustomPin {
Type = PinType.Place,
Position = new Position (37.79752, -122.40183),
Label = "Xamarin San Francisco Office",
Address = "394 Pacific Ave, San Francisco CA",
Id = "Xamarin",
Url = "http://xamarin.com/about/"
};

customMap.CustomPins = new List<CustomPin> { pin };


customMap.Pins.Add (pin);
customMap.MoveToRegion (MapSpan.FromCenterAndRadius (
new Position (37.79752, -122.40183), Distance.FromMiles (1.0)));
}

Essa inicialização adiciona um marcador personalizado e posiciona a exibição do mapa com o método
MoveToRegion , que altera a posição e o nível de aplicação de zoom do mapa com a criação de um MapSpan com
base em uma Position e uma Distance .
Agora, um renderizador personalizado pode ser adicionado a cada projeto de aplicativo para personalizar os
controles de mapa nativos.

Criando o renderizador personalizado em cada plataforma


O processo para criar a classe do renderizador personalizado é o seguinte:
1. Criar uma subclasse da classe MapRenderer que renderiza o mapa personalizado.
2. Substituir o método OnElementChanged que renderiza o mapa personalizado e escrever a lógica para
personalizá-lo. Esse método é chamado quando o mapa personalizado do Xamarin.Forms correspondente é
criado.
3. Adicione um atributo ExportRenderer à classe de renderizador personalizado para especificar que ele será
usado para renderizar o mapa personalizado do Xamarin.Forms. Esse atributo é usado para registrar o
renderizador personalizado no Xamarin.Forms.

NOTE
O fornecimento de um renderizador personalizado em cada projeto da plataforma é opcional. Se um renderizador
personalizado não estiver registrado, será usado o renderizador padrão da classe base do controle.

O seguinte diagrama ilustra as responsabilidades de cada projeto no aplicativo de exemplo, bem como as
relações entre elas:
O controle CustomMap é renderizado por classes de renderizador específicas da plataforma, que derivam da classe
MapRenderer para cada plataforma. Isso faz com que cada controle CustomMap seja renderizado com controles
específicos da plataforma, conforme mostrado nas seguintes capturas de tela:

A classe MapRenderer expõe o método OnElementChanged , que é chamado quando o mapa personalizado do
Xamarin.Forms é criado para renderizar o controle nativo correspondente. Esse método usa um parâmetro
ElementChangedEventArgs , que contém as propriedades OldElement e NewElement . Essas propriedades
representam o elemento do Xamarin.Forms ao qual o renderizador estava anexado e o elemento do
Xamarin.Forms ao qual o renderizador está anexado, respectivamente. No aplicativo de exemplo, a propriedade
OldElement será null e a propriedade NewElement conterá uma referência à instância de CustomMap .

Uma versão de substituição do método OnElementChanged , em cada classe de renderizador específica da


plataforma, é o lugar para realizar a personalização do controle nativo. Uma referência tipada ao controle nativo
que está sendo usado na plataforma pode ser acessada por meio da propriedade Control . Além disso, é possível
obter uma referência ao controle do Xamarin.Forms que está sendo renderizado por meio da propriedade
Element .

É necessário ter cuidado ao assinar manipuladores de eventos no método OnElementChanged , conforme


demonstrado no seguinte exemplo de código:

protected override void OnElementChanged (ElementChangedEventArgs<Xamarin.Forms.ListView> e)


{
base.OnElementChanged (e);

if (e.OldElement != null) {
// Unsubscribe from event handlers
}

if (e.NewElement != null) {
// Configure the native control and subscribe to event handlers
}
}

O controle nativo deverá ser configurado e os manipuladores de eventos deverão ser assinados apenas quando o
renderizador personalizado for anexado a um novo elemento do Xamarin.Forms. De forma semelhante, a
assinatura dos manipuladores de eventos assinados só deverá ser cancelada quando o elemento ao qual o
renderizador está anexado for alterado. A adoção dessa abordagem ajudará a criar um renderizador
personalizado que não sofre perdas de memória.
Cada classe de renderizador personalizado é decorada com um atributo ExportRenderer que registra o
renderizador no Xamarin.Forms. O atributo aceita dois parâmetros – o nome do tipo de controle personalizado
do Xamarin.Forms que está sendo renderizado e o nome do tipo de renderizador personalizado. O prefixo
assembly do atributo especifica que o atributo se aplica a todo o assembly.

As seções a seguir abordam a implementação de cada classe de renderizador personalizado específica da


plataforma.
Criando o renderizador personalizado no iOS
As seguintes capturas de tela mostram o mapa, antes e após a personalização:

No iOS, o marcador é chamado de anotação e pode ser uma imagem personalizada ou um marcador definido
pelo sistema de várias cores. As anotações podem opcionalmente mostrar um texto explicativo, que é exibido em
resposta à seleção da anotação pelo usuário. O texto explicativo exibe o Label e as propriedades Address da
instância Pin , com as exibições acessório direita e esquerda opcionais. Na captura de tela acima, a exibição
acessório esquerda é a imagem de um macaco, com a exibição acessório direita sendo o botão Informações.
O seguinte exemplo de código mostra o renderizador personalizado para a plataforma iOS:
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace CustomRenderer.iOS
{
public class CustomMapRenderer : MapRenderer
{
UIView customPinView;
List<CustomPin> customPins;

protected override void OnElementChanged(ElementChangedEventArgs<View> e)


{
base.OnElementChanged(e);

if (e.OldElement != null) {
var nativeMap = Control as MKMapView;
if (nativeMap != null) {
nativeMap.RemoveAnnotations(nativeMap.Annotations);
nativeMap.GetViewForAnnotation = null;
nativeMap.CalloutAccessoryControlTapped -= OnCalloutAccessoryControlTapped;
nativeMap.DidSelectAnnotationView -= OnDidSelectAnnotationView;
nativeMap.DidDeselectAnnotationView -= OnDidDeselectAnnotationView;
}
}

if (e.NewElement != null) {
var formsMap = (CustomMap)e.NewElement;
var nativeMap = Control as MKMapView;
customPins = formsMap.CustomPins;

nativeMap.GetViewForAnnotation = GetViewForAnnotation;
nativeMap.CalloutAccessoryControlTapped += OnCalloutAccessoryControlTapped;
nativeMap.DidSelectAnnotationView += OnDidSelectAnnotationView;
nativeMap.DidDeselectAnnotationView += OnDidDeselectAnnotationView;
}
}
...
}
}

O método OnElementChanged executa a seguinte configuração da instância MKMapView , desde que o renderizador
personalizado esteja anexado a um novo elemento do Xamarin.Forms:
A propriedade GetViewForAnnotation é definida como o método GetViewForAnnotation . Esse método é
chamado quando a localização da anotação se torna visível no mapa e é usado para personalizar a anotação
antes da exibição.
Os manipuladores de eventos para os eventos CalloutAccessoryControlTapped , DidSelectAnnotationView e
DidDeselectAnnotationView são registrados. Esses eventos são disparados quando o usuário toca o acessório
direito no texto explicativo e quando o usuário marca e desmarca a anotação, respectivamente. A assinatura
dos eventos é cancelada somente quando o elemento ao qual o renderizador está anexado é alterado.
Exibindo a anotação
O método GetViewForAnnotation é chamado quando a localização da anotação se torna visível no mapa e é usado
para personalizar a anotação antes da exibição. Uma anotação tem duas partes:
MkAnnotation – inclui o título, o subtítulo e a localização da anotação.
MkAnnotationView – contém a imagem para representar a anotação e, opcionalmente, um texto explicativo que
é mostrado quando o usuário toca a anotação.
O método GetViewForAnnotation aceita uma IMKAnnotation que contém os dados da anotação e retorna uma
MKAnnotationView para exibição no mapa e é mostrado no seguinte exemplo de código:
protected override MKAnnotationView GetViewForAnnotation(MKMapView mapView, IMKAnnotation annotation)
{
MKAnnotationView annotationView = null;

if (annotation is MKUserLocation)
return null;

var customPin = GetCustomPin(annotation as MKPointAnnotation);


if (customPin == null) {
throw new Exception("Custom pin not found");
}

annotationView = mapView.DequeueReusableAnnotation(customPin.Id.ToString());
if (annotationView == null) {
annotationView = new CustomMKAnnotationView(annotation, customPin.Id.ToString());
annotationView.Image = UIImage.FromFile("pin.png");
annotationView.CalloutOffset = new CGPoint(0, 0);
annotationView.LeftCalloutAccessoryView = new UIImageView(UIImage.FromFile("monkey.png"));
annotationView.RightCalloutAccessoryView = UIButton.FromType(UIButtonType.DetailDisclosure);
((CustomMKAnnotationView)annotationView).Id = customPin.Id.ToString();
((CustomMKAnnotationView)annotationView).Url = customPin.Url;
}
annotationView.CanShowCallout = true;

return annotationView;
}

Esse método garante que a anotação seja exibida como uma imagem personalizada, em vez de como um
marcador definido pelo sistema, e que quando a anotação for tocada, um texto explicativo seja exibido que inclua
conteúdo adicional à esquerda e à direita do título da anotação e do endereço. Isso é feito da seguinte maneira:
1. O método GetCustomPin é chamado para retornar os dados de marcador personalizados da anotação.
2. Para conservar a memória, a exibição da anotação é colocada em pool para reutilização com a chamada a
DequeueReusableAnnotation .
3. A classe CustomMKAnnotationView estende a classe MKAnnotationView com as propriedades Id e Url que
correspondem às propriedades idênticas na instância CustomPin . Uma nova instância da
CustomMKAnnotationView é criada, desde que a anotação seja null :
A propriedade CustomMKAnnotationView.Image está definida como a imagem que representará a
anotação no mapa.
A propriedade CustomMKAnnotationView.CalloutOffset é definida como um CGPoint que especifica que
o texto explicativo será centralizado acima da anotação.
A propriedade CustomMKAnnotationView.LeftCalloutAccessoryView é definida como uma imagem de um
macaco que será exibido à esquerda do título da anotação e do endereço.
A propriedade CustomMKAnnotationView.RightCalloutAccessoryView é definida como um botão
Informações que será exibido à direita do título da anotação e do endereço.
A propriedade CustomMKAnnotationView.Id é definida como a propriedade CustomPin.Id retornada pelo
método GetCustomPin . Isso permite que a anotação seja identificada para que seu texto explicativo
possa ser personalizado ainda mais, se desejado.
A propriedade CustomMKAnnotationView.Url é definida como a propriedade CustomPin.Url retornada
pelo método GetCustomPin . A URL será direcionada quando o usuário tocar o botão exibido na exibição
acessório direita do texto explicativo.
4. A propriedade MKAnnotationView.CanShowCallout é definida como true para que o texto explicativo seja
exibido quando a anotação é tocada.
5. A anotação é retornada para a exibição no mapa.
Selecionando a anotação
Quando o usuário toca a anotação, o evento DidSelectAnnotationView é disparado, que, por sua vez, executa o
método OnDidSelectAnnotationView :

void OnDidSelectAnnotationView (object sender, MKAnnotationViewEventArgs e)


{
var customView = e.View as CustomMKAnnotationView;
customPinView = new UIView ();

if (customView.Id == "Xamarin") {
customPinView.Frame = new CGRect (0, 0, 200, 84);
var image = new UIImageView (new CGRect (0, 0, 200, 84));
image.Image = UIImage.FromFile ("xamarin.png");
customPinView.AddSubview (image);
customPinView.Center = new CGPoint (0, -(e.View.Frame.Height + 75));
e.View.AddSubview (customPinView);
}
}

Esse método estende o texto explicativo existente (que contém as exibições acessório esquerda e direita),
adicionando uma instância UIView a ele que contém uma imagem do logotipo do Xamarin, desde que a anotação
selecionada tenha sua propriedade Id definida como Xamarin . Isso permite cenários em que diferentes textos
explicativos podem ser exibidos para diferentes anotações. A instância UIView será exibida centralizada acima do
texto explicativo existente.
Tocando a exibição acessório direita do texto explicativo
Quando o usuário toca o botão Informações na exibição acessório direita do texto explicativo, o evento
CalloutAccessoryControlTapped é disparado, que, por sua vez, executa o método OnCalloutAccessoryControlTapped :

void OnCalloutAccessoryControlTapped (object sender, MKMapViewAccessoryTappedEventArgs e)


{
var customView = e.View as CustomMKAnnotationView;
if (!string.IsNullOrWhiteSpace (customView.Url)) {
UIApplication.SharedApplication.OpenUrl (new Foundation.NSUrl (customView.Url));
}
}

Esse método abre um navegador da Web e navega para o endereço armazenado na propriedade
CustomMKAnnotationView.Url . Observe que o endereço foi definido durante a criação da coleção CustomPin no
projeto da biblioteca do .NET Standard.
Cancelando a seleção da anotação
Quando a anotação é exibida e o usuário toca o mapa, o evento DidDeselectAnnotationView é disparado, que, por
sua vez, executa o método OnDidDeselectAnnotationView :

void OnDidDeselectAnnotationView (object sender, MKAnnotationViewEventArgs e)


{
if (!e.View.Selected) {
customPinView.RemoveFromSuperview ();
customPinView.Dispose ();
customPinView = null;
}
}

Esse método garante que, quando o texto explicativo existente não estiver selecionado, a parte estendida do texto
explicativo (a imagem do logotipo do Xamarin) também não será mais exibida e seus recursos serão liberados.
Para obter mais informações sobre como personalizar uma instância MKMapView , confira Mapas do iOS.
Criando o renderizador personalizado no Android
As seguintes capturas de tela mostram o mapa, antes e após a personalização:

No Android, o marcador é chamado de marcador e pode ser uma imagem personalizada ou um marcador
definido pelo sistema de várias cores. Os marcadores podem mostrar uma janela de informações, que é exibida
na resposta ao toque do usuário no marcador. A janela de informações exibe as propriedades Label e Address
da instância Pin e pode ser personalizada para incluir outros tipos de conteúdo. No entanto, apenas uma janela
de informações pode ser mostrada por vez.
O seguinte exemplo de código mostra o renderizador personalizado para a plataforma Android:

[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]


namespace CustomRenderer.Droid
{
public class CustomMapRenderer : MapRenderer, GoogleMap.IInfoWindowAdapter
{
List<CustomPin> customPins;

public CustomMapRenderer(Context context) : base(context)


{
}

protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Map>


e)
{
base.OnElementChanged(e);

if (e.OldElement != null)
{
NativeMap.InfoWindowClick -= OnInfoWindowClick;
}

if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
customPins = formsMap.CustomPins;
Control.GetMapAsync(this);
}
}

protected override void OnMapReady(GoogleMap map)


{
base.OnMapReady(map);

NativeMap.InfoWindowClick += OnInfoWindowClick;
NativeMap.SetInfoWindowAdapter(this);
}
...
}
}
Desde que o renderizador personalizado esteja anexado a um novo elemento do Xamarin.Forms, o método
OnElementChanged chamará o método MapView.GetMapAsync , que obterá o GoogleMap subjacente que está
vinculado à exibição. Depois que a instância GoogleMap estiver disponível, a substituição OnMapReady será
invocada. Esse método registra um manipulador de eventos para o evento InfoWindowClick , que é disparado
quando a janela de informações recebe um clique e tem a assinatura cancelada somente quando o elemento ao
qual o renderizador está anexado é alterado. A substituição OnMapReady também chama o método
SetInfoWindowAdapter para especificar que a instância da classe CustomMapRenderer fornecerá os métodos para
personalizar a janela de informações.
A classe CustomMapRenderer implementa a interface GoogleMap.IInfoWindowAdapter para personalizar a janela de
informações. Essa interface especifica que os seguintes métodos precisam ser implementados:
public Android.Views.View GetInfoWindow(Marker marker) – Esse método é chamado para retornar uma janela
de informações personalizada para um marcador. Se ele retornar null , a renderização de janela padrão será
usada. Se ele retornar uma View , essa View será colocada dentro do quadro da janela de informações.
public Android.Views.View GetInfoContents(Marker marker) – Esse método é chamado para retornar uma View
que traz o conteúdo da janela de informações e só é chamado se o método GetInfoWindow retorna null . Se
ele retornar null , a renderização padrão do conteúdo da janela de informações será usada.

No aplicativo de exemplo, somente o conteúdo da janela de informações é personalizado e, portanto, o método


GetInfoWindow retorna null para permitir isso.

Personalizando o marcador
O ícone usado para representar um marcador pode ser personalizado por meio da chamada ao método
MarkerOptions.SetIcon . Isso pode ser feito pela substituição do método CreateMarker , que é invocado para cada
Pin adicionado ao mapa:

protected override MarkerOptions CreateMarker(Pin pin)


{
var marker = new MarkerOptions();
marker.SetPosition(new LatLng(pin.Position.Latitude, pin.Position.Longitude));
marker.SetTitle(pin.Label);
marker.SetSnippet(pin.Address);
marker.SetIcon(BitmapDescriptorFactory.FromResource(Resource.Drawable.pin));
return marker;
}

Esse método cria uma instância MarkerOption para cada instância Pin . Depois de definir a posição, o rótulo e o
endereço do marcador, seu ícone será definido com o método SetIcon . Esse método usa um objeto
BitmapDescriptor que contém os dados necessários para renderizar o ícone, com a classe
BitmapDescriptorFactory fornecendo métodos auxiliares para simplificar a criação do BitmapDescriptor . Para
obter mais informações sobre como usar a classe BitmapDescriptorFactory para personalizar um marcador,
confira Personalizando um marcador.

NOTE
Se necessário, o método GetMarkerForPin pode ser invocado no renderizador de mapa para recuperar um Marker de
um Pin .

Personalizando a janela de informações


Quando um usuário toca o marcador, o método GetInfoContents é executado, desde que o método
GetInfoWindow retorne null . O seguinte exemplo de código mostra o método GetInfoContents :
public Android.Views.View GetInfoContents (Marker marker)
{
var inflater = Android.App.Application.Context.GetSystemService (Context.LayoutInflaterService) as
Android.Views.LayoutInflater;
if (inflater != null) {
Android.Views.View view;

var customPin = GetCustomPin (marker);


if (customPin == null) {
throw new Exception ("Custom pin not found");
}

if (customPin.Id.ToString() == "Xamarin") {
view = inflater.Inflate (Resource.Layout.XamarinMapInfoWindow, null);
} else {
view = inflater.Inflate (Resource.Layout.MapInfoWindow, null);
}

var infoTitle = view.FindViewById<TextView> (Resource.Id.InfoWindowTitle);


var infoSubtitle = view.FindViewById<TextView> (Resource.Id.InfoWindowSubtitle);

if (infoTitle != null) {
infoTitle.Text = marker.Title;
}
if (infoSubtitle != null) {
infoSubtitle.Text = marker.Snippet;
}

return view;
}
return null;
}

Esse método retorna uma View que traz o conteúdo da janela de informações. Isso é feito da seguinte maneira:
Uma instância LayoutInflater é recuperada. Isso é usado para criar uma instância de um arquivo XML de
layout em sua View correspondente.
O método GetCustomPin é chamado para retornar os dados de marcador personalizados para a janela de
informações.
O layout XamarinMapInfoWindow é inflado se a propriedade CustomPin.Id é igual a Xamarin . Caso contrário, o
layout MapInfoWindow é inflado. Isso permite cenários em que diferentes layouts da janela de informações
podem ser exibidos para diferentes marcadores.
Os recursos InfoWindowTitle e InfoWindowSubtitle são recuperados do layout inflado e suas propriedades
Text são definidas com os dados correspondentes por meio da instância Marker , desde que os recursos não
sejam null .
A instância View é retornada para exibição no mapa.

NOTE
Uma janela de informações não é uma View dinâmica. Em vez disso, o Android converterá a View em um bitmap
estático e os exibirá como uma imagem. Isso significa que, embora uma janela de informações possa responder a um
evento de clique, ela não pode responder a eventos de toque ou gestos e os controles individuais na janela de informações
não podem responder a seus próprios eventos de clique.

Clicando na janela de informações


Quando o usuário clica a janela de informações, o evento InfoWindowClick é disparado, que, por sua vez, executa
o método OnInfoWindowClick :
void OnInfoWindowClick (object sender, GoogleMap.InfoWindowClickEventArgs e)
{
var customPin = GetCustomPin (e.Marker);
if (customPin == null) {
throw new Exception ("Custom pin not found");
}

if (!string.IsNullOrWhiteSpace (customPin.Url)) {
var url = Android.Net.Uri.Parse (customPin.Url);
var intent = new Intent (Intent.ActionView, url);
intent.AddFlags (ActivityFlags.NewTask);
Android.App.Application.Context.StartActivity (intent);
}
}

Esse método abre um navegador da Web e navega para o endereço armazenado na propriedade Url da
instância CustomPin recuperada para o Marker . Observe que o endereço foi definido durante a criação da
coleção CustomPin no projeto da biblioteca do .NET Standard.
Para obter mais informações sobre como personalizar uma instância MapView , confira API de Mapas.
Criando o renderizador personalizado na Plataforma Universal do Windows
As seguintes capturas de tela mostram o mapa, antes e após a personalização:

No UWP, o marcador é chamado de ícone de mapa e pode ser uma imagem personalizada ou a imagem padrão
definida pelo sistema. Um ícone de mapa pode mostrar um UserControl , que é exibido em resposta ao toque do
usuário no ícone de mapa. O UserControl pode exibir qualquer conteúdo, incluindo as propriedades Label e
Address da instância Pin .

O seguinte exemplo de código mostra o renderizador personalizado do UWP:


[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace CustomRenderer.UWP
{
public class CustomMapRenderer : MapRenderer
{
MapControl nativeMap;
List<CustomPin> customPins;
XamarinMapOverlay mapOverlay;
bool xamarinOverlayShown = false;

protected override void OnElementChanged(ElementChangedEventArgs<Map> e)


{
base.OnElementChanged(e);

if (e.OldElement != null)
{
nativeMap.MapElementClick -= OnMapElementClick;
nativeMap.Children.Clear();
mapOverlay = null;
nativeMap = null;
}

if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
nativeMap = Control as MapControl;
customPins = formsMap.CustomPins;

nativeMap.Children.Clear();
nativeMap.MapElementClick += OnMapElementClick;

foreach (var pin in customPins)


{
var snPosition = new BasicGeoposition { Latitude = pin.Pin.Position.Latitude, Longitude =
pin.Pin.Position.Longitude };
var snPoint = new Geopoint(snPosition);

var mapIcon = new MapIcon();


mapIcon.Image = RandomAccessStreamReference.CreateFromUri(new Uri("ms-appx:///pin.png"));
mapIcon.CollisionBehaviorDesired = MapElementCollisionBehavior.RemainVisible;
mapIcon.Location = snPoint;
mapIcon.NormalizedAnchorPoint = new Windows.Foundation.Point(0.5, 1.0);

nativeMap.MapElements.Add(mapIcon);
}
}
}
...
}
}

O método OnElementChanged executa as seguintes operações, desde que o renderizador personalizado esteja
anexado a um novo elemento do Xamarin.Forms:
Ele limpa a coleção MapControl.Children para remover os elementos de interface do usuário existentes do
mapa, antes de registrar um manipulador de eventos para o evento MapElementClick . Esse evento é disparado
quando o usuário toca um MapElement ou clica nele no MapControl e tem a assinatura cancelada somente
quando o elemento ao qual o renderizador está anexado é alterado.
Cada marcador da coleção customPins é exibido na localização geográfica correta no mapa da seguinte
maneira:
A localização para o marcador é criado como uma instância Geopoint .
Uma instância MapIcon é criada para representar o marcador.
A imagem usada para representar o MapIcon é especificada definindo a propriedade MapIcon.Image .
No entanto, não há a garantia de que a imagem do ícone de mapa seja sempre mostrada, pois ela pode
ser obscurecida por outros elementos no mapa. Portanto, a propriedade CollisionBehaviorDesired do
ícone de mapa é definida como MapElementCollisionBehavior.RemainVisible , para garantir que ela
permaneça visível.
A localização do MapIcon é especificado definindo a propriedade MapIcon.Location .
A propriedade MapIcon.NormalizedAnchorPoint é definida como a localização aproximada do ponteiro na
imagem. Se essa propriedade retiver seu valor padrão de (0,0), que representa o canto superior
esquerdo da imagem, as alterações no nível de aplicação de zoom do mapa poderão fazer com que a
imagem aponte para uma localização diferente.
A instância MapIcon é adicionada à coleção MapControl.MapElements . Isso resulta na exibição do ícone
de mapa no MapControl .

NOTE
Ao usar a mesma imagem para vários ícones de mapa, a instância RandomAccessStreamReference deve ser declarada no
nível de página ou de aplicativo para melhor desempenho.

Exibindo o UserControl
Quando um usuário toca o ícone de mapa, o método OnMapElementClick é executado. O seguinte exemplo de
código mostra esse método:

private void OnMapElementClick(MapControl sender, MapElementClickEventArgs args)


{
var mapIcon = args.MapElements.FirstOrDefault(x => x is MapIcon) as MapIcon;
if (mapIcon != null)
{
if (!xamarinOverlayShown)
{
var customPin = GetCustomPin(mapIcon.Location.Position);
if (customPin == null)
{
throw new Exception("Custom pin not found");
}

if (customPin.Id.ToString() == "Xamarin")
{
if (mapOverlay == null)
{
mapOverlay = new XamarinMapOverlay(customPin);
}

var snPosition = new BasicGeoposition { Latitude = customPin.Pin.Position.Latitude, Longitude


= customPin.Pin.Position.Longitude };
var snPoint = new Geopoint(snPosition);

nativeMap.Children.Add(mapOverlay);
MapControl.SetLocation(mapOverlay, snPoint);
MapControl.SetNormalizedAnchorPoint(mapOverlay, new Windows.Foundation.Point(0.5, 1.0));
xamarinOverlayShown = true;
}
}
else
{
nativeMap.Children.Remove(mapOverlay);
xamarinOverlayShown = false;
}
}
}
Esse método cria uma instância UserControl que exibe informações sobre o marcador. Isso é feito da seguinte
maneira:
A instância MapIcon é recuperada.
O método GetCustomPin é chamado para retornar os dados de marcador personalizados que serão exibidos.
Uma instância XamarinMapOverlay é criada para exibir os dados de fixação personalizados. Essa classe é um
controle de usuário.
A localização geográfica na qual exibir a instância XamarinMapOverlay no MapControl é criada como uma
instância Geopoint .
A instância XamarinMapOverlay é adicionada à coleção MapControl.Children . Essa coleção contém elementos
de interface do usuário XAML que serão exibidos no mapa.
A localização geográfica da instância XamarinMapOverlay no mapa é definida chamando o método
SetLocation .
A localização relativa na instância XamarinMapOverlay , que corresponde à localização especificada, é definida
chamando o método SetNormalizedAnchorPoint . Isso garante que as alterações no nível de aplicação de zoom
do mapa resultem na exibição constante da instância XamarinMapOverlay na localização correta.

Como alternativa, se as informações sobre o marcador já estiverem sendo exibidas no mapa, o toque no mapa
removerá a instância XamarinMapOverlay da coleção MapControl.Children .
Tocando no botão de informações
Quando o usuário toca o botão Informações no controle de usuário XamarinMapOverlay , o evento Tapped é
disparado, que, por sua vez, executa o método OnInfoButtonTapped :

private async void OnInfoButtonTapped(object sender, TappedRoutedEventArgs e)


{
await Launcher.LaunchUriAsync(new Uri(customPin.Url));
}

Esse método abre um navegador da Web e navega para o endereço armazenado na propriedade Url da
instância CustomPin . Observe que o endereço foi definido durante a criação da coleção CustomPin no projeto da
biblioteca do .NET Standard.
Para obter mais informações sobre como personalizar uma instância MapControl , confira Visão geral de mapas e
localização no MSDN.

Resumo
Este artigo demonstrou como criar um renderizador personalizado para o controle Map , permitindo que os
desenvolvedores substituam a renderização nativa padrão por sua própria personalização específica da
plataforma. O Xamarin.Forms.Maps fornece uma abstração multiplataforma para a exibição de mapas que usam
as APIs de mapa nativo em cada plataforma, a fim de fornecer uma experiência de mapa rápida e familiar para os
usuários.

Links relacionados
Controle de mapas
Mapas do iOS
API de mapas
Marcador personalizado (exemplo)
Realçando uma área circular em um mapa
12/04/2019 • 9 minutes to read • Edit Online

Baixar o exemplo
Este artigo explica como adicionar uma sobreposição circular a um mapa a fim de realçar uma área circular nele.

Visão geral
Uma sobreposição é um gráfico em camadas em um mapa. As sobreposições são suporte para elaborar conteúdos
gráficos que são dimensionados com o mapa conforme ele é ampliado e reduzido. As capturas de tela a seguir
mostram o resultado do acréscimo de uma sobreposição circular a um mapa:

Quando um controle Map é renderizado por um aplicativo Xamarin.Forms, no iOS é criada uma instância da
classe MapRenderer , o que por sua vez cria uma instância de um controle MKMapView nativo. Na plataforma
Android, a classe MapRenderer cria uma instância de um controle MapView nativo. Na UWP (Plataforma Universal
do Windows), a classe MapRenderer cria uma instância de um MapControl nativo. E possível aproveitar o processo
de renderização para implementar personalizações de mapa específicas da plataforma criando um renderizador
personalizado para um Map em cada plataforma. O processo para fazer isso é o seguinte:
1. Criar um mapa personalizado do Xamarin.Forms.
2. Consumir o mapa personalizado do Xamarin.Forms.
3. Personalizar o mapa criando um renderizador personalizado para o mapa em cada plataforma.

NOTE
Xamarin.Forms.Maps precisa ser inicializado e configurado antes do uso. Para obter mais informações, confira
Maps Control

Para obter informações sobre como personalizar um mapa usando um renderizador personalizado, confira
Personalizando um marcador de mapa.
Criando o mapa personalizado
Crie uma classe CustomCircle com as propriedades Position e Radius :
public class CustomCircle
{
public Position Position { get; set; }
public double Radius { get; set; }
}

Em seguida, crie uma subclasse da classe Map , que adiciona uma propriedade do tipo CustomCircle :

public class CustomMap : Map


{
public CustomCircle Circle { get; set; }
}

Consumindo o mapa personalizado


Consuma o controle CustomMap declarando uma instância dele na instância da página XAML:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MapOverlay;assembly=MapOverlay"
x:Class="MapOverlay.MapPage">
<ContentPage.Content>
<local:CustomMap x:Name="customMap" MapType="Street" WidthRequest="{x:Static local:App.ScreenWidth}"
HeightRequest="{x:Static local:App.ScreenHeight}" />
</ContentPage.Content>
</ContentPage>

Como alternativa, consuma o controle CustomMap declarando uma instância dele na instância da página em C#:

public class MapPageCS : ContentPage


{
public MapPageCS ()
{
var customMap = new CustomMap {
MapType = MapType.Street,
WidthRequest = App.ScreenWidth,
HeightRequest = App.ScreenHeight
};
...
Content = customMap;
}
}

Inicialize o controle CustomMap da forma necessária:


public partial class MapPage : ContentPage
{
public MapPage ()
{
...
var pin = new Pin {
Type = PinType.Place,
Position = new Position (37.79752, -122.40183),
Label = "Xamarin San Francisco Office",
Address = "394 Pacific Ave, San Francisco CA"
};

var position = new Position (37.79752, -122.40183);


customMap.Circle = new CustomCircle {
Position = position,
Radius = 1000
};

customMap.Pins.Add (pin);
customMap.MoveToRegion (MapSpan.FromCenterAndRadius (position, Distance.FromMiles (1.0)));
}
}

Essa inicialização adiciona instâncias de Pin e CustomCircle ao mapa personalizado e posiciona a exibição do
mapa com o método MoveToRegion , que altera a posição e o nível de aplicação de zoom do mapa com a criação de
um MapSpan com base em uma Position e uma Distance .
Personalizando o mapa
Agora, é necessário adicionar um renderizador personalizado a cada projeto de aplicativo para adicionar a
sobreposição circular ao mapa.
Criando o renderizador personalizado no iOS
Crie uma subclasse da classe MapRenderer e substitua seu método OnElementChanged para adicionar a
sobreposição circular:
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace MapOverlay.iOS
{
public class CustomMapRenderer : MapRenderer
{
MKCircleRenderer circleRenderer;

protected override void OnElementChanged(ElementChangedEventArgs<View> e)


{
base.OnElementChanged(e);

if (e.OldElement != null) {
var nativeMap = Control as MKMapView;
if (nativeMap != null) {
nativeMap.RemoveOverlays(nativeMap.Overlays);
nativeMap.OverlayRenderer = null;
circleRenderer = null;
}
}

if (e.NewElement != null) {
var formsMap = (CustomMap)e.NewElement;
var nativeMap = Control as MKMapView;
var circle = formsMap.Circle;

nativeMap.OverlayRenderer = GetOverlayRenderer;

var circleOverlay = MKCircle.Circle(new


CoreLocation.CLLocationCoordinate2D(circle.Position.Latitude, circle.Position.Longitude), circle.Radius);
nativeMap.AddOverlay(circleOverlay);
}
}
...
}
}

Esse método executa a seguinte configuração, desde que o renderizador personalizado esteja anexado a um novo
elemento do Xamarin.Forms:
A propriedade MKMapView.OverlayRenderer é definida como um delegado correspondente.
O círculo é criado definindo um objeto MKCircle estático que especifica o centro do círculo e seu raio em
metros.
O círculo é adicionado ao mapa chamando o método MKMapView.AddOverlay .

Em seguida, implemente o método GetOverlayRenderer para personalizar a renderização da sobreposição:


public class CustomMapRenderer : MapRenderer
{
MKCircleRenderer circleRenderer;
...

MKOverlayRenderer GetOverlayRenderer(MKMapView mapView, IMKOverlay overlayWrapper)


{
if (circleRenderer == null && !Equals(overlayWrapper, null)) {
var overlay = Runtime.GetNSObject(overlayWrapper.Handle) as IMKOverlay;
circleRenderer = new MKCircleRenderer(overlay as MKCircle) {
FillColor = UIColor.Red,
Alpha = 0.4f
};
}
return circleRenderer;
}
}

Criando o renderizador personalizado no Android


Crie uma subclasse da classe MapRenderer e substitua seus métodos OnElementChanged e OnMapReady para
adicionar a sobreposição circular:
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace MapOverlay.Droid
{
public class CustomMapRenderer : MapRenderer
{
CustomCircle circle;

public CustomMapRenderer(Context context) : base(context)


{
}

protected override void


OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Xamarin.Forms.Maps.Map> e)
{
base.OnElementChanged(e);

if (e.OldElement != null)
{
// Unsubscribe
}

if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
circle = formsMap.Circle;
Control.GetMapAsync(this);
}
}

protected override void OnMapReady(Android.Gms.Maps.GoogleMap map)


{
base.OnMapReady(map);

var circleOptions = new CircleOptions();


circleOptions.InvokeCenter(new LatLng(circle.Position.Latitude, circle.Position.Longitude));
circleOptions.InvokeRadius(circle.Radius);
circleOptions.InvokeFillColor(0X66FF0000);
circleOptions.InvokeStrokeColor(0X66FF0000);
circleOptions.InvokeStrokeWidth(0);

NativeMap.AddCircle(circleOptions);
}
}
}

O método OnElementChanged chamará o método MapView.GetMapAsync , que obterá o GoogleMap subjacente que
está vinculado à exibição, desde que o renderizador personalizado esteja anexado a um novo elemento do
Xamarin.Forms. Quando a instância de GoogleMap estiver disponível, o método OnMapReady será invocado e o
círculo será criado instanciando um objeto CircleOptions que especifica o centro do círculo e seu raio em metros.
Em seguida, o círculo é adicionado ao mapa chamando o método NativeMap.AddCircle .
Criando o renderizador personalizado na Plataforma Universal do Windows
Crie uma subclasse da classe MapRenderer e substitua seu método OnElementChanged para adicionar a
sobreposição circular:
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace MapOverlay.UWP
{
public class CustomMapRenderer : MapRenderer
{
const int EarthRadiusInMeteres = 6371000;

protected override void OnElementChanged(ElementChangedEventArgs<Map> e)


{
base.OnElementChanged(e);

if (e.OldElement != null)
{
// Unsubscribe
}
if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
var nativeMap = Control as MapControl;
var circle = formsMap.Circle;

var coordinates = new List<BasicGeoposition>();


var positions = GenerateCircleCoordinates(circle.Position, circle.Radius);
foreach (var position in positions)
{
coordinates.Add(new BasicGeoposition { Latitude = position.Latitude, Longitude =
position.Longitude });
}

var polygon = new MapPolygon();


polygon.FillColor = Windows.UI.Color.FromArgb(128, 255, 0, 0);
polygon.StrokeColor = Windows.UI.Color.FromArgb(128, 255, 0, 0);
polygon.StrokeThickness = 5;
polygon.Path = new Geopath(coordinates);
nativeMap.MapElements.Add(polygon);
}
}
// GenerateCircleCoordinates helper method (below)
}
}

Esse método executa as seguintes operações, desde que o renderizador personalizado esteja anexado a um novo
elemento do Xamarin.Forms:
A posição e o raio do círculo são recuperados da propriedade CustomMap.Circle e passados para o método
GenerateCircleCoordinates , que gera coordenadas de latitude e longitude para o perímetro do círculo. O código
desse método auxiliar é mostrado abaixo.
As coordenadas de perímetro do círculo são convertidas em um List de coordenadas BasicGeoposition .
O círculo é criado instanciando um objeto MapPolygon . A classe MapPolygon é usada para exibir uma forma de
vários pontos no mapa, definindo sua propriedade Path como um objeto Geopath que contém as
coordenadas da forma.
O polígono é renderizado no mapa adicionando-o à coleção MapControl.MapElements .
List<Position> GenerateCircleCoordinates(Position position, double radius)
{
double latitude = position.Latitude.ToRadians();
double longitude = position.Longitude.ToRadians();
double distance = radius / EarthRadiusInMeteres;
var positions = new List<Position>();

for (int angle = 0; angle <=360; angle++)


{
double angleInRadians = ((double)angle).ToRadians();
double latitudeInRadians = Math.Asin(Math.Sin(latitude) * Math.Cos(distance) + Math.Cos(latitude) *
Math.Sin(distance) * Math.Cos(angleInRadians));
double longitudeInRadians = longitude + Math.Atan2(Math.Sin(angleInRadians) * Math.Sin(distance) *
Math.Cos(latitude), Math.Cos(distance) - Math.Sin(latitude) * Math.Sin(latitudeInRadians));

var pos = new Position(latitudeInRadians.ToDegrees(), longitudeInRadians.ToDegrees());


positions.Add(pos);
}

return positions;
}

Resumo
Este artigo explicou como adicionar uma sobreposição circular a um mapa a fim de realçar uma área circular nele.

Links relacionados
Sobreposição de mapa circular (amostra)
Personalizar um Pin de mapa
Xamarin.Forms.Maps
Realçando uma região em um mapa
12/04/2019 • 10 minutes to read • Edit Online

Baixar o exemplo
Este artigo explicou como adicionar uma sobreposição poligonal a um mapa a fim de realçar uma determinada
região. Polígonos são uma forma fechada e têm seus interiores preenchidos.

Visão geral
Uma sobreposição é um gráfico em camadas em um mapa. As sobreposições são suporte para elaborar conteúdos
gráficos que são dimensionados com o mapa conforme ele é ampliado e reduzido. As capturas de tela a seguir
mostram o resultado do acréscimo de uma sobreposição de polígono a um mapa:

Quando um controle Map é renderizado por um aplicativo Xamarin.Forms, no iOS é criada uma instância da
classe MapRenderer , o que por sua vez cria uma instância de um controle MKMapView nativo. Na plataforma
Android, a classe MapRenderer cria uma instância de um controle MapView nativo. Na UWP (Plataforma Universal
do Windows), a classe MapRenderer cria uma instância de um MapControl nativo. E possível aproveitar o processo
de renderização para implementar personalizações de mapa específicas da plataforma criando um renderizador
personalizado para um Map em cada plataforma. O processo para fazer isso é o seguinte:
1. Criar um mapa personalizado do Xamarin.Forms.
2. Consumir o mapa personalizado do Xamarin.Forms.
3. Personalizar o mapa criando um renderizador personalizado para o mapa em cada plataforma.

NOTE
Xamarin.Forms.Maps precisa ser inicializado e configurado antes do uso. Para obter mais informações, consulte
Maps Control .

Para obter informações sobre como personalizar um mapa usando um renderizador personalizado, confira
Personalizando um marcador de mapa.
Criando o mapa personalizado
Crie uma subclasse da classe Map , que adiciona uma propriedade ShapeCoordinates :

public class CustomMap : Map


{
public List<Position> ShapeCoordinates { get; set; }

public CustomMap ()
{
ShapeCoordinates = new List<Position> ();
}
}

A propriedade ShapeCoordinates armazenará uma coleção de coordenadas que definem a região a ser realçada.
Consumindo o mapa personalizado
Consuma o controle CustomMap declarando uma instância dele na instância da página XAML:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MapOverlay;assembly=MapOverlay"
x:Class="MapOverlay.MapPage">
<ContentPage.Content>
<local:CustomMap x:Name="customMap" MapType="Street" WidthRequest="{x:Static local:App.ScreenWidth}"
HeightRequest="{x:Static local:App.ScreenHeight}" />
</ContentPage.Content>
</ContentPage>

Como alternativa, consuma o controle CustomMap declarando uma instância dele na instância da página em C#:

public class MapPageCS : ContentPage


{
public MapPageCS ()
{
var customMap = new CustomMap {
MapType = MapType.Street,
WidthRequest = App.ScreenWidth,
HeightRequest = App.ScreenHeight
};
...
Content = customMap;
}
}

Inicialize o controle CustomMap da forma necessária:

public partial class MapPage : ContentPage


{
public MapPage ()
{
...
customMap.ShapeCoordinates.Add (new Position (37.797513, -122.402058));
customMap.ShapeCoordinates.Add (new Position (37.798433, -122.402256));
customMap.ShapeCoordinates.Add (new Position (37.798582, -122.401071));
customMap.ShapeCoordinates.Add (new Position (37.797658, -122.400888));

customMap.MoveToRegion (MapSpan.FromCenterAndRadius (new Position (37.79752, -122.40183),


Distance.FromMiles (0.1)));
}
}
Essa inicialização especifica uma série de coordenadas de latitude e longitude para definir a região do mapa a ser
realçada. Em seguida, ela posiciona a exibição do mapa com o método MoveToRegion , que altera a posição e o nível
de zoom do mapa criando um MapSpan de um Position e um Distance .
Personalizando o mapa
Agora, é necessário adicionar um renderizador personalizado a cada projeto de aplicativo para adicionar a
sobreposição de polígono ao mapa.
Criando o renderizador personalizado no iOS
Crie uma subclasse da classe MapRenderer e substitua seu método OnElementChanged para adicionar a
sobreposição de polígono:

[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]


namespace MapOverlay.iOS
{
public class CustomMapRenderer : MapRenderer
{
MKPolygonRenderer polygonRenderer;

protected override void OnElementChanged(ElementChangedEventArgs<View> e)


{
base.OnElementChanged(e);

if (e.OldElement != null) {
var nativeMap = Control as MKMapView;
if (nativeMap != null) {
nativeMap.RemoveOverlays(nativeMap.Overlays);
nativeMap.OverlayRenderer = null;
polygonRenderer = null;
}
}

if (e.NewElement != null) {
var formsMap = (CustomMap)e.NewElement;
var nativeMap = Control as MKMapView;

nativeMap.OverlayRenderer = GetOverlayRenderer;

CLLocationCoordinate2D[] coords = new CLLocationCoordinate2D[formsMap.ShapeCoordinates.Count];

int index = 0;
foreach (var position in formsMap.ShapeCoordinates)
{
coords[index] = new CLLocationCoordinate2D(position.Latitude, position.Longitude);
index++;
}

var blockOverlay = MKPolygon.FromCoordinates(coords);


nativeMap.AddOverlay(blockOverlay);
}
}
...
}
}

Esse método executa a seguinte configuração, desde que o renderizador personalizado esteja anexado a um novo
elemento do Xamarin.Forms:
A propriedade MKMapView.OverlayRenderer é definida como um delegado correspondente.
A coleção de coordenadas de latitude e longitude é recuperada da propriedade CustomMap.ShapeCoordinates e
armazenada como uma matriz de instâncias de CLLocationCoordinate2D .
O polígono é criado chamando o método MKPolygon.FromCoordinates estático, que especifica a latitude e a
longitude de cada ponto.
O polígono é adicionado ao mapa chamando o método MKMapView.AddOverlay . Esse método fecha
automaticamente o polígono desenhando uma linha que conecta o primeiro e último pontos.
Em seguida, implemente o método GetOverlayRenderer para personalizar a renderização da sobreposição:

public class CustomMapRenderer : MapRenderer


{
MKPolygonRenderer polygonRenderer;
...

MKOverlayRenderer GetOverlayRenderer(MKMapView mapView, IMKOverlay overlayWrapper)


{
if (polygonRenderer == null && !Equals(overlayWrapper, null)) {
var overlay = Runtime.GetNSObject(overlayWrapper.Handle) as IMKOverlay;
polygonRenderer = new MKPolygonRenderer(overlay as MKPolygon) {
FillColor = UIColor.Red,
StrokeColor = UIColor.Blue,
Alpha = 0.4f,
LineWidth = 9
};
}
return polygonRenderer;
}
}

Criando o renderizador personalizado no Android


Crie uma subclasse da classe MapRenderer e substitua seus métodos OnElementChanged e OnMapReady para
adicionar a sobreposição de polígono:
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace MapOverlay.Droid
{
public class CustomMapRenderer : MapRenderer
{
List<Position> shapeCoordinates;

public CustomMapRenderer(Context context) : base(context)


{
}

protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Map>


e)
{
base.OnElementChanged(e);

if (e.OldElement != null)
{
// Unsubscribe
}

if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
shapeCoordinates = formsMap.ShapeCoordinates;
Control.GetMapAsync(this);
}
}

protected override void OnMapReady(Android.Gms.Maps.GoogleMap map)


{
base.OnMapReady(map);

var polygonOptions = new PolygonOptions();


polygonOptions.InvokeFillColor(0x66FF0000);
polygonOptions.InvokeStrokeColor(0x660000FF);
polygonOptions.InvokeStrokeWidth(30.0f);

foreach (var position in shapeCoordinates)


{
polygonOptions.Add(new LatLng(position.Latitude, position.Longitude));
}
NativeMap.AddPolygon(polygonOptions);
}
}
}

O método OnElementChanged recupera a coleção de coordenadas de latitude e longitude da propriedade


CustomMap.ShapeCoordinates e a armazena em uma variável de membro. Em seguida, ele chama o método
MapView.GetMapAsync , que obtém o GoogleMap subjacente que está vinculado à exibição, desde que o renderizador
personalizado esteja anexado a um novo elemento do Xamarin.Forms. Quando a instância de GoogleMap estiver
disponível, o método OnMapReady será invocado e o polígono será criado instanciando um objeto PolygonOptions
que especifica a latitude e a longitude de cada ponto. Em seguida, o polígono será adicionado ao mapa chamando
o método NativeMap.AddPolygon . Esse método fecha automaticamente o polígono desenhando uma linha que
conecta o primeiro e último pontos.
Criando o renderizador personalizado na Plataforma Universal do Windows
Crie uma subclasse da classe MapRenderer e substitua seu método OnElementChanged para adicionar a
sobreposição de polígono:
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace MapOverlay.UWP
{
public class CustomMapRenderer : MapRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Map> e)
{
base.OnElementChanged(e);

if (e.OldElement != null)
{
// Unsubscribe
}

if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
var nativeMap = Control as MapControl;

var coordinates = new List<BasicGeoposition>();


foreach (var position in formsMap.ShapeCoordinates)
{
coordinates.Add(new BasicGeoposition() { Latitude = position.Latitude, Longitude =
position.Longitude });
}

var polygon = new MapPolygon();


polygon.FillColor = Windows.UI.Color.FromArgb(128, 255, 0, 0);
polygon.StrokeColor = Windows.UI.Color.FromArgb(128, 0, 0, 255);
polygon.StrokeThickness = 5;
polygon.Path = new Geopath(coordinates);
nativeMap.MapElements.Add(polygon);
}
}
}
}

Esse método executa as seguintes operações, desde que o renderizador personalizado esteja anexado a um novo
elemento do Xamarin.Forms:
A coleção de coordenadas de latitude e longitude é recuperada da propriedade CustomMap.ShapeCoordinates e
convertida em uma List de coordenadas BasicGeoposition .
O polígono é criado instanciando um objeto MapPolygon . A classe MapPolygon é usada para exibir uma forma
de vários pontos no mapa, definindo sua propriedade Path como um objeto Geopath que contém as
coordenadas da forma.
O polígono é renderizado no mapa adicionando-o à coleção MapControl.MapElements . Observe que o polígono
será fechado automaticamente desenhando uma linha que conecta o primeiro e último pontos.

Resumo
Este artigo explicou como adicionar uma sobreposição poligonal a um mapa a fim de realçar uma determinada
região. Polígonos são uma forma fechada e têm seus interiores preenchidos.

Links relacionados
Sobreposição de mapa com polígono (amostra)
Personalizar um Pin de mapa
Xamarin.Forms.Maps
Realçando uma rota em um mapa
12/04/2019 • 9 minutes to read • Edit Online

Baixar o exemplo
Este artigo explica como adicionar uma sobreposição de polilinha a um mapa. Uma sobreposição de polilinha é
uma série de segmentos de linha conectados que normalmente são usados para mostrar uma rota em um mapa
ou para formar qualquer forma que seja necessária.

Visão geral
Uma sobreposição é um gráfico em camadas em um mapa. As sobreposições são suporte para elaborar conteúdos
gráficos que são dimensionados com o mapa conforme ele é ampliado e reduzido. As capturas de tela a seguir
mostram o resultado do acréscimo de uma sobreposição de polilinha a um mapa:

Quando um controle Map é renderizado por um aplicativo Xamarin.Forms, no iOS é criada uma instância da
classe MapRenderer , o que por sua vez cria uma instância de um controle MKMapView nativo. Na plataforma
Android, a classe MapRenderer cria uma instância de um controle MapView nativo. Na UWP (Plataforma Universal
do Windows), a classe MapRenderer cria uma instância de um MapControl nativo. E possível aproveitar o processo
de renderização para implementar personalizações de mapa específicas da plataforma criando um renderizador
personalizado para um Map em cada plataforma. O processo para fazer isso é o seguinte:
1. Criar um mapa personalizado do Xamarin.Forms.
2. Consumir o mapa personalizado do Xamarin.Forms.
3. Personalizar o mapa criando um renderizador personalizado para o mapa em cada plataforma.

NOTE
Xamarin.Forms.Maps precisa ser inicializado e configurado antes do uso. Para obter mais informações, consulte
Maps Control .

Para obter informações sobre como personalizar um mapa usando um renderizador personalizado, confira
Personalizando um marcador de mapa.
Criando o mapa personalizado
Crie uma subclasse da classe Map , que adiciona uma propriedade RouteCoordinates :

public class CustomMap : Map


{
public List<Position> RouteCoordinates { get; set; }

public CustomMap ()
{
RouteCoordinates = new List<Position> ();
}
}

A propriedade RouteCoordinates armazenará uma coleção de coordenadas que definem a rota a ser realçada.
Consumindo o mapa personalizado
Consuma o controle CustomMap declarando uma instância dele na instância da página XAML:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MapOverlay;assembly=MapOverlay"
x:Class="MapOverlay.MapPage">
<ContentPage.Content>
<local:CustomMap x:Name="customMap" MapType="Street" WidthRequest="{x:Static local:App.ScreenWidth}"
HeightRequest="{x:Static local:App.ScreenHeight}" />
</ContentPage.Content>
</ContentPage>

Como alternativa, consuma o controle CustomMap declarando uma instância dele na instância da página em C#:

public class MapPageCS : ContentPage


{
public MapPageCS ()
{
var customMap = new CustomMap {
MapType = MapType.Street,
WidthRequest = App.ScreenWidth,
HeightRequest = App.ScreenHeight
};
...
Content = customMap;
}
}

Inicialize o controle CustomMap da forma necessária:

public partial class MapPage : ContentPage


{
public MapPage ()
{
...
customMap.RouteCoordinates.Add (new Position (37.785559, -122.396728));
customMap.RouteCoordinates.Add (new Position (37.780624, -122.390541));
customMap.RouteCoordinates.Add (new Position (37.777113, -122.394983));
customMap.RouteCoordinates.Add (new Position (37.776831, -122.394627));

customMap.MoveToRegion (MapSpan.FromCenterAndRadius (new Position (37.79752, -122.40183),


Distance.FromMiles (1.0)));
}
}
Essa inicialização especifica uma série de coordenadas de latitude e longitude para definir a rota do mapa a ser
realçada. Em seguida, ela posiciona a exibição do mapa com o método MoveToRegion , que altera a posição e o nível
de aplicação de zoom do mapa criando um MapSpan de um Position e um Distance .
Personalizando o mapa
Agora, é necessário adicionar um renderizador personalizado a cada projeto de aplicativo para adicionar a
sobreposição de polilinha ao mapa.
Criando o renderizador personalizado no iOS
Crie uma subclasse da classe MapRenderer e substitua seu método OnElementChanged para adicionar a
sobreposição de polilinha:

[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]


namespace MapOverlay.iOS
{
public class CustomMapRenderer : MapRenderer
{
MKPolylineRenderer polylineRenderer;

protected override void OnElementChanged(ElementChangedEventArgs<View> e)


{
base.OnElementChanged(e);

if (e.OldElement != null) {
var nativeMap = Control as MKMapView;
if (nativeMap != null) {
nativeMap.RemoveOverlays(nativeMap.Overlays);
nativeMap.OverlayRenderer = null;
polylineRenderer = null;
}
}

if (e.NewElement != null) {
var formsMap = (CustomMap)e.NewElement;
var nativeMap = Control as MKMapView;
nativeMap.OverlayRenderer = GetOverlayRenderer;

CLLocationCoordinate2D[] coords = new CLLocationCoordinate2D[formsMap.RouteCoordinates.Count];


int index = 0;
foreach (var position in formsMap.RouteCoordinates)
{
coords[index] = new CLLocationCoordinate2D(position.Latitude, position.Longitude);
index++;
}

var routeOverlay = MKPolyline.FromCoordinates(coords);


nativeMap.AddOverlay(routeOverlay);
}
}
...
}
}

Esse método executa a seguinte configuração, desde que o renderizador personalizado esteja anexado a um novo
elemento do Xamarin.Forms:
A propriedade MKMapView.OverlayRenderer é definida como um delegado correspondente.
A coleção de coordenadas de latitude e longitude é recuperada da propriedade CustomMap.RouteCoordinates e
armazenada como uma matriz de instâncias de CLLocationCoordinate2D .
A polilinha é criada chamando o método MKPolyline.FromCoordinates estático, que especifica a latitude e a
longitude de cada ponto.
A polilinha é adicionada ao mapa chamando o método MKMapView.AddOverlay .

Em seguida, implemente o método GetOverlayRenderer para personalizar a renderização da sobreposição:

public class CustomMapRenderer : MapRenderer


{
MKPolylineRenderer polylineRenderer;
...

MKOverlayRenderer GetOverlayRenderer(MKMapView mapView, IMKOverlay overlayWrapper)


{
if (polylineRenderer == null && !Equals(overlayWrapper, null)) {
var overlay = Runtime.GetNSObject(overlayWrapper.Handle) as IMKOverlay;
polylineRenderer = new MKPolylineRenderer(overlay as MKPolyline) {
FillColor = UIColor.Blue,
StrokeColor = UIColor.Red,
LineWidth = 3,
Alpha = 0.4f
};
}
return polylineRenderer;
}
}

Criando o renderizador personalizado no Android


Crie uma subclasse da classe MapRenderer e substitua seus métodos OnElementChanged e OnMapReady para
adicionar a sobreposição de polilinha:
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace MapOverlay.Droid
{
public class CustomMapRenderer : MapRenderer
{
List<Position> routeCoordinates;

public CustomMapRenderer(Context context) : base(context)


{
}

protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Map>


e)
{
base.OnElementChanged(e);

if (e.OldElement != null)
{
// Unsubscribe
}

if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
routeCoordinates = formsMap.RouteCoordinates;
Control.GetMapAsync(this);
}
}

protected override void OnMapReady(Android.Gms.Maps.GoogleMap map)


{
base.OnMapReady(map);

var polylineOptions = new PolylineOptions();


polylineOptions.InvokeColor(0x66FF0000);

foreach (var position in routeCoordinates)


{
polylineOptions.Add(new LatLng(position.Latitude, position.Longitude));
}

NativeMap.AddPolyline(polylineOptions);
}
}
}

O método OnElementChanged recupera a coleção de coordenadas de latitude e longitude da propriedade


CustomMap.RouteCoordinates e a armazena em uma variável de membro. Em seguida, ele chama o método
MapView.GetMapAsync , que obtém o GoogleMap subjacente que está vinculado à exibição, desde que o renderizador
personalizado esteja anexado a um novo elemento do Xamarin.Forms. Quando a instância de GoogleMap estiver
disponível, o método OnMapReady será invocado e a polilinha será criada instanciando um objeto PolylineOptions
que especifica a latitude e a longitude de cada ponto. Em seguida, a polilinha é adicionada ao mapa chamando o
método NativeMap.AddPolyline .
Criando o renderizador personalizado na Plataforma Universal do Windows
Crie uma subclasse da classe MapRenderer e substitua seu método OnElementChanged para adicionar a
sobreposição de polilinha:
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace MapOverlay.UWP
{
public class CustomMapRenderer : MapRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Map> e)
{
base.OnElementChanged(e);

if (e.OldElement != null)
{
// Unsubscribe
}

if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
var nativeMap = Control as MapControl;

var coordinates = new List<BasicGeoposition>();


foreach (var position in formsMap.RouteCoordinates)
{
coordinates.Add(new BasicGeoposition() { Latitude = position.Latitude, Longitude =
position.Longitude });
}

var polyline = new MapPolyline();


polyline.StrokeColor = Windows.UI.Color.FromArgb(128, 255, 0, 0);
polyline.StrokeThickness = 5;
polyline.Path = new Geopath(coordinates);
nativeMap.MapElements.Add(polyline);
}
}
}
}

Esse método executa as seguintes operações, desde que o renderizador personalizado esteja anexado a um novo
elemento do Xamarin.Forms:
A coleção de coordenadas de latitude e longitude é recuperada da propriedade CustomMap.RouteCoordinates e
convertida em uma List de coordenadas BasicGeoposition .
A polilinha é criada instanciando um objeto MapPolyline . A classe MapPolygon é usada para exibir uma linha no
mapa, definindo sua propriedade Path como um objeto Geopath que contém as coordenadas da linha.
A polilinha é renderizada no mapa adicionando-a à coleção MapControl.MapElements .

Resumo
Este artigo explicou como adicionar uma sobreposição de polilinha a um mapa, a fim de mostrar uma rota em um
mapa ou de criar qualquer forma necessária.

Links relacionados
Sobreposição de mapa de polilinha (amostra)
Personalizar um Pin de mapa
Xamarin.Forms.Maps
Personalizando uma ListView
12/04/2019 • 28 minutes to read • Edit Online

Baixar o exemplo
Uma ListView do Xamarin.Forms é uma exibição que mostra uma coleção de dados como uma lista vertical. Este
artigo demonstra como criar um renderizador personalizado que encapsula os controles de lista e layouts de
célula nativa específicos a uma plataforma, permitindo mais controle sobre o desempenho do controle de lista
nativo.
Cada exibição do Xamarin.Forms tem um renderizador que o acompanha para cada plataforma que cria uma
instância de um controle nativo. Quando um ListView é renderizado por um aplicativo Xamarin.Forms, no iOS é
criada uma instância da classe ListViewRenderer , o que por sua vez cria uma instância de um controle
UITableView nativo. Na plataforma Android, a classe ListViewRenderer cria uma instância de um controle
ListView nativo. Na UWP ( Plataforma Universal do Windows), a classe ListViewRenderer cria uma instância de
um controle ListView nativo. Para obter mais informações sobre as classes de renderizador e de controle nativo
para as quais os controles do Xamarin.Forms são mapeadas, confira Classes base do renderizador e controles
nativos.
O diagrama a seguir ilustra a relação entre o controle ListView e os controles nativos correspondentes que o
implementam:

E possível aproveitar o processo de renderização para implementar personalizações específicas da plataforma


criando um renderizador personalizado para um ListView em cada plataforma. O processo para fazer isso é o
seguinte:
1. Criar um controle personalizado do Xamarin.Forms.
2. Consumir o controle personalizado do Xamarin.Forms.
3. Criar o renderizador personalizado para o controle em cada plataforma.
Agora, cada item será abordado separadamente, a fim de implementar um renderizador de NativeListView que
tira proveito dos layouts de célula nativos e dos controles de lista específicos da plataforma. Esse cenário é útil ao
portar um aplicativo nativo existente que contém código de lista e de célula pode ser reutilizado. Além disso, ele
permite a personalização detalhada de recursos de controle de lista que podem afetar o desempenho, como a
virtualização de dados.

Criando o controle ListView personalizado


É possível criar um controle ListView personalizado criando subclasses da classe ListView , conforme mostrado
no exemplo de código a seguir:

public class NativeListView : ListView


{
public static readonly BindableProperty ItemsProperty =
BindableProperty.Create ("Items", typeof(IEnumerable<DataSource>), typeof(NativeListView), new
List<DataSource> ());

public IEnumerable<DataSource> Items {


get { return (IEnumerable<DataSource>)GetValue (ItemsProperty); }
set { SetValue (ItemsProperty, value); }
}

public event EventHandler<SelectedItemChangedEventArgs> ItemSelected;

public void NotifyItemSelected (object item)


{
if (ItemSelected != null) {
ItemSelected (this, new SelectedItemChangedEventArgs (item));
}
}
}

A NativeListView é criada no projeto da biblioteca .NET Standard e define a API para o controle personalizado.
Esse controle expõe uma propriedade Items que é usada para popular o ListView com os dados e que pode ser
associada a dados para fins de exibição. Ele também expõe um evento ItemSelected que será disparado sempre
que um item for selecionado em um controle de lista nativo específico da plataforma. Para obter mais informações
sobre vinculação de dados, veja Noções básicas de vinculação de dados.

Consumindo o controle personalizado


O controle personalizado NativeListView pode ser referenciado em XAML no projeto da biblioteca .NET
Standard declarando um namespace para sua localização e usando o prefixo do namespace no controle. O
exemplo de código a seguir mostra como o controle personalizado NativeListView pode ser consumido por uma
página XAML:

<ContentPage ...
xmlns:local="clr-namespace:CustomRenderer;assembly=CustomRenderer"
...>
...
<ContentPage.Content>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label Text="{x:Static local:App.Description}" HorizontalTextAlignment="Center" />
<local:NativeListView Grid.Row="1" x:Name="nativeListView" ItemSelected="OnItemSelected"
VerticalOptions="FillAndExpand" />
</Grid>
</ContentPage.Content>
</ContentPage>

O prefixo do namespace local pode ser qualquer nome. No entanto, os valores de clr-namespace e assembly
devem corresponder aos detalhes do controle personalizado. Quando o namespace é declarado, o prefixo é usado
para referenciar o controle personalizado.
O seguinte exemplo de código mostra como o controle personalizado NativeListView pode ser consumido por
um página em C#:
public class MainPageCS : ContentPage
{
NativeListView nativeListView;

public MainPageCS()
{
nativeListView = new NativeListView
{
Items = DataSource.GetList(),
VerticalOptions = LayoutOptions.FillAndExpand
};

switch (Device.RuntimePlatform)
{
case Device.iOS:
Padding = new Thickness(0, 20, 0, 0);
break;
case Device.Android:
case Device.UWP:
Padding = new Thickness(0);
break;
}

Content = new Grid


{
RowDefinitions = {
new RowDefinition { Height = GridLength.Auto },
new RowDefinition { Height = new GridLength (1, GridUnitType.Star) }
},
Children = {
new Label { Text = App.Description, HorizontalTextAlignment = TextAlignment.Center },
nativeListView
}
};
nativeListView.ItemSelected += OnItemSelected;
}
...
}

O controle personalizado NativeListView usa renderizadores personalizados específicos da plataforma para exibir
uma lista de dados, que são populados por meio da propriedade Items . Cada linha na lista contém três itens de
dados – um nome, uma categoria e um nome de arquivo de imagem. O layout de cada linha na lista é definido
pelo renderizador personalizado específico da plataforma.

NOTE
Como o controle personalizado NativeListView será renderizado usando controles de lista específicos da plataforma que
incluem a capacidade de rolagem, ele não deve ser colocado em controles de layout roláveis, como ScrollView .

Agora, é possível adicionar um renderizador personalizado a cada projeto de aplicativo para criar layouts de célula
nativa e controles de lista específicos da plataforma.

Criando o renderizador personalizado em cada plataforma


O processo para criar a classe do renderizador personalizado é o seguinte:
1. Crie uma subclasse da classe ListViewRenderer que renderiza o controle personalizado.
2. Substitua o método OnElementChanged que renderiza o controle personalizado e escreva a lógica para
personalizá-lo. Esse método é chamado quando o ListView do Xamarin.Forms correspondente é criado.
3. Adicione um atributo ExportRenderer à classe do renderizador personalizado para especificar que ele será
usado para renderizar o controle personalizado do Xamarin.Forms. Este atributo é usado para registrar o
renderizador personalizado no Xamarin.Forms.

NOTE
O fornecimento de um renderizador personalizado em cada projeto de plataforma é opcional. Se um renderizador
personalizado não estiver registrado, será usado o renderizador padrão da classe base da célula.

O diagrama a seguir ilustra as responsabilidades de cada projeto no aplicativo de exemplo, bem como as relações
entre elas:

O controle personalizado NativeListView é renderizado por classes de renderizador específicas da plataforma,


que derivam da classe ListViewRenderer para cada plataforma. Isso faz com que cada controle personalizado
NativeListView seja renderizado com controles de lista específicos da plataforma e layouts de célula nativos,
conforme mostrado nas capturas de tela seguir:

A classe ListViewRenderer expõe o método OnElementChanged , que é chamado quando um controle personalizado
do Xamarin.Forms é criado para renderizar o controle nativo correspondente. Esse método usa um parâmetro
ElementChangedEventArgs , que contém as propriedades OldElement e NewElement . Essas propriedades
representam o elemento do Xamarin.Forms a que o renderizador estava anexado e o elemento a que o
renderizador está anexado, respectivamente. No aplicativo de exemplo, a propriedade OldElement será null e a
propriedade NewElement conterá uma referência à instância de NativeListView .
Uma versão de substituição do método OnElementChanged , em cada classe de renderizador específica da
plataforma, é o lugar para realização da personalização do controle nativo. Uma referência tipada ao controle
nativo que está sendo usado na plataforma pode ser acessada por meio da propriedade Control . Além disso, é
possível obter uma referência ao controle do Xamarin.Forms que está sendo renderizado por meio da
propriedade Element .
É necessário ter cuidado ao assinar manipuladores de eventos no método OnElementChanged , conforme
demonstrado no exemplo de código a seguir:

protected override void OnElementChanged (ElementChangedEventArgs<Xamarin.Forms.ListView> e)


{
base.OnElementChanged (e);

if (e.OldElement != null) {
// Unsubscribe from event handlers and cleanup any resources
}

if (e.NewElement != null) {
// Configure the native control and subscribe to event handlers
}
}

O controle nativo deve ser configurado e os manipuladores de eventos devem ser inscritos apenas quando o
renderizador personalizado for anexado a um novo elemento Xamarin.Forms. De forma semelhante, a inscrição
de quaisquer manipuladores de evento inscritos só deve ser cancelada quando o elemento ao qual o renderizador
está anexado for alterado. Adotar essa abordagem ajudará a criar um renderizador personalizado que não sofre
perdas de memória.
Uma versão de substituição do método OnElementPropertyChanged , em cada classe de renderizador específica da
plataforma, é o lugar para responder a alterações de propriedade vinculáveis sobre o controle personalizado do
Xamarin.Forms. Uma verificação da propriedade alterada sempre deve ser feita, pois essa substituição pode ser
chamada várias vezes.
Cada classe de renderizador personalizado é decorada com um atributo ExportRenderer que registra o
renderizador no Xamarin.Forms. O atributo aceita dois parâmetros – o nome do tipo de controle personalizado do
Xamarin.Forms que está sendo renderizado e o nome do tipo de renderizador personalizado. O prefixo assembly
do atributo especifica que o atributo se aplica a todo o assembly.
As seções a seguir abordam a implementação de cada classe de renderizador personalizado específica da
plataforma.
Criando o renderizador personalizado no iOS
O exemplo de código a seguir mostra o renderizador personalizado para a plataforma iOS:
[assembly: ExportRenderer (typeof(NativeListView), typeof(NativeiOSListViewRenderer))]
namespace CustomRenderer.iOS
{
public class NativeiOSListViewRenderer : ListViewRenderer
{
protected override void OnElementChanged (ElementChangedEventArgs<Xamarin.Forms.ListView> e)
{
base.OnElementChanged (e);

if (e.OldElement != null) {
// Unsubscribe
}

if (e.NewElement != null) {
Control.Source = new NativeiOSListViewSource (e.NewElement as NativeListView);
}
}
}
}

O controle UITableView é configurado criando uma instância da classe NativeiOSListViewSource , desde que o
renderizador personalizado esteja anexado a um novo elemento do Xamarin.Forms. Essa classe fornece dados ao
controle UITableView substituindo os métodos RowsInSection e GetCell da classe UITableViewSource e expondo
uma propriedade Items que contém a lista de dados a serem exibidos. A classe também fornece uma substituição
do método RowSelected que invoca o evento ItemSelected fornecido pelo controle personalizado
NativeListView . Para obter mais informações sobre as substituições de método, confira Subclassificação de
UITableViewSource. O método GetCell retorna um UITableCellView que é preenchido com os dados para cada
linha na lista e é mostrado no exemplo de código a seguir:

public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)


{
// request a recycled cell to save memory
NativeiOSListViewCell cell = tableView.DequeueReusableCell (cellIdentifier) as NativeiOSListViewCell;

// if there are no cells to reuse, create a new one


if (cell == null) {
cell = new NativeiOSListViewCell (cellIdentifier);
}

if (String.IsNullOrWhiteSpace (tableItems [indexPath.Row].ImageFilename)) {


cell.UpdateCell (tableItems [indexPath.Row].Name
, tableItems [indexPath.Row].Category
, null);
} else {
cell.UpdateCell (tableItems [indexPath.Row].Name
, tableItems [indexPath.Row].Category
, UIImage.FromFile ("Images/" + tableItems [indexPath.Row].ImageFilename + ".jpg"));
}

return cell;
}

Esse método cria uma instância de NativeiOSListViewCell para cada linha de dados que será exibida na tela. A
instância de NativeiOSCell define o layout de cada célula e os dados da célula. Quando uma célula desaparecer
da tela devido à rolagem, ela será disponibilizada para reutilização. Isso evita o desperdício de memória
garantindo que haja apenas instâncias de NativeiOSCell para os dados que estão sendo exibidos na tela, em vez
de todos os dados da lista. Para obter mais informações sobre a reutilização de células, confira Reutilização de
células. O método GetCell também lê a propriedade ImageFilename de cada linha de dados, desde que elas
existam, e lê a imagem e a armazena como uma instância de UIImage antes de atualizar a instância de
NativeiOSListViewCell com os dados (nome, categoria e imagem) da linha.
A classe NativeiOSListViewCell define o layout para cada célula e é mostrada no exemplo de código a seguir:

public class NativeiOSListViewCell : UITableViewCell


{
UILabel headingLabel, subheadingLabel;
UIImageView imageView;

public NativeiOSListViewCell (NSString cellId) : base (UITableViewCellStyle.Default, cellId)


{
SelectionStyle = UITableViewCellSelectionStyle.Gray;

ContentView.BackgroundColor = UIColor.FromRGB (218, 255, 127);

imageView = new UIImageView ();

headingLabel = new UILabel () {


Font = UIFont.FromName ("Cochin-BoldItalic", 22f),
TextColor = UIColor.FromRGB (127, 51, 0),
BackgroundColor = UIColor.Clear
};

subheadingLabel = new UILabel () {


Font = UIFont.FromName ("AmericanTypewriter", 12f),
TextColor = UIColor.FromRGB (38, 127, 0),
TextAlignment = UITextAlignment.Center,
BackgroundColor = UIColor.Clear
};

ContentView.Add (headingLabel);
ContentView.Add (subheadingLabel);
ContentView.Add (imageView);
}

public void UpdateCell (string caption, string subtitle, UIImage image)


{
headingLabel.Text = caption;
subheadingLabel.Text = subtitle;
imageView.Image = image;
}

public override void LayoutSubviews ()


{
base.LayoutSubviews ();

headingLabel.Frame = new CoreGraphics.CGRect (5, 4, ContentView.Bounds.Width - 63, 25);


subheadingLabel.Frame = new CoreGraphics.CGRect (100, 18, 100, 20);
imageView.Frame = new CoreGraphics.CGRect (ContentView.Bounds.Width - 63, 5, 33, 33);
}
}

Essa classe define os controles usados para renderizar o conteúdo da célula e seu layout. O construtor
NativeiOSListViewCell cria instâncias dos controles UILabel e UIImageView e inicializa sua aparência. Esses
controles são usados para exibir dados de cada linha, com o método UpdateCell sendo usado para definir esses
dados na instâncias de UILabel e UIImageView . A localização dessas instâncias é definida pelo método
LayoutSubviews substituído especificando suas coordenadas dentro da célula.

Respondendo a uma alteração de propriedade no controle personalizado


Se a propriedade NativeListView.Items for alterada devido a itens serem adicionados ou removidos da lista, o
renderizador personalizado precisará responder exibindo as alterações. Isso pode ser feito substituindo o método
OnElementPropertyChanged , que é mostrado no exemplo de código a seguir:
protected override void OnElementPropertyChanged (object sender,
System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged (sender, e);

if (e.PropertyName == NativeListView.ItemsProperty.PropertyName) {
Control.Source = new NativeiOSListViewSource (Element as NativeListView);
}
}

O método cria uma nova instância da classe NativeiOSListViewSource que fornece dados para o controle
UITableView , desde que a propriedade NativeListView.Items vinculável tenha sido alterada.

Criando o renderizador personalizado no Android


O exemplo de código a seguir mostra o renderizador personalizado para a plataforma Android:

[assembly: ExportRenderer(typeof(NativeListView), typeof(NativeAndroidListViewRenderer))]


namespace CustomRenderer.Droid
{
public class NativeAndroidListViewRenderer : ListViewRenderer
{
Context _context;

public NativeAndroidListViewRenderer(Context context) : base(context)


{
_context = context;
}

protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.ListView> e)


{
base.OnElementChanged(e);

if (e.OldElement != null)
{
// unsubscribe
Control.ItemClick -= OnItemClick;
}

if (e.NewElement != null)
{
// subscribe
Control.Adapter = new NativeAndroidListViewAdapter(_context as Android.App.Activity,
e.NewElement as NativeListView);
Control.ItemClick += OnItemClick;
}
}
...

void OnItemClick(object sender, Android.Widget.AdapterView.ItemClickEventArgs e)


{
((NativeListView)Element).NotifyItemSelected(((NativeListView)Element).Items.ToList()[e.Position -
1]);
}
}
}

O controle ListView nativo é configurado, desde que o renderizador personalizado esteja anexado a um novo
elemento do Xamarin.Forms. Essa configuração envolve a criação de uma instância da classe
NativeAndroidListViewAdapter que fornece dados para o controle ListView nativo e o registro de um
manipulador de eventos para processar o evento ItemClick . Por sua vez, esse manipulador invocará o evento
ItemSelected fornecido pelo controle personalizado NativeListView . O evento ItemClick terá a assinatura
cancelada se o elemento Xamarin.Forms a que o renderizador está anexado for alterado.
O NativeAndroidListViewAdapter deriva da classe BaseAdapter e expõe uma propriedade Items que contém a
lista de dados a serem exibidos, além de substituir os métodos Count , GetView , GetItemId e this[int] . Para
obter mais informações sobre essas substituições de método, confira Implementando um ListAdapter. O método
GetView retorna uma exibição para cada linha, preenchida com os dados, e é mostrado no exemplo de código a
seguir:

public override View GetView (int position, View convertView, ViewGroup parent)
{
var item = tableItems [position];

var view = convertView;


if (view == null) {
// no view to re-use, create new
view = context.LayoutInflater.Inflate (Resource.Layout.NativeAndroidListViewCell, null);
}
view.FindViewById<TextView> (Resource.Id.Text1).Text = item.Name;
view.FindViewById<TextView> (Resource.Id.Text2).Text = item.Category;

// grab the old image and dispose of it


if (view.FindViewById<ImageView> (Resource.Id.Image).Drawable != null) {
using (var image = view.FindViewById<ImageView> (Resource.Id.Image).Drawable as BitmapDrawable) {
if (image != null) {
if (image.Bitmap != null) {
//image.Bitmap.Recycle ();
image.Bitmap.Dispose ();
}
}
}
}

// If a new image is required, display it


if (!String.IsNullOrWhiteSpace (item.ImageFilename)) {
context.Resources.GetBitmapAsync (item.ImageFilename).ContinueWith ((t) => {
var bitmap = t.Result;
if (bitmap != null) {
view.FindViewById<ImageView> (Resource.Id.Image).SetImageBitmap (bitmap);
bitmap.Dispose ();
}
}, TaskScheduler.FromCurrentSynchronizationContext ());
} else {
// clear the image
view.FindViewById<ImageView> (Resource.Id.Image).SetImageBitmap (null);
}

return view;
}

O método GetView é chamado para retornar a célula a ser renderizada, como um View , para cada linha de dados
na lista. Ele cria uma instância de View para cada linha de dados que será exibida na tela, com a aparência da
instância de View definida em um arquivo de layout. Quando uma célula desaparecer da tela devido à rolagem,
ela será disponibilizada para reutilização. Isso evita o desperdício de memória garantindo que haja apenas
instâncias de View para os dados que estão sendo exibidos na tela, em vez de todos os dados da lista. Para obter
mais informações sobre a reutilização da exibição, confira Reutilização da exibição de linha.
O método GetView também preenche a instância de View com os dados, incluindo a leitura dos dados de
imagem do nome de arquivo especificado na propriedade ImageFilename .
O layout de cada célula exibida pelo ListView nativo é definido no arquivo de layout
NativeAndroidListViewCell.axml , que é inflado pelo método LayoutInflater.Inflate . O exemplo de código a
seguir mostra a definição do layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:background="@drawable/CustomSelector">
<LinearLayout
android:id="@+id/Text"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="10dip">
<TextView
android:id="@+id/Text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FF7F3300"
android:textSize="20dip"
android:textStyle="italic" />
<TextView
android:id="@+id/Text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14dip"
android:textColor="#FF267F00"
android:paddingLeft="100dip" />
</LinearLayout>
<ImageView
android:id="@+id/Image"
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="5dp"
android:src="@drawable/icon"
android:layout_alignParentRight="true" />
</RelativeLayout>

Esse layout especifica que dois controles TextView e um controle ImageView sejam usados para exibir o conteúdo
da célula. Os dois controles TextView têm orientação vertical dentro de um controle LinearLayout , com todos os
controles contidos em um RelativeLayout .
Respondendo a uma alteração de propriedade no controle personalizado
Se a propriedade NativeListView.Items for alterada devido a itens serem adicionados ou removidos da lista, o
renderizador personalizado precisará responder exibindo as alterações. Isso pode ser feito substituindo o método
OnElementPropertyChanged , que é mostrado no exemplo de código a seguir:

protected override void OnElementPropertyChanged (object sender,


System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged (sender, e);

if (e.PropertyName == NativeListView.ItemsProperty.PropertyName) {
Control.Adapter = new NativeAndroidListViewAdapter (_context as Android.App.Activity, Element as
NativeListView);
}
}

O método cria uma nova instância da classe NativeAndroidListViewAdapter que fornece dados para o controle
ListView nativo, desde que a propriedade NativeListView.Items vinculável tenha sido alterada.

Criando o renderizador personalizado na UWP


O exemplo de código a seguir mostra o renderizador personalizado para a UWP:
[assembly: ExportRenderer(typeof(NativeListView), typeof(NativeUWPListViewRenderer))]
namespace CustomRenderer.UWP
{
public class NativeUWPListViewRenderer : ListViewRenderer
{
ListView listView;

protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.ListView> e)


{
base.OnElementChanged(e);

listView = Control as ListView;

if (e.OldElement != null)
{
// Unsubscribe
listView.SelectionChanged -= OnSelectedItemChanged;
}

if (e.NewElement != null)
{
listView.SelectionMode = ListViewSelectionMode.Single;
listView.IsItemClickEnabled = false;
listView.ItemsSource = ((NativeListView)e.NewElement).Items;
listView.ItemTemplate = App.Current.Resources["ListViewItemTemplate"] as
Windows.UI.Xaml.DataTemplate;
// Subscribe
listView.SelectionChanged += OnSelectedItemChanged;
}
}

void OnSelectedItemChanged(object sender, SelectionChangedEventArgs e)


{
((NativeListView)Element).NotifyItemSelected(listView.SelectedItem);
}
}
}

O controle ListView nativo é configurado, desde que o renderizador personalizado esteja anexado a um novo
elemento do Xamarin.Forms. Essa configuração envolve definir como o controle ListView nativo responderá à
seleção de itens, ao preenchimento dos dados exibidos pelo controle, à definição da aparência e do conteúdo de
cada célula e ao registro de um manipulador de eventos para processar o evento SelectionChanged . Por sua vez,
esse manipulador invocará o evento ItemSelected fornecido pelo controle personalizado NativeListView . O
evento SelectionChanged terá a assinatura cancelada se o elemento Xamarin.Forms a que o renderizador está
anexado for alterado.
A aparência e o conteúdo de cada célula ListView nativa são definidos por um DataTemplate denominado
ListViewItemTemplate . Esse DataTemplate é armazenado no dicionário de recursos de nível de aplicativo e é
mostrado no exemplo de código a seguir:
<DataTemplate x:Key="ListViewItemTemplate">
<Grid Background="#DAFF7F">
<Grid.Resources>
<local:ConcatImageExtensionConverter x:Name="ConcatImageExtensionConverter" />
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.40*" />
<ColumnDefinition Width="0.40*"/>
<ColumnDefinition Width="0.20*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.ColumnSpan="2" Foreground="#7F3300" FontStyle="Italic" FontSize="22"
VerticalAlignment="Top" Text="{Binding Name}" />
<TextBlock Grid.RowSpan="2" Grid.Column="1" Foreground="#267F00" FontWeight="Bold" FontSize="12"
VerticalAlignment="Bottom" Text="{Binding Category}" />
<Image Grid.RowSpan="2" Grid.Column="2" HorizontalAlignment="Left" VerticalAlignment="Center" Source="
{Binding ImageFilename, Converter={StaticResource ConcatImageExtensionConverter}}" Width="50" Height="50" />
<Line Grid.Row="1" Grid.ColumnSpan="3" X1="0" X2="1" Margin="30,20,0,0" StrokeThickness="1"
Stroke="LightGray" Stretch="Fill" VerticalAlignment="Bottom" />
</Grid>
</DataTemplate>

O DataTemplate especifica os controles usados para exibir o conteúdo da célula, bem como seu layout e aparência.
Dois controles TextBlock e um controle Image são usados para exibir o conteúdo da célula por meio da
associação de dados. Além disso, uma instância do ConcatImageExtensionConverter é usada para concatenar a
extensão de arquivo .jpg a cada nome de arquivo de imagem. Isso garante que o controle Image possa carregar
e renderizar a imagem quando sua propriedade Source estiver definida.
Respondendo a uma alteração de propriedade no controle personalizado
Se a propriedade NativeListView.Items for alterada devido a itens serem adicionados ou removidos da lista, o
renderizador personalizado precisará responder exibindo as alterações. Isso pode ser feito substituindo o método
OnElementPropertyChanged , que é mostrado no exemplo de código a seguir:

protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs


e)
{
base.OnElementPropertyChanged(sender, e);

if (e.PropertyName == NativeListView.ItemsProperty.PropertyName)
{
listView.ItemsSource = ((NativeListView)Element).Items;
}
}

O método preenche novamente o controle ListView nativo com os dados alterados, desde que a propriedade
NativeListView.Items vinculável tenha sido alterada.

Resumo
Este artigo demonstrou como criar um renderizador personalizado que encapsula os controles de lista e layouts
de célula nativa específicos a uma plataforma, permitindo mais controle sobre o desempenho do controle de lista
nativo.

Links relacionados
CustomRendererListView (amostra)
Personalizando um ViewCell
12/04/2019 • 25 minutes to read • Edit Online

Baixar o exemplo
Um ViewCell do Xamarin.Forms é uma célula que pode ser adicionada a um ListView ou a um TableView, que
contém uma exibição definida pelo desenvolvedor. Este artigo demonstra como criar um renderizador
personalizado para um ViewCell hospedado dentro de um controle ListView do Xamarin.Forms. Isso impede que
os cálculos de layout do Xamarin.Forms sejam chamados repetidamente durante a rolagem de ListView.
Cada uma das células do Xamarin.Forms tem um renderizador que a acompanha para cada plataforma que cria
uma instância de um controle nativo. Quando um ViewCell é renderizado por um aplicativo Xamarin.Forms, no
iOS é criada uma instância da classe ViewCellRenderer , o que por sua vez cria uma instância de um controle
UITableViewCell nativo. Na plataforma Android, a classe ViewCellRenderer cria uma instância de um controle
View nativo. Na UWP ( Plataforma Universal do Windows), a classe ViewCellRenderer cria uma instância de um
DataTemplate nativo. Para obter mais informações sobre as classes de renderizador e de controle nativo para as
quais os controles do Xamarin.Forms são mapeadas, confira Classes base do renderizador e controles nativos.
O seguinte diagrama ilustra a relação entre o ViewCell e os controles nativos correspondentes que o
implementam:

E possível aproveitar o processo de renderização para implementar personalizações específicas da plataforma


criando um renderizador personalizado para um ViewCell em cada plataforma. O processo para fazer isso é o
seguinte:
1. Criar uma célula personalizada do Xamarin.Forms.
2. Consumir a célula personalizada do Xamarin.Forms.
3. Criar o renderizador personalizado para a célula em cada plataforma.
Agora, cada item será abordado separadamente, a fim de implementar um renderizador de NativeCell que tira
proveito de um layout específico da plataforma para cada célula hospedada dentro de um controle ListView do
Xamarin.Forms. Isso impede que os cálculos de layout do Xamarin.Forms sejam chamados repetidamente
durante a rolagem de ListView .

Criando a célula personalizada


É possível criar um controle de célula personalizado criando subclasses da classe ViewCell , conforme mostrado
no exemplo de código a seguir:
public class NativeCell : ViewCell
{
public static readonly BindableProperty NameProperty =
BindableProperty.Create ("Name", typeof(string), typeof(NativeCell), "");

public string Name {


get { return (string)GetValue (NameProperty); }
set { SetValue (NameProperty, value); }
}

public static readonly BindableProperty CategoryProperty =


BindableProperty.Create ("Category", typeof(string), typeof(NativeCell), "");

public string Category {


get { return (string)GetValue (CategoryProperty); }
set { SetValue (CategoryProperty, value); }
}

public static readonly BindableProperty ImageFilenameProperty =


BindableProperty.Create ("ImageFilename", typeof(string), typeof(NativeCell), "");

public string ImageFilename {


get { return (string)GetValue (ImageFilenameProperty); }
set { SetValue (ImageFilenameProperty, value); }
}
}

A classe NativeCell é criada no projeto da biblioteca .NET Standard e define a API para a célula personalizada. A
célula personalizada expõe as propriedades Name , Category e ImageFilename , que podem ser exibidas por meio
da associação de dados. Para obter mais informações sobre vinculação de dados, veja Noções básicas de
vinculação de dados.

Consumindo a célula personalizada


A célula personalizada NativeCell pode ser referenciada em XAML no projeto da biblioteca .NET Standard
declarando um namespace para sua localização e usando o prefixo do namespace na célula personalizada. O
exemplo de código a seguir mostra como a célula personalizada NativeCell pode ser consumida por uma página
XAML:

<ContentPage ...
xmlns:local="clr-namespace:CustomRenderer;assembly=CustomRenderer"
...>
...
<ContentPage.Content>
<StackLayout>
<Label Text="Xamarin.Forms native cell" HorizontalTextAlignment="Center" />
<ListView x:Name="listView" CachingStrategy="RecycleElement" ItemSelected="OnItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<local:NativeCell Name="{Binding Name}" Category="{Binding Category}"
ImageFilename="{Binding ImageFilename}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>

O prefixo do namespace local pode ter qualquer nome. No entanto, os valores de clr-namespace e assembly
devem corresponder aos detalhes do controle personalizado. Quando o namespace é declarado, o prefixo é usado
para referenciar a célula personalizada.
O exemplo de código a seguir mostra como a célula personalizada NativeCell pode ser consumida por uma
página C#:

public class NativeCellPageCS : ContentPage


{
ListView listView;

public NativeCellPageCS()
{
listView = new ListView(ListViewCachingStrategy.RecycleElement)
{
ItemsSource = DataSource.GetList(),
ItemTemplate = new DataTemplate(() =>
{
var nativeCell = new NativeCell();
nativeCell.SetBinding(NativeCell.NameProperty, "Name");
nativeCell.SetBinding(NativeCell.CategoryProperty, "Category");
nativeCell.SetBinding(NativeCell.ImageFilenameProperty, "ImageFilename");

return nativeCell;
})
};

switch (Device.RuntimePlatform)
{
case Device.iOS:
Padding = new Thickness(0, 20, 0, 0);
break;
case Device.Android:
case Device.UWP:
Padding = new Thickness(0);
break;
}

Content = new StackLayout


{
Children = {
new Label { Text = "Xamarin.Forms native cell", HorizontalTextAlignment =
TextAlignment.Center },
listView
}
};
listView.ItemSelected += OnItemSelected;
}
...
}

Um controle ListView do Xamarin.Forms é usado para exibir uma lista de dados, que é preenchida por meio da
propriedade ItemSource . A estratégia de cache de RecycleElement tenta minimizar o volume de memória de
ListView e a velocidade de execução reciclando células da lista. Para obter mais informações, confira Estratégia
de Cache.
Cada linha na lista contém três itens de dados – um nome, uma categoria e um nome de arquivo de imagem. O
layout de cada linha da lista é definido pelo DataTemplate , que é referenciado por meio da propriedade associável
ListView.ItemTemplate . O DataTemplate define que cada linha de dados na lista será um NativeCell que exibe
suas propriedades Name , Category e ImageFilename por meio da associação de dados. Para obter mais
informações sobre o controle ListView , confira ListView.
Agora, um renderizador personalizado pode ser adicionado a cada projeto de aplicativo para personalizar o layout
específico à plataforma para cada célula.

Criando o renderizador personalizado em cada plataforma


O processo para criar a classe do renderizador personalizado é o seguinte:
1. Criar uma subclasse da classe ViewCellRenderer que renderiza a célula personalizada.
2. Substitua o método específico à plataforma que renderiza a célula personalizada e escreva a lógica para
personalizá-la.
3. Adicione um atributo ExportRenderer à classe de renderizador personalizado para especificar que ele será
usado para renderizar a célula personalizada do Xamarin.Forms. Esse atributo é usado para registrar o
renderizador personalizado no Xamarin.Forms.

NOTE
Para a maioria dos elementos do Xamarin.Forms, o fornecimento de um renderizador personalizado em cada projeto de
plataforma é opcional. Se um renderizador personalizado não estiver registrado, será usado o renderizador padrão da classe
base do controle. No entanto, são necessários renderizadores personalizados em cada projeto da plataforma durante a
renderização de um elemento ViewCell.

O seguinte diagrama ilustra as responsabilidades de cada projeto no aplicativo de exemplo, bem como as
relações entre elas:

A célula personalizada NativeCell é renderizada por classes de renderizador específicas da plataforma, que
derivam da classe ViewCellRenderer de cada plataforma. Isso faz com que cada célula personalizada NativeCell
seja renderizada com o layout específico da plataforma, conforme mostrado nas capturas de tela seguir:

A classe ViewCellRenderer expõe métodos específicos da plataforma para renderização da célula personalizada.
Trata-se do método GetCell na plataforma iOS, do método GetCellCore na plataforma Android e do método
GetTemplate na UWP.
Cada classe de renderizador personalizado é decorada com um atributo ExportRenderer que registra o
renderizador no Xamarin.Forms. O atributo aceita dois parâmetros – o nome do tipo da célula do Xamarin.Forms
que está sendo renderizada e o nome do tipo de renderizador personalizado. O prefixo assembly do atributo
especifica que o atributo se aplica a todo o assembly.
As seções a seguir abordam a implementação de cada classe de renderizador personalizado específica da
plataforma.
Criando o renderizador personalizado no iOS
O seguinte exemplo de código mostra o renderizador personalizado para a plataforma iOS:

[assembly: ExportRenderer(typeof(NativeCell), typeof(NativeiOSCellRenderer))]


namespace CustomRenderer.iOS
{
public class NativeiOSCellRenderer : ViewCellRenderer
{
NativeiOSCell cell;

public override UITableViewCell GetCell(Cell item, UITableViewCell reusableCell, UITableView tv)


{
var nativeCell = (NativeCell)item;

cell = reusableCell as NativeiOSCell;


if (cell == null)
cell = new NativeiOSCell(item.GetType().FullName, nativeCell);
else
cell.NativeCell.PropertyChanged -= OnNativeCellPropertyChanged;

nativeCell.PropertyChanged += OnNativeCellPropertyChanged;
cell.UpdateCell(nativeCell);
return cell;
}
...
}
}

O método GetCell é chamado para compilar cada célula a ser exibida. Cada célula é uma instância de
NativeiOSCell , que define o layout da célula e seus dados. A operação do método GetCell depende da
estratégia de cache de ListView :
Quando a estratégia de cache de ListView é RetainElement , o método GetCell é invocado para cada
célula. Uma instância de NativeiOSCell é criada para cada instância de NativeCell exibida inicialmente na
tela. Conforme o usuário rola pelo ListView , instâncias de NativeiOSCell são reutilizadas. Para obter mais
informações sobre a reutilização de células do iOS, confira Reutilização de células.

NOTE
Esse código de renderizador personalizado reutilizará algumas células mesmo quando o ListView estiver definido
para reter células.

Os dados exibidos por cada instância de NativeiOSCell , quer ela tenha sido criada recentemente ou
reutilizada, serão atualizados com os dados de cada instância de NativeCell pelo método UpdateCell .

NOTE
O método OnNativeCellPropertyChanged nunca será invocado quando a estratégia de cache de ListView
estiver definida para reter as células.
Quando a estratégia de cache de ListView é RecycleElement , o método GetCell é invocado para cada
célula exibida inicialmente na tela. Uma instância de NativeiOSCell é criada para cada instância de
NativeCell exibida inicialmente na tela. Os dados exibidos por cada instância de NativeiOSCell serão
atualizados com os dados da instância de NativeCell pelo método UpdateCell . No entanto, o método
GetCell não será invocado conforme o usuário percorrer o ListView . Em vez disso, as instâncias de
NativeiOSCell serão reutilizadas. Eventos PropertyChanged serão gerados na instância de NativeCell
quando seus dados forem alterados e o manipulador de eventos OnNativeCellPropertyChanged atualizará os
dados em cada instância de NativeiOSCell reutilizada.

O exemplo de código a seguir mostra o método OnNativeCellPropertyChanged invocado quando um evento


PropertyChanged é gerado:

namespace CustomRenderer.iOS
{
public class NativeiOSCellRenderer : ViewCellRenderer
{
...

void OnNativeCellPropertyChanged(object sender, PropertyChangedEventArgs e)


{
var nativeCell = (NativeCell)sender;
if (e.PropertyName == NativeCell.NameProperty.PropertyName)
{
cell.HeadingLabel.Text = nativeCell.Name;
}
else if (e.PropertyName == NativeCell.CategoryProperty.PropertyName)
{
cell.SubheadingLabel.Text = nativeCell.Category;
}
else if (e.PropertyName == NativeCell.ImageFilenameProperty.PropertyName)
{
cell.CellImageView.Image = cell.GetImage(nativeCell.ImageFilename);
}
}
}
}

Esse método atualiza os dados exibidos pelas instâncias de NativeiOSCell reutilizadas. É feita uma verificação da
propriedade alterada, pois o método pode ser chamado várias vezes.
A classe NativeiOSCell define o layout para cada célula e é mostrada no exemplo de código a seguir:
internal class NativeiOSCell : UITableViewCell, INativeElementView
{
public UILabel HeadingLabel { get; set; }
public UILabel SubheadingLabel { get; set; }
public UIImageView CellImageView { get; set; }

public NativeCell NativeCell { get; private set; }


public Element Element => NativeCell;

public NativeiOSCell(string cellId, NativeCell cell) : base(UITableViewCellStyle.Default, cellId)


{
NativeCell = cell;

SelectionStyle = UITableViewCellSelectionStyle.Gray;
ContentView.BackgroundColor = UIColor.FromRGB(255, 255, 224);
CellImageView = new UIImageView();

HeadingLabel = new UILabel()


{
Font = UIFont.FromName("Cochin-BoldItalic", 22f),
TextColor = UIColor.FromRGB(127, 51, 0),
BackgroundColor = UIColor.Clear
};

SubheadingLabel = new UILabel()


{
Font = UIFont.FromName("AmericanTypewriter", 12f),
TextColor = UIColor.FromRGB(38, 127, 0),
TextAlignment = UITextAlignment.Center,
BackgroundColor = UIColor.Clear
};

ContentView.Add(HeadingLabel);
ContentView.Add(SubheadingLabel);
ContentView.Add(CellImageView);
}

public void UpdateCell(NativeCell cell)


{
HeadingLabel.Text = cell.Name;
SubheadingLabel.Text = cell.Category;
CellImageView.Image = GetImage(cell.ImageFilename);
}

public UIImage GetImage(string filename)


{
return (!string.IsNullOrWhiteSpace(filename)) ? UIImage.FromFile("Images/" + filename + ".jpg") : null;
}

public override void LayoutSubviews()


{
base.LayoutSubviews();

HeadingLabel.Frame = new CGRect(5, 4, ContentView.Bounds.Width - 63, 25);


SubheadingLabel.Frame = new CGRect(100, 18, 100, 20);
CellImageView.Frame = new CGRect(ContentView.Bounds.Width - 63, 5, 33, 33);
}
}

Essa classe define os controles usados para renderizar o conteúdo da célula e seu layout. A classe implementa a
interface INativeElementView , o que é necessário quando o ListView usa a estratégia de cache RecycleElement .
Essa interface especifica que a classe deve implementar a propriedade Element , que deve retornar dados da
célula personalizada para células recicladas.
O construtor NativeiOSCell inicializa a aparência das propriedades HeadingLabel , SubheadingLabel e
CellImageView . Essas propriedades são usadas para exibir os dados armazenados na instância de NativeCell ,
com o método UpdateCell sendo chamado para definir o valor de cada propriedade. Além disso, quando o
ListView usa a estratégia de cache RecycleElement , os dados exibidos pelas propriedades HeadingLabel ,
SubheadingLabel e CellImageView podem ser atualizados pelo método OnNativeCellPropertyChanged no
renderizador personalizado.
O layout da célula é executado pela substituição LayoutSubviews , que define as coordenadas de HeadingLabel ,
SubheadingLabel e CellImageView dentro da célula.

Criando o renderizador personalizado no Android


O seguinte exemplo de código mostra o renderizador personalizado para a plataforma Android:

[assembly: ExportRenderer(typeof(NativeCell), typeof(NativeAndroidCellRenderer))]


namespace CustomRenderer.Droid
{
public class NativeAndroidCellRenderer : ViewCellRenderer
{
NativeAndroidCell cell;

protected override Android.Views.View GetCellCore(Cell item, Android.Views.View convertView,


ViewGroup parent, Context context)
{
var nativeCell = (NativeCell)item;
Console.WriteLine("\t\t" + nativeCell.Name);

cell = convertView as NativeAndroidCell;


if (cell == null)
{
cell = new NativeAndroidCell(context, nativeCell);
}
else
{
cell.NativeCell.PropertyChanged -= OnNativeCellPropertyChanged;
}

nativeCell.PropertyChanged += OnNativeCellPropertyChanged;

cell.UpdateCell(nativeCell);
return cell;
}
...
}
}

O método GetCellCore é chamado para compilar cada célula a ser exibida. Cada célula é uma instância de
NativeAndroidCell , que define o layout da célula e seus dados. A operação do método GetCellCore depende da
estratégia de cache de ListView :
Quando a estratégia de cache de ListView é RetainElement , o método GetCellCore é invocado para cada
célula. Um NativeAndroidCell é criado para cada instância de NativeCell exibida inicialmente na tela.
Conforme o usuário rola pelo ListView , instâncias de NativeAndroidCell são reutilizadas. Para obter mais
informações sobre a reutilização de células no Android, confira Reutilização da exibição de linha.

NOTE
Observe que esse código de renderizador personalizado reutilizará algumas células mesmo quando o ListView
estiver definido para reter células.

Os dados exibidos por cada instância de NativeAndroidCell , quer ela tenha sido criada recentemente ou
reutilizada, serão atualizados com os dados de cada instância de NativeCell pelo método UpdateCell .

NOTE
Observe que, embora o método OnNativeCellPropertyChanged seja invocado quando ListView é configurado
para reter as células, ele não atualizará o valores da propriedade NativeAndroidCell .

Quando a estratégia de cache de ListView é RecycleElement , o método GetCellCore é invocado para cada
célula exibida inicialmente na tela. Uma instância de NativeAndroidCell é criada para cada instância de
NativeCell exibida inicialmente na tela. Os dados exibidos por cada instância de NativeAndroidCell serão
atualizados com os dados da instância de NativeCell pelo método UpdateCell . No entanto, o método
GetCellCore não será invocado conforme o usuário percorrer o ListView . Em vez disso, as instâncias de
NativeAndroidCell serão reutilizadas. Eventos PropertyChanged serão gerados na instância de NativeCell
quando seus dados forem alterados e o manipulador de eventos OnNativeCellPropertyChanged atualizará os
dados em cada instância de NativeAndroidCell reutilizada.

O exemplo de código a seguir mostra o método OnNativeCellPropertyChanged invocado quando um evento


PropertyChanged é gerado:

namespace CustomRenderer.Droid
{
public class NativeAndroidCellRenderer : ViewCellRenderer
{
...

void OnNativeCellPropertyChanged(object sender, PropertyChangedEventArgs e)


{
var nativeCell = (NativeCell)sender;
if (e.PropertyName == NativeCell.NameProperty.PropertyName)
{
cell.HeadingTextView.Text = nativeCell.Name;
}
else if (e.PropertyName == NativeCell.CategoryProperty.PropertyName)
{
cell.SubheadingTextView.Text = nativeCell.Category;
}
else if (e.PropertyName == NativeCell.ImageFilenameProperty.PropertyName)
{
cell.SetImage(nativeCell.ImageFilename);
}
}
}
}

Esse método atualiza os dados exibidos pelas instâncias de NativeAndroidCell reutilizadas. É feita uma verificação
da propriedade alterada, pois o método pode ser chamado várias vezes.
A classe NativeAndroidCell define o layout para cada célula e é mostrada no exemplo de código a seguir:
internal class NativeAndroidCell : LinearLayout, INativeElementView
{
public TextView HeadingTextView { get; set; }
public TextView SubheadingTextView { get; set; }
public ImageView ImageView { get; set; }

public NativeCell NativeCell { get; private set; }


public Element Element => NativeCell;

public NativeAndroidCell(Context context, NativeCell cell) : base(context)


{
NativeCell = cell;

var view = (context as Activity).LayoutInflater.Inflate(Resource.Layout.NativeAndroidCell, null);


HeadingTextView = view.FindViewById<TextView>(Resource.Id.HeadingText);
SubheadingTextView = view.FindViewById<TextView>(Resource.Id.SubheadingText);
ImageView = view.FindViewById<ImageView>(Resource.Id.Image);

AddView(view);
}

public void UpdateCell(NativeCell cell)


{
HeadingTextView.Text = cell.Name;
SubheadingTextView.Text = cell.Category;

// Dispose of the old image


if (ImageView.Drawable != null)
{
using (var image = ImageView.Drawable as BitmapDrawable)
{
if (image != null)
{
if (image.Bitmap != null)
{
image.Bitmap.Dispose();
}
}
}
}

SetImage(cell.ImageFilename);
}

public void SetImage(string filename)


{
if (!string.IsNullOrWhiteSpace(filename))
{
// Display new image
Context.Resources.GetBitmapAsync(filename).ContinueWith((t) =>
{
var bitmap = t.Result;
if (bitmap != null)
{
ImageView.SetImageBitmap(bitmap);
bitmap.Dispose();
}
}, TaskScheduler.FromCurrentSynchronizationContext());
}
else
{
// Clear the image
ImageView.SetImageBitmap(null);
}
}
}
Essa classe define os controles usados para renderizar o conteúdo da célula e seu layout. A classe implementa a
interface INativeElementView , o que é necessário quando o ListView usa a estratégia de cache RecycleElement .
Essa interface especifica que a classe deve implementar a propriedade Element , que deve retornar dados da
célula personalizada para células recicladas.
O construtor NativeAndroidCellinfla o layout NativeAndroidCell e inicializa as propriedades HeadingTextView ,
SubheadingTextView e ImageView para os controles no layout inflado. Essas propriedades são usadas para exibir
os dados armazenados na instância de NativeCell , com o método UpdateCell sendo chamado para definir o
valor de cada propriedade. Além disso, quando o ListView usa a estratégia de cache RecycleElement , os dados
exibidos pelas propriedades HeadingTextView , SubheadingTextView e ImageView podem ser atualizados pelo
método OnNativeCellPropertyChanged no renderizador personalizado.
O exemplo de código a seguir mostra a definição do layout para o arquivo de layout NativeAndroidCell.axml :

<?xml version="1.0" encoding="utf-8"?>


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:background="@drawable/CustomSelector">
<LinearLayout
android:id="@+id/Text"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="10dip">
<TextView
android:id="@+id/HeadingText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FF7F3300"
android:textSize="20dip"
android:textStyle="italic" />
<TextView
android:id="@+id/SubheadingText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14dip"
android:textColor="#FF267F00"
android:paddingLeft="100dip" />
</LinearLayout>
<ImageView
android:id="@+id/Image"
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="5dp"
android:src="@drawable/icon"
android:layout_alignParentRight="true" />
</RelativeLayout>

Esse layout especifica que dois controles TextView e um controle ImageView sejam usados para exibir o conteúdo
da célula. Os dois controles TextView têm orientação vertical dentro de um controle LinearLayout , com todos os
controles contidos em um RelativeLayout .
Criando o renderizador personalizado na UWP
O seguinte exemplo de código mostra o renderizador personalizado para o UWP:
[assembly: ExportRenderer(typeof(NativeCell), typeof(NativeUWPCellRenderer))]
namespace CustomRenderer.UWP
{
public class NativeUWPCellRenderer : ViewCellRenderer
{
public override Windows.UI.Xaml.DataTemplate GetTemplate(Cell cell)
{
return App.Current.Resources["ListViewItemTemplate"] as Windows.UI.Xaml.DataTemplate;
}
}
}

O método GetTemplate é chamado para retornar a célula a ser renderizada para cada linha de dados na lista. Ele
cria um DataTemplate para cada instância de NativeCell que será exibida na tela, com o DataTemplate definindo
a aparência e o conteúdo da célula.
O DataTemplate é armazenado no dicionário de recursos de nível de aplicativo e é mostrado no exemplo de
código a seguir:

<DataTemplate x:Key="ListViewItemTemplate">
<Grid Background="LightYellow">
<Grid.Resources>
<local:ConcatImageExtensionConverter x:Name="ConcatImageExtensionConverter" />
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.40*" />
<ColumnDefinition Width="0.40*"/>
<ColumnDefinition Width="0.20*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.ColumnSpan="2" Foreground="#7F3300" FontStyle="Italic" FontSize="22"
VerticalAlignment="Top" Text="{Binding Name}" />
<TextBlock Grid.RowSpan="2" Grid.Column="1" Foreground="#267F00" FontWeight="Bold" FontSize="12"
VerticalAlignment="Bottom" Text="{Binding Category}" />
<Image Grid.RowSpan="2" Grid.Column="2" HorizontalAlignment="Left" VerticalAlignment="Center"
Source="{Binding ImageFilename, Converter={StaticResource ConcatImageExtensionConverter}}" Width="50"
Height="50" />
<Line Grid.Row="1" Grid.ColumnSpan="3" X1="0" X2="1" Margin="30,20,0,0" StrokeThickness="1"
Stroke="LightGray" Stretch="Fill" VerticalAlignment="Bottom" />
</Grid>
</DataTemplate>

O DataTemplate especifica os controles usados para exibir o conteúdo da célula, bem como seu layout e
aparência. Dois controles TextBlock e um controle Image são usados para exibir o conteúdo da célula por meio
da associação de dados. Além disso, uma instância do ConcatImageExtensionConverter é usada para concatenar a
extensão de arquivo .jpg a cada nome de arquivo de imagem. Isso garante que o controle Image possa carregar
e renderizar a imagem quando sua propriedade Source estiver definida.

Resumo
Este artigo demonstrou como criar um renderizador personalizado para um ViewCell hospedado dentro de um
controle ListView do Xamarin.Forms. Isso impede que os cálculos de layout do Xamarin.Forms sejam chamados
repetidamente durante a rolagem de ListView .

Links relacionados
Desempenho de ListView
CustomRendererViewCell (amostra)
Implementando uma exibição
12/04/2019 • 17 minutes to read • Edit Online

Baixar o exemplo
Controles de interfaces do usuário personalizadas do Xamarin.Forms devem derivar da classe View, que é usada
para colocar os layouts e controles na tela. Este artigo demonstra como criar um renderizador personalizado para
um controle personalizado do Xamarin.Forms, que é usado para exibir um fluxo de vídeo de visualização com a
câmera do dispositivo.
Cada exibição do Xamarin.Forms tem um renderizador que o acompanha para cada plataforma que cria uma
instância de um controle nativo. Quando um View é renderizado por um aplicativo Xamarin.Forms no iOS, é
criada uma instância da classe ViewRenderer , que, por sua vez, cria uma instância de um controle UIView nativo.
Na plataforma Android, a classe ViewRenderer cria uma instância de um controle View nativo. Na UWP
(Plataforma Universal do Windows), a classe ViewRenderer cria uma instância de um controle FrameworkElement
nativo. Para obter mais informações sobre as classes de renderizador e de controle nativo para as quais os
controles do Xamarin.Forms são mapeadas, confira Classes base do renderizador e controles nativos.
O seguinte diagrama ilustra a relação entre o View e os controles nativos correspondentes que o implementam:

E possível usar o processo de renderização para implementar personalizações específicas da plataforma criando
um renderizador personalizado para um View em cada plataforma. O processo para fazer isso é o seguinte:
1. Criar um controle personalizado do Xamarin.Forms.
2. Consumir o controle personalizado do Xamarin.Forms.
3. Criar o renderizador personalizado para o controle em cada plataforma.
Agora, cada item será discutido separadamente, a fim de implementar um renderizador CameraPreview que exibe
um fluxo de vídeo de visualização usando a câmera do dispositivo. Tocar no fluxo de vídeo o interromperá e
iniciará.

Criando o controle personalizado


É possível criar um controle personalizado criando subclasses da classe View , conforme mostrado no exemplo de
código a seguir:
public class CameraPreview : View
{
public static readonly BindableProperty CameraProperty = BindableProperty.Create (
propertyName: "Camera",
returnType: typeof(CameraOptions),
declaringType: typeof(CameraPreview),
defaultValue: CameraOptions.Rear);

public CameraOptions Camera {


get { return (CameraOptions)GetValue (CameraProperty); }
set { SetValue (CameraProperty, value); }
}
}

O controle personalizado CameraPreview é criado no projeto de PCL (biblioteca de classes portátil) e define a API
para o controle. O controle personalizado expõe uma propriedade Camera que é usada para controlar se o fluxo de
vídeo deve ser exibido na parte frontal ou traseira da câmera do dispositivo. Se não for especificado um valor para
a propriedade Camera quando o controle for criado, o comportamento padrão será especificar a câmera traseira.

Consumindo o controle personalizado


O controle personalizado CameraPreview pode ser referenciado em XAML no projeto da PCL declarando um
namespace para sua localização e usando o prefixo do namespace no elemento de controle personalizado. O
exemplo de código a seguir mostra como o controle personalizado CameraPreview pode ser consumido por uma
página XAML:

<ContentPage ...
xmlns:local="clr-namespace:CustomRenderer;assembly=CustomRenderer"
...>
<ContentPage.Content>
<StackLayout>
<Label Text="Camera Preview:" />
<local:CameraPreview Camera="Rear"
HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" />
</StackLayout>
</ContentPage.Content>
</ContentPage>

O prefixo do namespace local pode ser qualquer nome. No entanto, os valores de clr-namespace e assembly
devem corresponder aos detalhes do controle personalizado. Quando o namespace é declarado, o prefixo é usado
para referenciar o controle personalizado.
O seguinte exemplo de código mostra como o controle personalizado CameraPreview pode ser consumido por um
página em C#:
public class MainPageCS : ContentPage
{
public MainPageCS ()
{
...
Content = new StackLayout {
Children = {
new Label { Text = "Camera Preview:" },
new CameraPreview {
Camera = CameraOptions.Rear,
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand
}
}
};
}
}

Uma instância do controle personalizado CameraPreview será usada para exibir o fluxo de vídeo de visualização da
câmera do dispositivo. Além de, opcionalmente, especificar um valor para a propriedade Camera , a personalização
do controle será realizada no renderizador personalizado.
Agora, é possível adicionar um renderizador personalizado a cada projeto de aplicativo para criar controles de
visualização de câmera específicos da plataforma.

Criando o renderizador personalizado em cada plataforma


O processo para criar a classe do renderizador personalizado é o seguinte:
1. Crie uma subclasse da classe ViewRenderer<T1,T2> que renderiza o controle personalizado. O primeiro
argumento de tipo deve ser o controle personalizado a que o renderizador se aplica, neste caso, CameraPreview .
O segundo argumento de tipo deve ser o controle nativo que implementará o controle personalizado.
2. Substitua o método OnElementChanged que renderiza o controle personalizado e escreva a lógica para
personalizá-lo. Esse método é chamado quando o controle do Xamarin.Forms correspondente é criado.
3. Adicione um atributo ExportRenderer à classe do renderizador personalizado para especificar que ele será
usado para renderizar o controle personalizado do Xamarin.Forms. Esse atributo é usado para registrar o
renderizador personalizado no Xamarin.Forms.

NOTE
Para a maioria dos elementos do Xamarin.Forms, o fornecimento de um renderizador personalizado em cada projeto de
plataforma é opcional. Se um renderizador personalizado não estiver registrado, será usado o renderizador padrão da classe
base do controle. No entanto, são necessários renderizadores personalizados em cada projeto da plataforma durante a
renderização de um elemento View.

O diagrama a seguir ilustra as responsabilidades de cada projeto no aplicativo de exemplo, bem como as relações
entre elas:
O controle personalizado CameraPreview é renderizado por classes de renderizador específicas da plataforma, que
derivam da classe ViewRenderer para cada plataforma. Isso faz com que cada controle personalizado
CameraPreview seja renderizado com controles específicos da plataforma, conforme mostrado nas capturas de tela
seguir:

A classe ViewRenderer expõe o método OnElementChanged , que é chamado quando um controle personalizado do
Xamarin.Forms é criado para renderizar o controle nativo correspondente. Esse método usa um parâmetro
ElementChangedEventArgs , que contém as propriedades OldElement e NewElement . Essas propriedades representam
o elemento do Xamarin.Forms a que o renderizador estava anexado e o elemento a que o renderizador está
anexado, respectivamente. No aplicativo de exemplo, a propriedade OldElement será null e a propriedade
NewElement conterá uma referência à instância de CameraPreview .

Uma versão de substituição do método OnElementChanged , em cada classe de renderizador específica da


plataforma, é o lugar para realização da instanciação e da personalização do controle nativo. O método
SetNativeControl deve ser usado para instanciar o controle nativo e esse método também atribuirá a referência de
controle à propriedade Control . Além disso, é possível obter uma referência ao controle do Xamarin.Forms que
está sendo renderizado por meio da propriedade Element .
Em algumas circunstâncias, o método OnElementChanged pode ser chamado várias vezes. Portanto, para evitar
perdas de memória, é necessário ter cuidado ao instanciar um novo controle nativo. A abordagem a ser usada ao
instanciar um novo controle nativo em um renderizador personalizado é mostrada no exemplo de código a seguir:

protected override void OnElementChanged (ElementChangedEventArgs<NativeListView> e)


{
base.OnElementChanged (e);

if (Control == null) {
// Instantiate the native control and assign it to the Control property with
// the SetNativeControl method
}

if (e.OldElement != null) {
// Unsubscribe from event handlers and cleanup any resources
}

if (e.NewElement != null) {
// Configure the control and subscribe to event handlers
}
}
Um novo controle nativo deve ser instanciado apenas uma vez, quando a propriedade Control é null . O
controle deve ser configurado e os manipuladores de eventos devem ser inscritos apenas quando o renderizador
personalizado for anexado a um novo elemento Xamarin.Forms. Da mesma forma, a inscrição de quaisquer
manipuladores de evento inscritos só deve ser cancelada quando o elemento ao qual o renderizador está anexado
for alterado. Adotar essa abordagem ajudará a criar um renderizador personalizado com bom desempenho que
não sofre perdas de memória.
Cada classe de renderizador personalizado é decorada com um atributo ExportRenderer que registra o
renderizador no Xamarin.Forms. O atributo aceita dois parâmetros – o nome do tipo de controle personalizado do
Xamarin.Forms que está sendo renderizado e o nome do tipo de renderizador personalizado. O prefixo assembly
do atributo especifica que o atributo se aplica a todo o assembly.
As seções a seguir abordam a implementação de cada classe de renderizador personalizado específica da
plataforma.
Criando o renderizador personalizado no iOS
O exemplo de código a seguir mostra o renderizador personalizado para a plataforma iOS:

[assembly: ExportRenderer (typeof(CameraPreview), typeof(CameraPreviewRenderer))]


namespace CustomRenderer.iOS
{
public class CameraPreviewRenderer : ViewRenderer<CameraPreview, UICameraPreview>
{
UICameraPreview uiCameraPreview;

protected override void OnElementChanged (ElementChangedEventArgs<CameraPreview> e)


{
base.OnElementChanged (e);

if (Control == null) {
uiCameraPreview = new UICameraPreview (e.NewElement.Camera);
SetNativeControl (uiCameraPreview);
}
if (e.OldElement != null) {
// Unsubscribe
uiCameraPreview.Tapped -= OnCameraPreviewTapped;
}
if (e.NewElement != null) {
// Subscribe
uiCameraPreview.Tapped += OnCameraPreviewTapped;
}
}

void OnCameraPreviewTapped (object sender, EventArgs e)


{
if (uiCameraPreview.IsPreviewing) {
uiCameraPreview.CaptureSession.StopRunning ();
uiCameraPreview.IsPreviewing = false;
} else {
uiCameraPreview.CaptureSession.StartRunning ();
uiCameraPreview.IsPreviewing = true;
}
}
...
}
}

Desde que a propriedade Control seja null , o método SetNativeControl será chamado para instanciar um novo
controle UICameraPreview e para atribuir uma referência a ele para a propriedade Control . O controle
UICameraPreview é um controle personalizado específico da plataforma que usa as APIs AVCapture para fornecer o
fluxo de visualização da câmera. Ele expõe um evento Tapped que é manipulado pelo método
OnCameraPreviewTapped parar e iniciar a visualização do vídeo quando é tocado. O evento Tapped é assinado
quando o renderizador personalizado é anexado a um novo elemento do Xamarin.Forms e a assinatura é
cancelada apenas quando o elemento a que o renderizador está anexado é alterado.
Criando o renderizador personalizado no Android
O exemplo de código a seguir mostra o renderizador personalizado para a plataforma Android:

[assembly: ExportRenderer(typeof(CustomRenderer.CameraPreview), typeof(CameraPreviewRenderer))]


namespace CustomRenderer.Droid
{
public class CameraPreviewRenderer : ViewRenderer<CustomRenderer.CameraPreview,
CustomRenderer.Droid.CameraPreview>
{
CameraPreview cameraPreview;

public CameraPreviewRenderer(Context context) : base(context)


{
}

protected override void OnElementChanged(ElementChangedEventArgs<CustomRenderer.CameraPreview> e)


{
base.OnElementChanged(e);

if (Control == null)
{
cameraPreview = new CameraPreview(Context);
SetNativeControl(cameraPreview);
}

if (e.OldElement != null)
{
// Unsubscribe
cameraPreview.Click -= OnCameraPreviewClicked;
}
if (e.NewElement != null)
{
Control.Preview = Camera.Open((int)e.NewElement.Camera);

// Subscribe
cameraPreview.Click += OnCameraPreviewClicked;
}
}

void OnCameraPreviewClicked(object sender, EventArgs e)


{
if (cameraPreview.IsPreviewing)
{
cameraPreview.Preview.StopPreview();
cameraPreview.IsPreviewing = false;
}
else
{
cameraPreview.Preview.StartPreview();
cameraPreview.IsPreviewing = true;
}
}
...
}
}

Desde que a propriedade Control seja null , o método SetNativeControl será chamado para instanciar um novo
controle CameraPreview e para atribuir uma referência a ele para a propriedade Control . O controle
CameraPreview é um controle personalizado específico da plataforma que usa a API Camera para fornecer o fluxo
de visualização da câmera. O controle CameraPreview é configurado, desde que o renderizador personalizado
esteja anexado a um novo elemento do Xamarin.Forms. Essa configuração envolve a criação de um novo objeto
Camera nativo para acessar uma câmera de hardware específica e registrar um manipulador de eventos para
processar o evento Click . Por sua vez, esse manipulador parará e iniciará a visualização do vídeo quando for
tocado. O evento Click terá a assinatura cancelada se o elemento Xamarin.Forms a que o renderizador está
anexado for alterado.
Criando o renderizador personalizado na UWP
O exemplo de código a seguir mostra o renderizador personalizado para a UWP:

[assembly: ExportRenderer(typeof(CameraPreview), typeof(CameraPreviewRenderer))]


namespace CustomRenderer.UWP
{
public class CameraPreviewRenderer : ViewRenderer<CameraPreview, Windows.UI.Xaml.Controls.CaptureElement>
{
...
CaptureElement _captureElement;
bool _isPreviewing;

protected override void OnElementChanged(ElementChangedEventArgs<CameraPreview> e)


{
base.OnElementChanged(e);

if (Control == null)
{
...
_captureElement = new CaptureElement();
_captureElement.Stretch = Stretch.UniformToFill;

SetupCamera();
SetNativeControl(_captureElement);
}
if (e.OldElement != null)
{
// Unsubscribe
Tapped -= OnCameraPreviewTapped;
...
}
if (e.NewElement != null)
{
// Subscribe
Tapped += OnCameraPreviewTapped;
}
}

async void OnCameraPreviewTapped(object sender, TappedRoutedEventArgs e)


{
if (_isPreviewing)
{
await StopPreviewAsync();
}
else
{
await StartPreviewAsync();
}
}
...
}
}

Desde que a propriedade Control seja null , um novo CaptureElement será instanciado e o método SetupCamera
será chamado, que usa a API MediaCapture para fornecer o fluxo de visualização da câmera. Em seguida, o método
SetNativeControl é chamado para atribuir uma referência para a instância CaptureElement para a propriedade
Control . O controle CaptureElement expõe um evento Tapped que é manipulado pelo método
OnCameraPreviewTapped para parar e iniciar a visualização do vídeo quando é tocado. O evento Tapped é assinado
quando o renderizador personalizado é anexado a um novo elemento do Xamarin.Forms e a assinatura é
cancelada apenas quando o elemento a que o renderizador está anexado é alterado.

NOTE
É importante parar e descartar os objetos que fornecem acesso à câmera em um aplicativo da UWP. Deixar de fazer isso
pode interferir em outros aplicativos que tentam acessar a câmera do dispositivo. Para obter mais informações, confira Exibir
a visualização da câmera.

Resumo
Este artigo demonstrou como criar um renderizador personalizado para um controle personalizado do
Xamarin.Forms, que é usado para exibir um fluxo de vídeo de visualização com a câmera do dispositivo. Controles
da interface do usuário personalizadas do Xamarin.Forms devem derivar da classe View , que é usada para colocar
os layouts e controles na tela.

Links relacionados
CustomRendererView (amostra)
Implementando um HybridWebView
12/04/2019 • 30 minutes to read • Edit Online

Baixar o exemplo
Controles de interfaces do usuário personalizadas do Xamarin.Forms devem derivar da classe View, que é usada
para colocar os layouts e controles na tela. Este artigo demonstra como criar um renderizador personalizado para
um controle personalizado HybridWebView, que demonstra como aprimorar os controles da Web específicos a
uma plataforma para permitir que código C# seja invocado do JavaScript.
Cada exibição do Xamarin.Forms tem um renderizador que o acompanha para cada plataforma que cria uma
instância de um controle nativo. Quando um View é renderizado por um aplicativo Xamarin.Forms no iOS, é
criada uma instância da classe ViewRenderer , que, por sua vez, cria uma instância de um controle UIView nativo.
Na plataforma Android, a classe ViewRenderer cria uma instância de um controle View . Na UWP (Plataforma
Universal do Windows), a classe ViewRenderer cria uma instância de um controle FrameworkElement nativo. Para
obter mais informações sobre as classes de renderizador e de controle nativo para as quais os controles do
Xamarin.Forms são mapeadas, confira Classes base do renderizador e controles nativos.
O seguinte diagrama ilustra a relação entre o View e os controles nativos correspondentes que o implementam:

E possível usar o processo de renderização para implementar personalizações específicas da plataforma criando
um renderizador personalizado para um View em cada plataforma. O processo para fazer isso é o seguinte:
1. Criar o controle personalizado HybridWebView .
2. Consumir a HybridWebView do Xamarin.Forms.
3. Criar o renderizador personalizado para a página HybridWebView em cada plataforma.
Agora, abordaremos cada item separadamente para implementar um renderizador de HybridWebView que
aprimora os controles da Web específicos da plataforma para permitir que código C# seja invocado do JavaScript.
A instância de HybridWebView será usada para exibir uma página HTML que pede ao usuário para digitar seu
nome. Em seguida, quando o usuário clicar em um botão HTML, uma função de JavaScript invocará um Action
em C# que exibe um pop-up que contém o nome do usuário.
Para obter mais informações sobre o processo de invocar C# do JavaScript, confira Invocando C# do JavaScript.
Para obter mais informações sobre a página HTML, confira Criando a página da Web.

Criando o HybridWebView
É possível criar o controle personalizado HybridWebView criando subclasses da classe View , conforme mostrado
no exemplo de código a seguir:

public class HybridWebView : View


{
Action<string> action;
public static readonly BindableProperty UriProperty = BindableProperty.Create (
propertyName: "Uri",
returnType: typeof(string),
declaringType: typeof(HybridWebView),
defaultValue: default(string));

public string Uri {


get { return (string)GetValue (UriProperty); }
set { SetValue (UriProperty, value); }
}

public void RegisterAction (Action<string> callback)


{
action = callback;
}

public void Cleanup ()


{
action = null;
}

public void InvokeAction (string data)


{
if (action == null || data == null) {
return;
}
action.Invoke (data);
}
}

O controle personalizado HybridWebView é criado no projeto da biblioteca do .NET Standard e define a seguinte
API para o controle:
Uma propriedade Uri que especifica o endereço da página da Web a ser carregada.
Um método RegisterAction que registra um Action com o controle. A ação registrada será invocada do
JavaScript contido no arquivo HTML referenciado por meio da propriedade Uri .
Um método CleanUp que remove a referência ao Action registrado.
Um método InvokeAction que invoca o Action registrado. Esse método será chamado de um renderizador
personalizado em cada projeto específico da plataforma.

Consumindo o HybridWebView
O controle personalizado HybridWebView pode ser referenciado em XAML no projeto da biblioteca .NET Standard
declarando um namespace para sua localização e usando o prefixo do namespace no controle personalizado. O
exemplo de código a seguir mostra como o controle personalizado HybridWebView pode ser consumido por uma
página XAML:
<ContentPage ...
xmlns:local="clr-namespace:CustomRenderer;assembly=CustomRenderer"
x:Class="CustomRenderer.HybridWebViewPage"
Padding="0,20,0,0">
<ContentPage.Content>
<local:HybridWebView x:Name="hybridWebView" Uri="index.html"
HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" />
</ContentPage.Content>
</ContentPage>

O prefixo do namespace local pode ser qualquer nome. No entanto, os valores de clr-namespace e assembly
devem corresponder aos detalhes do controle personalizado. Quando o namespace é declarado, o prefixo é usado
para referenciar o controle personalizado.
O seguinte exemplo de código mostra como o controle personalizado HybridWebView pode ser consumido por um
página em C#:

public class HybridWebViewPageCS : ContentPage


{
public HybridWebViewPageCS ()
{
var hybridWebView = new HybridWebView {
Uri = "index.html",
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand
};
...
Padding = new Thickness (0, 20, 0, 0);
Content = hybridWebView;
}
}

A instância HybridWebView será usada para exibir um controle da Web nativo em cada plataforma. Sua propriedade
Uri é definida como um arquivo HTML armazenado em cada projeto específico da plataforma, que será exibido
pelo controle da Web nativo. O HTML renderizado solicita que o usuário insira seu nome, com uma função de
JavaScript invocando um Action C# em resposta a um clique no botão HTML.
O HybridWebViewPage registra a ação a ser invocada do JavaScript, conforme mostrado no exemplo de código a
seguir:

public partial class HybridWebViewPage : ContentPage


{
public HybridWebViewPage ()
{
...
hybridWebView.RegisterAction (data => DisplayAlert ("Alert", "Hello " + data, "OK"));
}
}

Essa ação chama o método DisplayAlert para exibir um pop-up modal que apresenta o nome inserido na página
HTML exibida pela instância de HybridWebView .
Agora, é possível adicionar um renderizador personalizado a cada projeto de aplicativo para aprimorar os
controles da Web específicos da plataforma, permitindo que o código C# seja invocado do JavaScript.

Criando o renderizador personalizado em cada plataforma


O processo para criar a classe do renderizador personalizado é o seguinte:
1. Crie uma subclasse da classe ViewRenderer<T1,T2> que renderiza o controle personalizado. O primeiro
argumento de tipo deve ser o controle personalizado a que o renderizador se aplica, neste caso, HybridWebView .
O segundo argumento de tipo deve ser o controle nativo que implementará a exibição personalizada.
2. Substitua o método OnElementChanged que renderiza o controle personalizado e escreva a lógica para
personalizá-lo. Esse método é chamado quando o controle personalizado do Xamarin.Forms correspondente é
criado.
3. Adicione um atributo ExportRenderer à classe do renderizador personalizado para especificar que ele será
usado para renderizar o controle personalizado do Xamarin.Forms. Esse atributo é usado para registrar o
renderizador personalizado no Xamarin.Forms.

NOTE
Para a maioria dos elementos do Xamarin.Forms, o fornecimento de um renderizador personalizado em cada projeto de
plataforma é opcional. Se um renderizador personalizado não estiver registrado, será usado o renderizador padrão da classe
base do controle. No entanto, são necessários renderizadores personalizados em cada projeto da plataforma durante a
renderização de um elemento View.

O seguinte diagrama ilustra as responsabilidades de cada projeto no aplicativo de exemplo, bem como as relações
entre elas:

O controle personalizado HybridWebView é renderizado por classes de renderizador específicas da plataforma, que
derivam da classe ViewRenderer para cada plataforma. Isso faz com que cada controle personalizado
HybridWebView seja renderizado com controles da Web específicos da plataforma, conforme mostrado nas
capturas de tela seguir:

A classe ViewRenderer expõe o método OnElementChanged , que é chamado quando um controle personalizado do
Xamarin.Forms é criado para renderizar o controle da Web nativo correspondente. Esse método usa um parâmetro
ElementChangedEventArgs , que contém as propriedades OldElement e NewElement . Essas propriedades representam
o elemento do Xamarin.Forms ao qual o renderizador estava anexado e o elemento do Xamarin.Forms ao qual o
renderizador está anexado, respectivamente. No aplicativo de exemplo, a propriedade OldElement será null e a
propriedade NewElement conterá uma referência à instância de HybridWebView .
Uma versão de substituição do método OnElementChanged , em cada classe de renderizador específica da
plataforma, é o lugar para realização da instanciação e da personalização do controle da Web nativo. O método
SetNativeControl deve ser usado para instanciar o controle da Web nativo e esse método também atribuirá a
referência de controle à propriedade Control . Além disso, é possível obter uma referência ao controle do
Xamarin.Forms que está sendo renderizado por meio da propriedade Element .
Em algumas circunstâncias, o método OnElementChanged pode ser chamado várias vezes. Portanto, para evitar
perdas de memória, é necessário ter cuidado ao instanciar um novo controle nativo. A abordagem a ser usada ao
instanciar um novo controle nativo em um renderizador personalizado é mostrada no exemplo de código a seguir:

protected override void OnElementChanged (ElementChangedEventArgs<NativeListView> e)


{
base.OnElementChanged (e);

if (Control == null) {
// Instantiate the native control and assign it to the Control property with
// the SetNativeControl method
}

if (e.OldElement != null) {
// Unsubscribe from event handlers and cleanup any resources
}

if (e.NewElement != null) {
// Configure the control and subscribe to event handlers
}
}

Um novo controle nativo deve ser instanciado apenas uma vez, quando a propriedade Control é null . O
controle deve ser configurado e os manipuladores de eventos devem ser inscritos apenas quando o renderizador
personalizado for anexado a um novo elemento Xamarin.Forms. Da mesma forma, a inscrição de quaisquer
manipuladores de evento inscritos só deve ser cancelada quando o elemento ao qual o renderizador está anexado
for alterado. Adotar essa abordagem ajudará a criar um renderizador personalizado com bom desempenho que
não sofre perdas de memória.
Cada classe de renderizador personalizado é decorada com um atributo ExportRenderer que registra o
renderizador no Xamarin.Forms. O atributo aceita dois parâmetros – o nome do tipo de controle personalizado do
Xamarin.Forms que está sendo renderizado e o nome do tipo de renderizador personalizado. O prefixo assembly
do atributo especifica que o atributo se aplica a todo o assembly.
As seções a seguir abordam a estrutura da página da Web carregada por cada controle da Web nativo, o processo
para invocar C# do JavaScript e a implementação disso em cada classe de renderizador personalizado específica
da plataforma.
Criando a página da Web
O exemplo de código a seguir mostra a página da Web que será exibida pelo controle personalizado
HybridWebView :
<html>
<body>
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<h1>HybridWebView Test</h1>
<br/>
Enter name: <input type="text" id="name">
<br/>
<br/>
<button type="button" onclick="javascript:invokeCSCode($('#name').val());">Invoke C# Code</button>
<br/>
<p id="result">Result:</p>
<script type="text/javascript">
function log(str)
{
$('#result').text($('#result').text() + " " + str);
}

function invokeCSCode(data) {
try {
log("Sending Data:" + data);
invokeCSharpAction(data);
}
catch (err){
log(err);
}
}
</script>
</body>
</html>

A página da Web permite que um usuário insira seu nome em um elemento input e fornece um elemento
button que invocará o código C# quando clicado. O processo para fazer isso é o seguinte:

Quando o usuário clica na elemento button , a função invokeCSCode de JavaScript é chamada, com o valor do
elemento input sendo passado para a função.
A função invokeCSCode chama a função log para exibir os dados que está enviando para o Action C#. Em
seguida, ela chama o método invokeCSharpAction para invocar o Action C#, passando o parâmetro recebido
do elemento input .

A função JavaScript invokeCSharpAction não está definida na página da Web e será injetada nela por cada
renderizador personalizado.
No iOS, esse arquivo HTML reside na pasta de conteúdo do projeto de plataforma, com uma ação de build
BundleResource. No Android, esse arquivo HTML reside na pasta de Ativos/Conteúdo do projeto de plataforma,
com uma ação de build AndroidAsset.
Invocando C# do JavaScript
O processo para invocar C# do JavaScript é idêntico em todas as plataformas:
O renderizador personalizado cria um controle da Web nativo e carrega o arquivo HTML especificado pela
propriedade HybridWebView.Uri .
Quando a página da Web é carregada, o renderizador personalizado injeta a função de JavaScript
invokeCSharpAction na página da Web.
Quando o usuário insere seu nome e clica no elemento button HTML, a função invokeCSCode é invocada, que,
por sua vez, invoca a função invokeCSharpAction .
A função invokeCSharpAction invoca um método no renderizador personalizado, que por sua vez invoca o
método HybridWebView.InvokeAction .
O método HybridWebView.InvokeAction invoca o Action registrado.
As seções a seguir abordam como esse processo é implementado em cada plataforma.
Criando o renderizador personalizado no iOS
O seguinte exemplo de código mostra o renderizador personalizado para a plataforma iOS:

[assembly: ExportRenderer (typeof(HybridWebView), typeof(HybridWebViewRenderer))]


namespace CustomRenderer.iOS
{
public class HybridWebViewRenderer : ViewRenderer<HybridWebView, WKWebView>, IWKScriptMessageHandler
{
const string JavaScriptFunction = "function invokeCSharpAction(data)
{window.webkit.messageHandlers.invokeAction.postMessage(data);}";
WKUserContentController userController;

protected override void OnElementChanged (ElementChangedEventArgs<HybridWebView> e)


{
base.OnElementChanged (e);

if (Control == null) {
userController = new WKUserContentController ();
var script = new WKUserScript (new NSString (JavaScriptFunction),
WKUserScriptInjectionTime.AtDocumentEnd, false);
userController.AddUserScript (script);
userController.AddScriptMessageHandler (this, "invokeAction");

var config = new WKWebViewConfiguration { UserContentController = userController };


var webView = new WKWebView (Frame, config);
SetNativeControl (webView);
}
if (e.OldElement != null) {
userController.RemoveAllUserScripts ();
userController.RemoveScriptMessageHandler ("invokeAction");
var hybridWebView = e.OldElement as HybridWebView;
hybridWebView.Cleanup ();
}
if (e.NewElement != null) {
string fileName = Path.Combine (NSBundle.MainBundle.BundlePath, string.Format ("Content/{0}",
Element.Uri));
Control.LoadRequest (new NSUrlRequest (new NSUrl (fileName, false)));
}
}

public void DidReceiveScriptMessage (WKUserContentController userContentController, WKScriptMessage


message)
{
Element.InvokeAction (message.Body.ToString ());
}
}
}

A classe HybridWebViewRenderer carrega a página da Web especificada na propriedade HybridWebView.Uri em um


controle WKWebView nativo e a função de JavaScript invokeCSharpAction é injetada na página da Web. Quando o
usuário insere seu nome e clica no elemento HTML button , a função de JavaScript invokeCSharpAction é
executada, com o método DidReceiveScriptMessage sendo chamado depois que uma mensagem é recebida da
página da Web. Por sua vez, esse método invoca o método HybridWebView.InvokeAction , que invoca a ação
registrada para exibir o pop-up.
Essa funcionalidade é obtida da seguinte maneira:
Desde que a propriedade Control seja null , as seguintes operações serão executadas:
Uma instância de WKUserContentController é criada, o que permite postar mensagens e injetar scripts do
usuário em uma página da Web.
Uma instância de WKUserScript é criada para injetar a função de JavaScript invokeCSharpAction na
página da Web após ela ser carregada.
O método WKUserContentController.AddUserScript adiciona a instância de WKUserScript ao controlador
de conteúdo.
O método WKUserContentController.AddScriptMessageHandler adiciona um manipulador de mensagens de
script denominado invokeAction à instância de WKUserContentController , o que fará com que a função
de JavaScript window.webkit.messageHandlers.invokeAction.postMessage(data) seja definida em todos os
quadros em todas as exibições da Web que usarão a instância de WKUserContentController .
Uma instância de WKWebViewConfiguration é criada, com a instância de WKUserContentController sendo
definida como o controlador de conteúdo.
Um controle WKWebView é instanciado e o método SetNativeControl é chamado para atribuir uma
referência ao controle WKWebView à propriedade Control .
Desde que o renderizador personalizado esteja anexado a um novo elemento do Xamarin.Forms:
O método WKWebView.LoadRequest carrega o arquivo HTML que é especificado pela propriedade
HybridWebView.Uri . O código especifica que o arquivo seja armazenado na pasta Content do projeto.
Após a página da Web ser exibida, a função de JavaScript invokeCSharpAction será injetada na página da
Web.
Quando o elemento a que o renderizador está anexado é alterado:
Recursos são liberados.

NOTE
A classe WKWebView tem suporte apenas no iOS 8 e posteriores.

Além disso, Info.plist deve ser atualizado para incluir os seguintes valores:

<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>

Criando o renderizador personalizado no Android


O seguinte exemplo de código mostra o renderizador personalizado para a plataforma Android:
[assembly: ExportRenderer(typeof(HybridWebView), typeof(HybridWebViewRenderer))]
namespace CustomRenderer.Droid
{
public class HybridWebViewRenderer : ViewRenderer<HybridWebView, Android.Webkit.WebView>
{
const string JavascriptFunction = "function invokeCSharpAction(data){jsBridge.invokeAction(data);}";
Context _context;

public HybridWebViewRenderer(Context context) : base(context)


{
_context = context;
}

protected override void OnElementChanged(ElementChangedEventArgs<HybridWebView> e)


{
base.OnElementChanged(e);

if (Control == null)
{
var webView = new Android.Webkit.WebView(_context);
webView.Settings.JavaScriptEnabled = true;
webView.SetWebViewClient(new JavascriptWebViewClient($"javascript: {JavascriptFunction}"));
SetNativeControl(webView);
}
if (e.OldElement != null)
{
Control.RemoveJavascriptInterface("jsBridge");
var hybridWebView = e.OldElement as HybridWebView;
hybridWebView.Cleanup();
}
if (e.NewElement != null)
{
Control.AddJavascriptInterface(new JSBridge(this), "jsBridge");
Control.LoadUrl($"file:///android_asset/Content/{Element.Uri}");
}
}
}
}

A classe HybridWebViewRenderer carrega a página da Web especificada na propriedade HybridWebView.Uri em um


controle WebView nativo e a função de JavaScript invokeCSharpAction é injetada na página da Web, após a página
da Web terminar de ser carregada, com a substituição OnPageFinished na classe JavascriptWebViewClient :

public class JavascriptWebViewClient : WebViewClient


{
string _javascript;

public JavascriptWebViewClient(string javascript)


{
_javascript = javascript;
}

public override void OnPageFinished(WebView view, string url)


{
base.OnPageFinished(view, url);
view.EvaluateJavascript(_javascript, null);
}
}

Quando o usuário insere seu nome e clica no elemento HTML button , a função de JavaScript invokeCSharpAction
é executada. Essa funcionalidade é obtida da seguinte maneira:
Desde que a propriedade Control seja null , as seguintes operações serão executadas:
Uma instância de nativa é criada, o JavaScript é habilitado no controle e uma instância de
WebView
JavascriptWebViewClient é definida como a implementação de WebViewClient .
O método SetNativeControl é chamado para atribuir uma referência ao controle WebView nativo à
propriedade Control .
Desde que o renderizador personalizado esteja anexado a um novo elemento do Xamarin.Forms:
O método WebView.AddJavascriptInterface injeta uma nova instância de JSBridge no quadro principal
do contexto do JavaScript do WebView, denominando-a jsBridge . Isso permite que métodos na classe
JSBridge sejam acessados do JavaScript.
O método WebView.LoadUrl carrega o arquivo HTML que é especificado pela propriedade
HybridWebView.Uri . O código especifica que o arquivo seja armazenado na pasta Content do projeto.
Na classe JavascriptWebViewClient , a função de JavaScript invokeCSharpAction é injetada na página da
Web depois que a página termina de ser carregada.
Quando o elemento a que o renderizador está anexado é alterado:
Recursos são liberados.
Quando a função de JavaScript invokeCSharpAction é executada, por sua vez, ela invoca o método
JSBridge.InvokeAction , que é mostrado no exemplo de código a seguir:

public class JSBridge : Java.Lang.Object


{
readonly WeakReference<HybridWebViewRenderer> hybridWebViewRenderer;

public JSBridge (HybridWebViewRenderer hybridRenderer)


{
hybridWebViewRenderer = new WeakReference <HybridWebViewRenderer> (hybridRenderer);
}

[JavascriptInterface]
[Export ("invokeAction")]
public void InvokeAction (string data)
{
HybridWebViewRenderer hybridRenderer;

if (hybridWebViewRenderer != null && hybridWebViewRenderer.TryGetTarget (out hybridRenderer))


{
hybridRenderer.Element.InvokeAction (data);
}
}
}

A classe deve derivar de Java.Lang.Object , e os métodos que são expostos para o JavaScript devem ser decorados
com os atributos [JavascriptInterface] e [Export] . Portanto, quando a função de JavaScript invokeCSharpAction
é injetada na página da Web e é executada, ela chama o método JSBridge.InvokeAction por ter sido decorada com
os atributos [JavascriptInterface] e [Export("invokeAction")] . Por sua vez, o método InvokeAction invoca o
método HybridWebView.InvokeAction , que invoca a ação registrada para exibir o pop-up.

NOTE
Projetos que usam o atributo [Export] devem incluir uma referência a Mono.Android.Export , ou ocorrerá um erro no
compilador.

Observe que a classe JSBridge mantém um WeakReference para a classe HybridWebViewRenderer . A finalidade é
evitar a criação de uma referência circular entre as duas classes. Para obter mais informações, conste Referências
Fracas no MSDN.
Criando o renderizador personalizado na UWP
O seguinte exemplo de código mostra o renderizador personalizado para o UWP:

[assembly: ExportRenderer(typeof(HybridWebView), typeof(HybridWebViewRenderer))]


namespace CustomRenderer.UWP
{
public class HybridWebViewRenderer : ViewRenderer<HybridWebView, Windows.UI.Xaml.Controls.WebView>
{
const string JavaScriptFunction = "function invokeCSharpAction(data){window.external.notify(data);}";

protected override void OnElementChanged(ElementChangedEventArgs<HybridWebView> e)


{
base.OnElementChanged(e);

if (Control == null)
{
SetNativeControl(new Windows.UI.Xaml.Controls.WebView());
}
if (e.OldElement != null)
{
Control.NavigationCompleted -= OnWebViewNavigationCompleted;
Control.ScriptNotify -= OnWebViewScriptNotify;
}
if (e.NewElement != null)
{
Control.NavigationCompleted += OnWebViewNavigationCompleted;
Control.ScriptNotify += OnWebViewScriptNotify;
Control.Source = new Uri(string.Format("ms-appx-web:///Content//{0}", Element.Uri));
}
}

async void OnWebViewNavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)


{
if (args.IsSuccess)
{
// Inject JS script
await Control.InvokeScriptAsync("eval", new[] { JavaScriptFunction });
}
}

void OnWebViewScriptNotify(object sender, NotifyEventArgs e)


{
Element.InvokeAction(e.Value);
}
}
}

A classe HybridWebViewRenderer carrega a página da Web especificada na propriedade HybridWebView.Uri em um


controle WebView nativo e a função de JavaScript invokeCSharpAction é injetada na página da Web, após a página
da Web ser carregada, com o método WebView.InvokeScriptAsync . Quando o usuário insere seu nome e clica no
elemento HTML button , a função de JavaScript invokeCSharpAction é executada, com o método
OnWebViewScriptNotify sendo chamado depois que uma notificação é recebida da página da Web. Por sua vez, esse
método invoca o método HybridWebView.InvokeAction , que invoca a ação registrada para exibir o pop-up.
Essa funcionalidade é obtida da seguinte maneira:
Desde que a propriedade Control seja null , as seguintes operações serão executadas:
O método SetNativeControl é chamado para instanciar um novo controle WebView nativo e para atribuir
uma referência a ele para a propriedade Control .
Desde que o renderizador personalizado esteja anexado a um novo elemento do Xamarin.Forms:
Manipuladores de eventos para os eventos NavigationCompleted e ScriptNotify são registrados. O
evento NavigationCompleted é acionado quando o controle nativo WebView termina de carregar o
conteúdo atual ou quando a navegação falha. O evento ScriptNotify é acionado quando o conteúdo no
controle WebView nativo usa JavaScript para passar uma cadeia de caracteres para o aplicativo. A página
da Web aciona o evento ScriptNotify chamando window.external.notify ao passar um parâmetro
string .
A propriedade WebView.Source é definida como o URI do arquivo HTML que é especificado pela
propriedade HybridWebView.Uri . O código presume que o arquivo seja armazenado na pasta Content do
projeto. Depois que a página da Web é exibida, o evento NavigationCompleted é acionado e o método
OnWebViewNavigationCompleted é invocado. A função de JavaScript invokeCSharpAction , em seguida, será
injetada na página da Web com o método WebView.InvokeScriptAsync , desde que a navegação tenha sido
concluída com êxito.
Quando o elemento a que o renderizador está anexado é alterado:
A assinatura dos eventos é cancelada.

Resumo
Este artigo demonstrou como criar um renderizador personalizado para um controle personalizado HybridWebView
, que demonstra como aprimorar os controles da Web específicos a uma plataforma para permitir que código C#
seja invocado do JavaScript.

Links relacionados
CustomRendererHybridWebView (amostra)
Chamar C# do JavaScript
Implementar um player de vídeo
12/04/2019 • 5 minutes to read • Edit Online

Baixar o exemplo
Às vezes é desejável reproduzir arquivos de vídeo em um aplicativo Xamarin.Forms. Esta série de artigos aborda
como criar renderizadores personalizados para iOS, Android e o UWP (Plataforma Universal do Windows) para
uma classe do Xamarin.Forms denominada VideoPlayer .
Na amostra VideoPlayerDemos, todos os arquivos que implementam e dão suporte a VideoPlayer estão em
pastas denominadas FormsVideoLibrary e identificadas com o namespace FormsVideoLibrary ou namespaces que
começam com FormsVideoLibrary . Essa organização e nomenclatura devem tornar fácil copiar os arquivos do
player de vídeo para sua própria solução do Xamarin.Forms.
VideoPlayer pode reproduzir arquivos de vídeo de três tipos de fontes:
A Internet, usando uma URL
Um recurso inserido no aplicativo da plataforma
A biblioteca de vídeos do dispositivo
Players de vídeo exigem controles de transporte, que são botões para reproduzir e pausar o vídeo e uma barra de
posicionamento que mostra o andamento no vídeo e permite que o usuário passe rapidamente para um tempo
diferente. VideoPlayer pode usar controles de transporte e a barra de posicionamento fornecidos pela plataforma
(como mostrado abaixo), ou você pode fornecer controles de transporte e uma barra de posicionamento
personalizados. Aqui está o programa em execução no iOS, no Android e na Plataforma Universal do Windows:

É claro que você pode deitar o telefone para obter uma exibição ampliada.
Um player de vídeo mais sofisticado tem alguns recursos adicionais, como controle de volume e um mecanismo
para interromper o vídeo quando chega uma chamada, bem como um meio de manter a tela ativa durante a
reprodução.
A série de artigos a seguir mostra progressivamente como os renderizadores de plataforma e as classes de
suporte são criados:
Criar os players de vídeo de plataforma
Cada plataforma requer uma classe VideoPlayerRenderer que cria e mantém um controle de player de vídeo
compatível com a plataforma. Este artigo mostra a estrutura das classes do renderizador e o modo como os
players são criados.

Reproduzir um vídeo da Web


A fonte mais comum de vídeos para um player de vídeo é provavelmente a Internet. Este artigo descreve como
um vídeo da Web pode ser referenciado e usado como uma fonte para o player de vídeo.

Associando fontes de vídeo ao player


Este artigo usa um ListView para apresentar uma coleção de vídeos para reproduzir. Um programa mostra como
o arquivo code-behind pode definir a fonte de vídeo do player de vídeo, mas um segundo programa mostra como
você pode usar a associação de dados entre o ListView e o player de vídeo.

Carregar vídeos de recursos do aplicativo


Vídeos podem ser inseridos como recursos nos projetos de plataforma. Este artigo mostra como armazenar esses
recursos e depois carregá-los no programa a ser reproduzido pelo player de vídeo.

Acessar a biblioteca de vídeos do dispositivo


Quando um vídeo é criado usando a câmera do dispositivo, o arquivo de vídeo é armazenado na biblioteca de
imagens do dispositivo. Este artigo mostra como acessar o seletor de imagem do dispositivo para selecionar o
vídeo e, em seguida, executá-lo usando o player de vídeo.

Controles personalizados de transporte de vídeo


Embora os players de vídeo em cada plataforma forneçam seus próprios controles de transporte na forma de
botões para Reproduzir e Pausar, você pode suprimir a exibição desses botões e fornecer os seus próprios. Este
artigo mostra como fazê-lo.

Posicionamento de vídeo personalizado


Cada um dos players de vídeo da plataforma tem uma barra de posição que mostra o progresso do vídeo e
permite que você avance ou retroceda para uma determinada posição. Este artigo demonstra como você pode
substituir essa barra de posição com um controle personalizado.

Links relacionados
Demonstrações do player de vídeo (amostra)
Criando os players de vídeo de plataforma
12/04/2019 • 13 minutes to read • Edit Online

[![DBaixar a amostra](~/media/shared/download.png) Baixar a amostra]


(https://developer.xamarin.com/samples/xamarin-forms/customrenderers/VideoPlayerDemos/)
A solução VideoPlayerDemos contém todo o código para implementar um player de vídeo para o
Xamarin.Forms. Também inclui uma série de páginas que demonstram como usar o player de vídeo em um
aplicativo. Todo o código VideoPlayer e seus renderizadores de plataforma residem em pastas de projeto
chamadas FormsVideoLibrary e também usam o namespace FormsVideoLibrary . Isso deve facilitar a cópia dos
arquivos em seu próprio aplicativo e a referência das classes.

O player de vídeo
A classe VideoPlayer faz parte da biblioteca do .NET Standard VideoPlayerDemos que é compartilhada entre as
plataformas. Ela deriva de View :

using System;
using Xamarin.Forms;

namespace FormsVideoLibrary
{
public class VideoPlayer : View, IVideoPlayerController
{
···
}
}

Os membros dessa classe (e a interface IVideoPlayerController ) são descritos nos artigos a seguir.
Cada uma das plataformas contém uma classe chamada VideoPlayerRenderer que contém o código específico da
plataforma para implementar um player de vídeo. A tarefa principal desse renderizador é criar um player de vídeo
para essa plataforma.
O controlador de exibição do player do iOS
Várias classes estão envolvidas ao implementar um player de vídeo no iOS. O aplicativo primeiro cria um
AVPlayerViewController e, em seguida, define a propriedade Player como um objeto do tipo AVPlayer . Classes
adicionais são necessárias quando o player recebe uma fonte de vídeo.
Como todos os renderizadores, o VideoPlayerRenderer do iOS contém um atributo ExportRenderer que identifica
a exibição VideoPlayer com o renderizador:
using System;
using System.ComponentModel;
using System.IO;

using AVFoundation;
using AVKit;
using CoreMedia;
using Foundation;
using UIKit;

using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(FormsVideoLibrary.VideoPlayer),
typeof(FormsVideoLibrary.iOS.VideoPlayerRenderer))]

namespace FormsVideoLibrary.iOS
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, UIView>
{
···
}
}

Geralmente, um renderizador que define um controle de plataforma deriva da classe


ViewRenderer<View, NativeView> , em que View é o derivado View do Xamarin.Forms (nesse caso, VideoPlayer ) e
NativeView é um derivado UIView do iOS para a classe de renderizador. Para esse renderizador, esse argumento
genérico é apenas definido como UIView , por motivos que você verá em breve.
Quando um renderizador se basear em um derivado de UIViewController (como esse), a classe deverá substituir a
propriedade ViewController e retornar o controlador de exibição, neste caso, AVPlayerViewController . Essa é a
finalidade do campo _playerViewController :
namespace FormsVideoLibrary.iOS
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, UIView>
{
AVPlayer player;
AVPlayerItem playerItem;
AVPlayerViewController _playerViewController; // solely for ViewController property

public override UIViewController ViewController => _playerViewController;

protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)


{
base.OnElementChanged(args);

if (args.NewElement != null)
{
if (Control == null)
{
// Create AVPlayerViewController
_playerViewController = new AVPlayerViewController();

// Set Player property to AVPlayer


player = new AVPlayer();
_playerViewController.Player = player;

// Use the View from the controller as the native control


SetNativeControl(_playerViewController.View);
}
···
}
}
···
}
}

A principal responsabilidade da substituição OnElementChanged é verificar se a propriedade Control é null e,


nesse caso, criar um controle de plataforma e passá-lo para o método SetNativeControl . Nesse caso, esse objeto
só está disponível na propriedade View do AVPlayerViewController . Por acaso, esse derivado de UIView é uma
classe particular chamada AVPlayerView , mas como é particular, ela não pode ser explicitamente especificada como
o segundo argumento genérico para ViewRenderer .
Geralmente, a propriedade Control da classe de renderizador depois disso se refere à UIView usada para
implementar o renderizador, mas nesse caso, a propriedade Control não é usada em nenhum outro lugar.
A exibição de vídeo do Android
O renderizador do Android para o VideoPlayer se baseia na classe VideoView do Android. No entanto, se
VideoView é usado por si só para reproduzir um vídeo em um aplicativo Xamarin.Forms, o vídeo preenche a área
alocada para o VideoPlayer sem manter a taxa de proporção correta. Por esse motivo (como você verá em breve),
a VideoView se torna um filho de um RelativeLayout do Android. Uma diretiva using define ARelativeLayout
para distingui-lo do RelativeLayout do Xamarin.Forms e esse é o segundo argumento genérico no ViewRenderer :
using System;
using System.ComponentModel;
using System.IO;

using Android.Content;
using Android.Media;
using Android.Widget;
using ARelativeLayout = Android.Widget.RelativeLayout;

using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

[assembly: ExportRenderer(typeof(FormsVideoLibrary.VideoPlayer),
typeof(FormsVideoLibrary.Droid.VideoPlayerRenderer))]

namespace FormsVideoLibrary.Droid
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, ARelativeLayout>
{
···
public VideoPlayerRenderer(Context context) : base(context)
{
}
···
}
}

Do Xamarin.Forms 2.5 em diante, os renderizadores do Android devem incluir um construtor com um argumento
Context .

A substituição OnElementChanged cria a VideoView e o RelativeLayout e define os parâmetros de layout para a


VideoView , a fim de centralizá-la dentro do RelativeLayout .
namespace FormsVideoLibrary.Droid
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, ARelativeLayout>
{
VideoView videoView;
MediaController mediaController; // Used to display transport controls
bool isPrepared;
···
protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)
{
base.OnElementChanged(args);

if (args.NewElement != null)
{
if (Control == null)
{
// Save the VideoView for future reference
videoView = new VideoView(Context);

// Put the VideoView in a RelativeLayout


ARelativeLayout relativeLayout = new ARelativeLayout(Context);
relativeLayout.AddView(videoView);

// Center the VideoView in the RelativeLayout


ARelativeLayout.LayoutParams layoutParams =
new ARelativeLayout.LayoutParams(LayoutParams.MatchParent, LayoutParams.MatchParent);
layoutParams.AddRule(LayoutRules.CenterInParent);
videoView.LayoutParameters = layoutParams;

// Handle a VideoView event


videoView.Prepared += OnVideoViewPrepared;

// Use the RelativeLayout as the native control


SetNativeControl(relativeLayout);
}
···
}
···
}

protected override void Dispose(bool disposing)


{
if (Control != null && videoView != null)
{
videoView.Prepared -= OnVideoViewPrepared;
}
base.Dispose(disposing);
}

void OnVideoViewPrepared(object sender, EventArgs args)


{
isPrepared = true;
···
}
···
}
}

Um manipulador para o evento Prepared é anexado a esse método e desanexado do método Dispose . Esse
evento é disparado quando a VideoView tem informações suficientes para começar a reprodução de um arquivo
de vídeo.
O elemento de mídia do UWP
No UWP (Plataforma Universal do Windows), o player de vídeo mais comum é o MediaElement . Essa
documentação do MediaElement indica que o MediaPlayerElement deve ser usado quando só é necessário dar
suporte a versões do Windows 10 começando pelo build 1607.
A substituição OnElementChanged precisa criar um MediaElement , definir alguns manipuladores de eventos e passar
o objeto MediaElement para SetNativeControl :

using System;
using System.ComponentModel;

using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;

using Xamarin.Forms;
using Xamarin.Forms.Platform.UWP;

[assembly: ExportRenderer(typeof(FormsVideoLibrary.VideoPlayer),
typeof(FormsVideoLibrary.UWP.VideoPlayerRenderer))]

namespace FormsVideoLibrary.UWP
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, MediaElement>
{
protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)
{
base.OnElementChanged(args);

if (args.NewElement != null)
{
if (Control == null)
{
MediaElement mediaElement = new MediaElement();
SetNativeControl(mediaElement);

mediaElement.MediaOpened += OnMediaElementMediaOpened;
mediaElement.CurrentStateChanged += OnMediaElementCurrentStateChanged;
}
···
}
···
}

protected override void Dispose(bool disposing)


{
if (Control != null)
{
Control.MediaOpened -= OnMediaElementMediaOpened;
Control.CurrentStateChanged -= OnMediaElementCurrentStateChanged;
}

base.Dispose(disposing);
}
···
}
}

Os dois manipuladores de eventos são desanexados no evento Dispose para o renderizador.

Mostrando os controles de transporte


Todos os players de vídeo incluídos nas plataformas dão suporte a um conjunto padrão de controles de transporte
que incluem botões para reproduzir e pausar, bem como uma barra para indicar a posição atual no vídeo e para
mover para uma nova posição.
A classe VideoPlayer define uma propriedade chamada AreTransportControlsEnabled e define o valor padrão
como true :

namespace FormsVideoLibrary
{
public class VideoPlayer : View, IVideoPlayerController
{
···
// AreTransportControlsEnabled property
public static readonly BindableProperty AreTransportControlsEnabledProperty =
BindableProperty.Create(nameof(AreTransportControlsEnabled), typeof(bool), typeof(VideoPlayer),
true);

public bool AreTransportControlsEnabled


{
set { SetValue(AreTransportControlsEnabledProperty, value); }
get { return (bool)GetValue(AreTransportControlsEnabledProperty); }
}
···
}
}

Embora essa propriedade tenha os acessadores set e get , o renderizador precisa lidar com casos somente
quando a propriedade está definida. O acessador get apenas retorna o valor atual da propriedade.
Propriedades como AreTransportControlsEnabled são tratadas em renderizadores de plataforma de duas maneiras:
A primeira vez é quando o Xamarin.Forms cria um elemento VideoPlayer . Isso é indicado na substituição
OnElementChanged do renderizador quando a propriedade NewElement não é null . Neste momento, o
renderizador pode definir seu próprio player de vídeo da plataforma com base no valor inicial da
propriedade, conforme definido no VideoPlayer .
Se a propriedade em VideoPlayer for alterada posteriormente, o método OnElementPropertyChanged no
renderizador será chamado. Isso permite que o renderizador atualize o player de vídeo da plataforma com
base na nova configuração de propriedade.
As seções a seguir abordam como a propriedade AreTransportControlsEnabled é tratada em cada plataforma.
Controles de reprodução do iOS
A propriedade do AVPlayerViewController do iOS que controla a exibição dos controles de transporte é
ShowsPlaybackControls . É assim como essa propriedade é definida no VideoViewRenderer do iOS:
namespace FormsVideoLibrary.iOS
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, UIView>
{
···
AVPlayerViewController _playerViewController; // solely for ViewController property

public override UIViewController ViewController => _playerViewController;

protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)


{
···
if (args.NewElement != null)
{
···
SetAreTransportControlsEnabled();
···
}
}

protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args)


{
base.OnElementPropertyChanged(sender, args);

if (args.PropertyName == VideoPlayer.AreTransportControlsEnabledProperty.PropertyName)
{
SetAreTransportControlsEnabled();
}
···
}

void SetAreTransportControlsEnabled()
{
((AVPlayerViewController)ViewController).ShowsPlaybackControls =
Element.AreTransportControlsEnabled;
}
···
}
}

A propriedade Element do renderizador refere-se à classe VideoPlayer .


O controlador de mídia do Android
No Android, a exibição dos controles de transporte exige a criação de um objeto MediaController e sua associação
com o objeto VideoView . A mecânica é demonstrada no método SetAreTransportControlsEnabled :
namespace FormsVideoLibrary.Droid
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, ARelativeLayout>
{
VideoView videoView;
MediaController mediaController; // Used to display transport controls
bool isPrepared;

protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)


{
···
if (args.NewElement != null)
{
···
SetAreTransportControlsEnabled();
···
}
}

protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args)


{
base.OnElementPropertyChanged(sender, args);

if (args.PropertyName == VideoPlayer.AreTransportControlsEnabledProperty.PropertyName)
{
SetAreTransportControlsEnabled();
}
···
}

void SetAreTransportControlsEnabled()
{
if (Element.AreTransportControlsEnabled)
{
mediaController = new MediaController(Context);
mediaController.SetMediaPlayer(videoView);
videoView.SetMediaController(mediaController);
}
else
{
videoView.SetMediaController(null);

if (mediaController != null)
{
mediaController.SetMediaPlayer(null);
mediaController = null;
}
}
}
···
}
}

A propriedade de Controles de Transporte do UWP


O MediaElement do UWP define uma propriedade chamada AreTransportControlsEnabled , de modo que a
propriedade seja definida com base na propriedade VideoPlayer de mesmo nome:
namespace FormsVideoLibrary.UWP
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, MediaElement>
{
protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)
{
···
if (args.NewElement != null)
{
···
SetAreTransportControlsEnabled();
···
}
}

protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args)


{
base.OnElementPropertyChanged(sender, args);

if (args.PropertyName == VideoPlayer.AreTransportControlsEnabledProperty.PropertyName)
{
SetAreTransportControlsEnabled();
}
···
}

void SetAreTransportControlsEnabled()
{
Control.AreTransportControlsEnabled = Element.AreTransportControlsEnabled;
}
···
}
}

Mais uma propriedade é necessária para iniciar a reprodução do vídeo: Essa é a propriedade Source crucial que
faz referência a um arquivo de vídeo. A implementação da propriedade Source é descrita no próximo artigo,
Reproduzindo um vídeo da Web.

Links relacionados
Demonstrações do player de vídeo (exemplo)
Reproduzindo um vídeo da Web
12/04/2019 • 14 minutes to read • Edit Online

[![DBaixar a amostra](~/media/shared/download.png) Baixar a amostra]


(https://developer.xamarin.com/samples/xamarin-forms/customrenderers/VideoPlayerDemos/)
A classe VideoPlayer define uma propriedade Source usada para especificar a origem do arquivo de vídeo, bem
como uma propriedade AutoPlay . AutoPlay Tem uma configuração padrão igual a true , o que significa que o
vídeo deve iniciar a reprodução automaticamente após a definição de Source :

using System;
using Xamarin.Forms;

namespace FormsVideoLibrary
{
public class VideoPlayer : View, IVideoPlayerController
{
···
// Source property
public static readonly BindableProperty SourceProperty =
BindableProperty.Create(nameof(Source), typeof(VideoSource), typeof(VideoPlayer), null);

[TypeConverter(typeof(VideoSourceConverter))]
public VideoSource Source
{
set { SetValue(SourceProperty, value); }
get { return (VideoSource)GetValue(SourceProperty); }
}

// AutoPlay property
public static readonly BindableProperty AutoPlayProperty =
BindableProperty.Create(nameof(AutoPlay), typeof(bool), typeof(VideoPlayer), true);

public bool AutoPlay


{
set { SetValue(AutoPlayProperty, value); }
get { return (bool)GetValue(AutoPlayProperty); }
}
···
}
}

A propriedade Source é do tipo VideoSource , que é padronizado após a classe abstrata ImageSource do
Xamarin.Forms e seus três derivados UriImageSource , FileImageSource e StreamImageSource . No entanto,
nenhuma opção de fluxo está disponível para o VideoPlayer , pois o iOS e o Android não dão suporte à
reprodução de um vídeo de um fluxo.

Fontes de vídeo
A classe abstrata VideoSource consiste exclusivamente em três métodos estáticos que criam uma instância das
três classes que derivam de VideoSource :
namespace FormsVideoLibrary
{
[TypeConverter(typeof(VideoSourceConverter))]
public abstract class VideoSource : Element
{
public static VideoSource FromUri(string uri)
{
return new UriVideoSource() { Uri = uri };
}

public static VideoSource FromFile(string file)


{
return new FileVideoSource() { File = file };
}

public static VideoSource FromResource(string path)


{
return new ResourceVideoSource() { Path = path };
}
}
}

A classe UriVideoSource é usada para especificar um arquivo de vídeo para download com um URI. Ela define
uma única propriedade do tipo string :

namespace FormsVideoLibrary
{
public class UriVideoSource : VideoSource
{
public static readonly BindableProperty UriProperty =
BindableProperty.Create(nameof(Uri), typeof(string), typeof(UriVideoSource));

public string Uri


{
set { SetValue(UriProperty, value); }
get { return (string)GetValue(UriProperty); }
}
}
}

A manipulação de objetos do tipo UriVideoSource é descrita abaixo.


A classe ResourceVideoSource é usada para acessar os arquivos de vídeo armazenados como recursos inseridos
no aplicativo da plataforma, também especificado com uma propriedade string :

namespace FormsVideoLibrary
{
public class ResourceVideoSource : VideoSource
{
public static readonly BindableProperty PathProperty =
BindableProperty.Create(nameof(Path), typeof(string), typeof(ResourceVideoSource));

public string Path


{
set { SetValue(PathProperty, value); }
get { return (string)GetValue(PathProperty); }
}
}
}

A manipulação de objetos do tipo ResourceVideoSource é descrita no artigo Carregando vídeos de recursos do


aplicativo. A classe VideoPlayer não têm recursos para carregar um arquivo de vídeo armazenado como um
recurso na biblioteca do .NET Standard.
A classe FileVideoSource é usada para acessar os arquivos de vídeo da biblioteca de vídeos do dispositivo. A
única propriedade também é do tipo string :

namespace FormsVideoLibrary
{
public class FileVideoSource : VideoSource
{
public static readonly BindableProperty FileProperty =
BindableProperty.Create(nameof(File), typeof(string), typeof(FileVideoSource));

public string File


{
set { SetValue(FileProperty, value); }
get { return (string)GetValue(FileProperty); }
}
}
}

A manipulação de objetos do tipo FileVideoSource é descrita no artigo Acessando a biblioteca de vídeos do


dispositivo.
A classe VideoSource inclui um atributo TypeConverter que referencia VideoSourceConverter :

namespace FormsVideoLibrary
{
[TypeConverter(typeof(VideoSourceConverter))]
public abstract class VideoSource : Element
{
···
}
}

Este conversor de tipo é invocado quando a propriedade Source é definida como uma cadeia de caracteres em
XAML. Esta é a classe VideoSourceConverter :

namespace FormsVideoLibrary
{
public class VideoSourceConverter : TypeConverter
{
public override object ConvertFromInvariantString(string value)
{
if (!String.IsNullOrWhiteSpace(value))
{
Uri uri;
return Uri.TryCreate(value, UriKind.Absolute, out uri) && uri.Scheme != "file" ?
VideoSource.FromUri(value) : VideoSource.FromResource(value);
}

throw new InvalidOperationException("Cannot convert null or whitespace to ImageSource");


}
}
}

O método ConvertFromInvariantString tenta converter a cadeia de caracteres em um objeto Uri . Se houver êxito
e o esquema não for file: , o método retornará uma UriVideoSource . Caso contrário, ele retornará uma
ResourceVideoSource .
Definindo a fonte de vídeo
Toda a outra lógica que envolve fontes de vídeo é implementada nos renderizadores de plataforma individual. As
seções a seguir mostram como os renderizadores de plataforma reproduzem vídeos quando a propriedade
Source é definida como um objeto UriVideoSource .

A fonte de vídeo do iOS


Duas seções do VideoPlayerRenderer estão envolvidas na definição da fonte de vídeo do player de vídeo. Quando
o Xamarin.Forms cria pela primeira vez um objeto do tipo VideoPlayer , o método OnElementChanged é chamado
com a propriedade NewElement do objeto de argumentos definida como esse VideoPlayer . O método
OnElementChanged chama SetSource :

namespace FormsVideoLibrary.iOS
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, UIView>
{
···
protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)
{
···
if (args.NewElement != null)
{
···
SetSource();
···
}
}

protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args)


{
···
else if (args.PropertyName == VideoPlayer.SourceProperty.PropertyName)
{
SetSource();
}
···
}
···
}
}

Posteriormente, quando a propriedade Source é alterada, o método OnElementPropertyChanged é chamado com


uma propriedade PropertyName igual a "Origem", e SetSource é chamado novamente.
Para reproduzir um arquivo de vídeo no iOS, um objeto do tipo AVAsset é criado primeiro para encapsular o
arquivo de vídeo e ele é usado para criar um AVPlayerItem , que é então transferido para o objeto AVPlayer . É
desta forma que o método SetSource manipula a propriedade Source quando ela é do tipo UriVideoSource :
namespace FormsVideoLibrary.iOS
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, UIView>
{
AVPlayer player;
AVPlayerItem playerItem;
···
void SetSource()
{
AVAsset asset = null;

if (Element.Source is UriVideoSource)
{
string uri = (Element.Source as UriVideoSource).Uri;

if (!String.IsNullOrWhiteSpace(uri))
{
asset = AVAsset.FromUrl(new NSUrl(uri));
}
}
···
if (asset != null)
{
playerItem = new AVPlayerItem(asset);
}
else
{
playerItem = null;
}

player.ReplaceCurrentItemWithPlayerItem(playerItem);

if (playerItem != null && Element.AutoPlay)


{
player.Play();
}
}
···
}
}

A propriedade AutoPlay não tem nenhuma comparação nas classes de vídeo do iOS e, portanto, a propriedade é
examinada no final do método SetSource para chamar o método Play no objeto AVPlayer .
Em alguns casos, os vídeos continuaram a execução depois que a página com o VideoPlayer foi direcionada para
a home page. Para interromper o vídeo, o ReplaceCurrentItemWithPlayerItem também é definido na substituição
Dispose :
namespace FormsVideoLibrary.iOS
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, UIView>
{
···
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);

if (player != null)
{
player.ReplaceCurrentItemWithPlayerItem(null);
}
}
···
}
}

A fonte de vídeo do Android


O VideoPlayerRenderer do Android precisa definir a fonte do player de vídeo quando o VideoPlayer é criado pela
primeira vez e, posteriormente, quando a propriedade Source é alterada:

namespace FormsVideoLibrary.Droid
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, ARelativeLayout>
{
···
protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)
{
···
if (args.NewElement != null)
{
···
SetSource();
···
}
}
···
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args)
{
···
else if (args.PropertyName == VideoPlayer.SourceProperty.PropertyName)
{
SetSource();
}
···
}
···
}
}

O método SetSource manipula objetos do tipo UriVideoSource chamando SetVideoUri na VideoView com um
objeto Uri do Android criado com base no URI da cadeia de caracteres. A classe Uri é totalmente qualificada
aqui para distingui-la da classe Uri do .NET:
namespace FormsVideoLibrary.Droid
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, ARelativeLayout>
{
···
void SetSource()
{
isPrepared = false;
bool hasSetSource = false;

if (Element.Source is UriVideoSource)
{
string uri = (Element.Source as UriVideoSource).Uri;

if (!String.IsNullOrWhiteSpace(uri))
{
videoView.SetVideoURI(Android.Net.Uri.Parse(uri));
hasSetSource = true;
}
}
···

if (hasSetSource && Element.AutoPlay)


{
videoView.Start();
}
}
···
}
}

O VideoView do Android não tem uma propriedade AutoPlay correspondente e, portanto, o método Start é
chamado se um novo vídeo foi definido.
Há uma diferença entre o comportamento dos renderizadores do iOS e do Android se a propriedade Source de
VideoPlayer é definida como null ou se a propriedade Uri de UriVideoSource é definida como null ou uma
cadeia de caracteres em branco. Se o player de vídeo do iOS estiver reproduzindo um vídeo no momento e
Source for definido como null (ou a cadeia de caracteres for null ou em branco),
ReplaceCurrentItemWithPlayerItem será chamado com o valor null . O vídeo atual será substituído e a execução
será interrompida.
O Android não dá suporte a um recurso semelhante. Se a propriedade Source estiver definida como null ,o
método SetSource apenas a ignorará e o vídeo atual continuará sendo reproduzido.
A fonte de vídeo do UWP
O MediaElement do UWP define uma propriedade AutoPlay , que é manipulada no renderizador como qualquer
outra propriedade:
namespace FormsVideoLibrary.UWP
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, MediaElement>
{
protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)
{
···
if (args.NewElement != null)
{
···
SetSource();
SetAutoPlay();
···
}
}

protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args)


{
···
else if (args.PropertyName == VideoPlayer.SourceProperty.PropertyName)
{
SetSource();
}
else if (args.PropertyName == VideoPlayer.AutoPlayProperty.PropertyName)
{
SetAutoPlay();
}
···
}
···
}
}

A propriedade SetSource manipula um objeto UriVideoSource definindo a propriedade Source de MediaElement


como um valor Uri do .NET ou como null se a propriedade Source de VideoPlayer está definida como null :
namespace FormsVideoLibrary.UWP
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, MediaElement>
{
···
async void SetSource()
{
bool hasSetSource = false;

if (Element.Source is UriVideoSource)
{
string uri = (Element.Source as UriVideoSource).Uri;

if (!String.IsNullOrWhiteSpace(uri))
{
Control.Source = new Uri(uri);
hasSetSource = true;
}
}
···
if (!hasSetSource)
{
Control.Source = null;
}
}

void SetAutoPlay()
{
Control.AutoPlay = Element.AutoPlay;
}
···
}
}

Definindo uma fonte de URL


Com a implementação dessas propriedades nos três renderizadores, é possível reproduzir um vídeo de uma fonte
de URL. A página Reproduzir um vídeo da Web no programa VideoPlayDemos é definida pelo seguinte
arquivo XAML:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:video="clr-namespace:FormsVideoLibrary"
x:Class="VideoPlayerDemos.PlayWebVideoPage"
Title="Play Web Video">

<video:VideoPlayer Source="https://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4" />

</ContentPage>

A classe VideoSourceConverter converte a cadeia de caracteres em uma UriVideoSource . Quando você navega
para a página Reproduzir um vídeo da Web, o vídeo começa a ser carregado e inicia a execução quando uma
quantidade suficiente de dados é baixada e armazenada em buffer. O vídeo tem cerca de 10 minutos:
Em cada uma das plataformas, os controles de transporte esmaecem se não são usados, mas podem ser
restaurados para exibição com um toque no vídeo.
Você pode impedir que o vídeo seja iniciado automaticamente definindo a propriedade AutoPlay como false :

<video:VideoPlayer Source="https://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4"
AutoPlay="false" />

Você precisará pressionar o botão Reproduzir para iniciar o vídeo.


Da mesma forma, você pode suprimir a exibição dos controles de transporte definindo a propriedade
AreTransportControlsEnabled como false :

<video:VideoPlayer Source="https://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4"
AreTransportControlsEnabled="False" />

Se você definir ambas as propriedades como false , o vídeo não começará a execução e não haverá nenhuma
maneira de iniciá-lo. Você precisará chamar Play no arquivo code-behind ou criar seus próprios controles de
transporte, conforme descrito no artigo Implementando controles de transporte de vídeo personalizados.
O arquivo App.xaml inclui recursos para dois vídeos adicionais:
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:video="clr-namespace:FormsVideoLibrary"
x:Class="VideoPlayerDemos.App">
<Application.Resources>
<ResourceDictionary>

<video:UriVideoSource x:Key="ElephantsDream"
Uri="https://archive.org/download/ElephantsDream/ed_hd_512kb.mp4" />

<video:UriVideoSource x:Key="BigBuckBunny"
Uri="https://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4"
/>

<video:UriVideoSource x:Key="Sintel"
Uri="https://archive.org/download/Sintel/sintel-2048-stereo_512kb.mp4" />

</ResourceDictionary>
</Application.Resources>
</Application>

Para referenciar um desses outros filmes, substitua a URL explícita no arquivo PlayWebVideo.xaml com uma
extensão de marcação StaticResource . Nesse caso, VideoSourceConverter não é necessário para criar o objeto
UriVideoSource :

<video:VideoPlayer Source="{StaticResource ElephantsDream}" />

Como alternativa, você pode definir a propriedade Source em um arquivo de vídeo em uma ListView , conforme
descrito no próximo artigo, Associando fontes de vídeo ao player.

Links relacionados
Demonstrações do player de vídeo (exemplo)
Associando fontes de vídeo ao player
12/04/2019 • 3 minutes to read • Edit Online

Baixar o exemplo
Quando a propriedade Source da exibição VideoPlayer for definida como um novo arquivo de vídeo, o vídeo
existente interromperá a execução e o novo vídeo será iniciado. Isso é demonstrado pela página Selecionar
vídeo da Web do exemplo VideoPlayerDemos. A página inclui um ListView com os títulos dos três vídeos
referenciados no arquivo App.xaml:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:video="clr-namespace:FormsVideoLibrary"
x:Class="VideoPlayerDemos.SelectWebVideoPage"
Title="Select Web Video">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>

<video:VideoPlayer x:Name="videoPlayer"
Grid.Row="0" />

<ListView Grid.Row="1"
ItemSelected="OnListViewItemSelected">
<ListView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Elephant's Dream</x:String>
<x:String>Big Buck Bunny</x:String>
<x:String>Sintel</x:String>
</x:Array>
</ListView.ItemsSource>
</ListView>
</Grid>
</ContentPage>

Quando um vídeo for selecionado, o manipulador de eventos ItemSelected no arquivo code-behind será
executado. O manipulador remove quaisquer espaços em branco e apóstrofos do título e usa isso como uma
chave para obter um dos recursos definidos no arquivo App.xaml. Esse objeto UriVideoSource é definido como a
propriedade Source do VideoPlayer .
namespace VideoPlayerDemos
{
public partial class SelectWebVideoPage : ContentPage
{
public SelectWebVideoPage()
{
InitializeComponent();
}

void OnListViewItemSelected(object sender, SelectedItemChangedEventArgs args)


{
if (args.SelectedItem != null)
{
string key = ((string)args.SelectedItem).Replace(" ", "").Replace("'", "");
videoPlayer.Source = (UriVideoSource)Application.Current.Resources[key];
}
}
}
}

Quando a página é carregada pela primeira vez, nenhum item é selecionado no ListView ; portanto, é necessário
selecionar um para que o vídeo comece a ser reproduzido:

A propriedade Source de VideoPlayer é apoiada por uma propriedade associável, o que significa que ela pode
ser o destino de uma associação de dados. Isso é demonstrado pela página Associar a VideoPlayer. A marcação
no arquivo BindToVideoPlayer.xaml é compatível com a seguinte classe que encapsula um título de um vídeo e
um objeto VideoSource correspondente:

namespace VideoPlayerDemos
{
public class VideoInfo
{
public string DisplayName { set; get; }

public VideoSource VideoSource { set; get; }

public override string ToString()


{
return DisplayName;
}
}
}
O ListView no arquivo BindToVideoPlayer.xaml contém uma matriz desses objetos VideoInfo , cada uma
inicializada com um título do vídeo e o objeto UriVideoSource do dicionário de recursos em App.xaml:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:VideoPlayerDemos"
xmlns:video="clr-namespace:FormsVideoLibrary"
x:Class="VideoPlayerDemos.BindToVideoPlayerPage"
Title="Bind to VideoPlayer">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>

<video:VideoPlayer x:Name="videoPlayer"
Grid.Row="0"
Source="{Binding Source={x:Reference listView},
Path=SelectedItem.VideoSource}" />

<ListView x:Name="listView"
Grid.Row="1">
<ListView.ItemsSource>
<x:Array Type="{x:Type local:VideoInfo}">
<local:VideoInfo DisplayName="Elephant's Dream"
VideoSource="{StaticResource ElephantsDream}" />

<local:VideoInfo DisplayName="Big Buck Bunny"


VideoSource="{StaticResource BigBuckBunny}" />

<local:VideoInfo DisplayName="Sintel"
VideoSource="{StaticResource Sintel}" />
</x:Array>
</ListView.ItemsSource>
</ListView>
</Grid>
</ContentPage>

A propriedade Source do VideoPlayer está associada ao ListView . O Path da associação é especificado como
SelectedItem.VideoSource , que é um demarcador composto que consiste em duas propriedades: SelectedItem é
uma propriedade de ListView . O item selecionado é do tipo VideoInfo , que tem uma propriedade VideoSource .
Assim como acontece com a primeira página Selecionar vídeo da Web, nenhum item é inicialmente selecionado
no ListView ; portanto, é necessário selecionar um dos vídeos antes de começar a reproduzi-lo.

Links relacionados
Demonstrações do player de vídeo (amostra)
Carregando vídeos de recursos do aplicativo
12/04/2019 • 7 minutes to read • Edit Online

Baixar o exemplo
Os renderizadores personalizados para a exibição VideoPlayer podem reproduzir arquivos de vídeo que foram
inseridos nos projetos da plataforma individual como recursos do aplicativo. No entanto, a versão atual do
VideoPlayer não pode acessar os recursos inseridos em uma biblioteca do .NET Standard.

Para carregar esses recursos, crie uma instância da ResourceVideoSource definindo a propriedade Path com o
nome de arquivo (ou o nome de arquivo e a pasta) do recurso. Como alternativa, você pode chamar o método
estático VideoSource.FromResource para referenciar o recurso. Em seguida, defina o objeto ResourceVideoSource
como a propriedade Source de VideoPlayer .

Armazenando os arquivos de vídeo


O armazenamento de um arquivo de vídeo no projeto da plataforma é diferente para cada plataforma.
Recursos de vídeo do iOS
Em um projeto do iOS, você pode armazenar um vídeo na pasta Resources ou em uma subpasta da pasta
Resources. O arquivo de vídeo precisa ter uma Build Action igual a BundleResource . Defina a propriedade Path
de ResourceVideoSource com o nome doe arquivo, por exemplo, MyFile.mp4 para um arquivo na pasta
Resources, ou MyFolder/MyFile.mp4, em que MyFolder é uma subpasta de Resources.
Na solução VideoPlayerDemos, o projeto VideoPlayerDemos.iOS contém uma subpasta de Resources
chamada Videos, que contém um arquivo chamado iOSApiVideo.mp4. Esse é um breve vídeo que mostra
como usar o site do Xamarin para encontrar a documentação da classe AVPlayerViewController do iOS.
Recursos de vídeo do Android
Em um projeto do Android, os vídeos precisam ser armazenados em uma subpasta de Resources chamada raw.
A pasta raw não pode conter subpastas. Dê ao arquivo de vídeo uma Build Action igual a AndroidResource .
Defina a propriedade Path de ResourceVideoSource com o nome de arquivo, por exemplo, MyFile.mp4.
O projeto VideoPlayerDemos.Android contém uma subpasta de Resources chamada raw, que contém um
arquivo chamado AndroidApiVideo.mp4.
Recursos de vídeo do UWP
Em um projeto da Plataforma Universal do Windows, você pode armazenar vídeos em qualquer pasta do projeto.
Dê ao arquivo uma Build Action igual a Content . Defina a propriedade Path de ResourceVideoSource como a
pasta e o nome de arquivo, por exemplo, MyFolder/MyVideo.mp4.
O projeto VideoPlayerDemos.UWP contém uma pasta chamada Videos com o arquivo UWPApiVideo.mp4.

Carregando os arquivos de vídeo


Cada uma das classes de renderizador da plataforma contém um código em seu método SetSource para
carregamento de arquivos de vídeo armazenados como recursos.
Carregamento de recursos do iOS
A versão do iOS do VideoPlayerRenderer usa o método GetUrlForResource de NSBundle para carregar o recurso.
O caminho completo precisa ser dividido em um nome de arquivo, uma extensão e um diretório. O código usa a
classe Path no namespace System.IO do .NET para dividir o caminho do arquivo nestes componentes:

namespace FormsVideoLibrary.iOS
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, UIView>
{
···
void SetSource()
{
AVAsset asset = null;
···
else if (Element.Source is ResourceVideoSource)
{
string path = (Element.Source as ResourceVideoSource).Path;

if (!String.IsNullOrWhiteSpace(path))
{
string directory = Path.GetDirectoryName(path);
string filename = Path.GetFileNameWithoutExtension(path);
string extension = Path.GetExtension(path).Substring(1);
NSUrl url = NSBundle.MainBundle.GetUrlForResource(filename, extension, directory);
asset = AVAsset.FromUrl(url);
}
}
···
}
···
}
}

Carregamento de recursos do Android


O VideoPlayerRenderer do Android usa o nome de arquivo e o nome de pacote para construir um objeto Uri . O
nome de pacote é o nome do aplicativo, neste caso, VideoPlayerDemos.Android, que pode ser obtido da
propriedade estática Context.PackageName . O objeto Uri resultante é então passado para o método SetVideoURI
de VideoView :
namespace FormsVideoLibrary.Droid
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, ARelativeLayout>
{
···
void SetSource()
{
isPrepared = false;
bool hasSetSource = false;
···
else if (Element.Source is ResourceVideoSource)
{
string package = Context.PackageName;
string path = (Element.Source as ResourceVideoSource).Path;

if (!String.IsNullOrWhiteSpace(path))
{
string filename = Path.GetFileNameWithoutExtension(path).ToLowerInvariant();
string uri = "android.resource://" + package + "/raw/" + filename;
videoView.SetVideoURI(Android.Net.Uri.Parse(uri));
hasSetSource = true;
}
}
···
}
···
}
}

Carregamento de recursos do UWP


O VideoPlayerRenderer do UWP constrói um objeto Uri para o caminho e o define com a propriedade Source
de MediaElement :

namespace FormsVideoLibrary.UWP
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, MediaElement>
{
···
async void SetSource()
{
bool hasSetSource = false;
···
else if (Element.Source is ResourceVideoSource)
{
string path = "ms-appx:///" + (Element.Source as ResourceVideoSource).Path;

if (!String.IsNullOrWhiteSpace(path))
{
Control.Source = new Uri(path);
hasSetSource = true;
}
}
}
···
}
}

Reproduzindo o arquivo de recurso


A página Reproduzir recurso de vídeo da solução VideoPlayerDemos usa a classe OnPlatform para
especificar o arquivo de vídeo para cada plataforma:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:video="clr-namespace:FormsVideoLibrary"
x:Class="VideoPlayerDemos.PlayVideoResourcePage"
Title="Play Video Resource">
<video:VideoPlayer>
<video:VideoPlayer.Source>
<video:ResourceVideoSource>
<video:ResourceVideoSource.Path>
<OnPlatform x:TypeArguments="x:String">
<On Platform="iOS" Value="Videos/iOSApiVideo.mp4" />
<On Platform="Android" Value="AndroidApiVideo.mp4" />
<On Platform="UWP" Value="Videos/UWPApiVideo.mp4" />
</OnPlatform>
</video:ResourceVideoSource.Path>
</video:ResourceVideoSource>
</video:VideoPlayer.Source>
</video:VideoPlayer>
</ContentPage>

Se o recurso do iOS está armazenado na pasta Resources e se o recurso do UWP está armazenado na pasta raiz
do projeto, você pode usar o mesmo nome de arquivo para cada plataforma. Se esse for o caso, você poderá
definir esse nome diretamente como a propriedade Source de VideoPlayer .
Esta é a página em execução:

Agora você já viu como carregar vídeos de um URI da Web e como reproduzir recursos inseridos. Além disso,
você pode carregar vídeos da biblioteca de vídeos do dispositivo.

Links relacionados
Demonstrações do player de vídeo (amostra)
Acessando a biblioteca de vídeos do dispositivo
12/04/2019 • 9 minutes to read • Edit Online

Baixar o exemplo
A maioria dos computadores desktop e dispositivos móveis modernos tem a capacidade de gravar vídeos usando
a câmera do dispositivo. Em seguida, os vídeos criados por um usuário são armazenados como arquivos no
dispositivo. Esses arquivos podem ser recuperados da biblioteca de imagens e reproduzidos pela classe
VideoPlayer , assim como qualquer outro vídeo.

O serviço de dependência do seletor de foto


Cada uma das plataformas inclui um recurso que permite ao usuário selecionar uma foto ou um vídeo da
biblioteca de imagens do dispositivo. A primeira etapa na reprodução de um vídeo da biblioteca de imagens do
dispositivo é criar um serviço de dependência que invoque o seletor de imagem em cada plataforma. O serviço
de dependência descrito abaixo é muito semelhante ao definido no artigo Escolhendo uma foto na biblioteca
de imagens, exceto que o seletor de vídeo retorna um nome de arquivo em vez de um objeto Stream .
O projeto da biblioteca do .NET Standard define uma interface chamada IVideoPicker para o serviço de
dependência:

namespace FormsVideoLibrary
{
public interface IVideoPicker
{
Task<string> GetVideoFileAsync();
}
}

Cada uma das plataformas contém uma classe chamada VideoPicker que implementa essa interface.
O seletor de vídeo do iOS
O VideoPicker do iOS usa o UIImagePickerController do iOS para acessar a biblioteca de imagens, especificando
que ela deve ser restrita a vídeos (conhecidos como "filmes") na propriedade MediaType do iOS. Observe que
VideoPicker implementa explicitamente a interface IVideoPicker . Observe também o atributo Dependency que
identifica essa classe como um serviço de dependência. Esses são os dois requisitos que permitem que o
Xamarin.Forms encontre o serviço de dependência no projeto da plataforma:
using System;
using System.Threading.Tasks;
using UIKit;
using Xamarin.Forms;

[assembly: Dependency(typeof(FormsVideoLibrary.iOS.VideoPicker))]

namespace FormsVideoLibrary.iOS
{
public class VideoPicker : IVideoPicker
{
TaskCompletionSource<string> taskCompletionSource;
UIImagePickerController imagePicker;

public Task<string> GetVideoFileAsync()


{
// Create and define UIImagePickerController
imagePicker = new UIImagePickerController
{
SourceType = UIImagePickerControllerSourceType.SavedPhotosAlbum,
MediaTypes = new string[] { "public.movie" }
};

// Set event handlers


imagePicker.FinishedPickingMedia += OnImagePickerFinishedPickingMedia;
imagePicker.Canceled += OnImagePickerCancelled;

// Present UIImagePickerController;
UIWindow window = UIApplication.SharedApplication.KeyWindow;
var viewController = window.RootViewController;
viewController.PresentModalViewController(imagePicker, true);

// Return Task object


taskCompletionSource = new TaskCompletionSource<string>();
return taskCompletionSource.Task;
}

void OnImagePickerFinishedPickingMedia(object sender, UIImagePickerMediaPickedEventArgs args)


{
if (args.MediaType == "public.movie")
{
taskCompletionSource.SetResult(args.MediaUrl.AbsoluteString);
}
else
{
taskCompletionSource.SetResult(null);
}
imagePicker.DismissModalViewController(true);
}

void OnImagePickerCancelled(object sender, EventArgs args)


{
taskCompletionSource.SetResult(null);
imagePicker.DismissModalViewController(true);
}
}
}

O seletor de vídeo do Android


A implementação do Android de IVideoPicker exige um método de retorno de chamada que faz parte da
atividade do aplicativo. Por esse motivo, a classe MainActivity define duas propriedades, um campo e um
método de retorno de chamada:
namespace VideoPlayerDemos.Droid
{
···
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle bundle)
{
Current = this;
···
}

// Field, properties, and method for Video Picker


public static MainActivity Current { private set; get; }

public static readonly int PickImageId = 1000;

public TaskCompletionSource<string> PickImageTaskCompletionSource { set; get; }

protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)


{
base.OnActivityResult(requestCode, resultCode, data);

if (requestCode == PickImageId)
{
if ((resultCode == Result.Ok) && (data != null))
{
// Set the filename as the completion of the Task
PickImageTaskCompletionSource.SetResult(data.DataString);
}
else
{
PickImageTaskCompletionSource.SetResult(null);
}
}
}
}
}

O método OnCreate em MainActivity armazena sua própria instância na propriedade estática Current . Isso
permite a implementação de IVideoPicker para obter a instância MainActivity a fim de iniciar o seletor
Selecionar Vídeo:
using System;
using System.Threading.Tasks;
using Android.Content;
using Xamarin.Forms;

// Need application's MainActivity


using VideoPlayerDemos.Droid;

[assembly: Dependency(typeof(FormsVideoLibrary.Droid.VideoPicker))]

namespace FormsVideoLibrary.Droid
{
public class VideoPicker : IVideoPicker
{
public Task<string> GetVideoFileAsync()
{
// Define the Intent for getting images
Intent intent = new Intent();
intent.SetType("video/*");
intent.SetAction(Intent.ActionGetContent);

// Get the MainActivity instance


MainActivity activity = MainActivity.Current;

// Start the picture-picker activity (resumes in MainActivity.cs)


activity.StartActivityForResult(
Intent.CreateChooser(intent, "Select Video"),
MainActivity.PickImageId);

// Save the TaskCompletionSource object as a MainActivity property


activity.PickImageTaskCompletionSource = new TaskCompletionSource<string>();

// Return Task object


return activity.PickImageTaskCompletionSource.Task;
}
}
}

As adições ao objeto MainActivity são o único código na solução VideoPlayerDemos, em que o código normal
do aplicativo precisa ser alterado para dar suporte às classes FormsVideoLibrary .
O seletor de vídeo do UWP
A implementação do UWP da interface IVideoPicker usa o FileOpenPicker do UWP. Ela inicia a pesquisa de
arquivo com a biblioteca de imagens e restringe os tipos de arquivo a MP4 e WMV (Vídeo do Windows Media):
using System;
using System.Threading.Tasks;
using Windows.Storage;
using Windows.Storage.Pickers;
using Xamarin.Forms;

[assembly: Dependency(typeof(FormsVideoLibrary.UWP.VideoPicker))]

namespace FormsVideoLibrary.UWP
{
public class VideoPicker : IVideoPicker
{
public async Task<string> GetVideoFileAsync()
{
// Create and initialize the FileOpenPicker
FileOpenPicker openPicker = new FileOpenPicker
{
ViewMode = PickerViewMode.Thumbnail,
SuggestedStartLocation = PickerLocationId.PicturesLibrary
};

openPicker.FileTypeFilter.Add(".wmv");
openPicker.FileTypeFilter.Add(".mp4");

// Get a file and return the path


StorageFile storageFile = await openPicker.PickSingleFileAsync();
return storageFile?.Path;
}
}
}

Invocando o serviço de dependência


A página Reproduzir vídeo da biblioteca do programa VideoPlayerDemos demonstra como usar o serviço
de dependência do seletor de vídeo. O arquivo XAML contém uma instância VideoPlayer e um Button rotulado
Mostrar biblioteca de vídeos:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:video="clr-namespace:FormsVideoLibrary"
x:Class="VideoPlayerDemos.PlayLibraryVideoPage"
Title="Play Library Video">
<StackLayout>
<video:VideoPlayer x:Name="videoPlayer"
VerticalOptions="FillAndExpand" />

<Button Text="Show Video Library"


Margin="10"
HorizontalOptions="Center"
Clicked="OnShowVideoLibraryClicked" />
</StackLayout>
</ContentPage>

O arquivo code-behind contém o manipulador Clicked para o Button . A invocação do serviço de dependência
exige uma chamada a DependencyService.Get para obter a implementação de uma interface IVideoPicker no
projeto da plataforma. O método GetVideoFileAsync é então chamado nessa instância:
namespace VideoPlayerDemos
{
public partial class PlayLibraryVideoPage : ContentPage
{
public PlayLibraryVideoPage()
{
InitializeComponent();
}

async void OnShowVideoLibraryClicked(object sender, EventArgs args)


{
Button btn = (Button)sender;
btn.IsEnabled = false;

string filename = await DependencyService.Get<IVideoPicker>().GetVideoFileAsync();

if (!String.IsNullOrWhiteSpace(filename))
{
videoPlayer.Source = new FileVideoSource
{
File = filename
};
}

btn.IsEnabled = true;
}
}
}

Em seguida, o manipulador Clicked usa esse nome de arquivo para criar um objeto FileVideoSource e defini-lo
como a propriedade Source do VideoPlayer .
Cada uma das classes VideoPlayerRenderer contém um código em seu método SetSource para objetos do tipo
FileVideoSource . Elas são mostradas abaixo:

Manipulando arquivos do iOS


A versão do iOS do VideoPlayerRenderer processa objetos FileVideoSource usando o método estático
Asset.FromUrl com o nome de arquivo. Isso cria um objeto AVAsset que representa o arquivo na biblioteca de
imagens do dispositivo:
namespace FormsVideoLibrary.iOS
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, UIView>
{
···
void SetSource()
{
AVAsset asset = null;
···
else if (Element.Source is FileVideoSource)
{
string uri = (Element.Source as FileVideoSource).File;

if (!String.IsNullOrWhiteSpace(uri))
{
asset = AVAsset.FromUrl(new NSUrl(uri));
}
}
···
}
···
}
}

Manipulando arquivos do Android


Durante o processamento de objetos do tipo FileVideoSource , a implementação do Android de
VideoPlayerRenderer usa o método SetVideoPath de VideoView para especificar o arquivo na biblioteca de
imagens do dispositivo:

namespace FormsVideoLibrary.Droid
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, ARelativeLayout>
{
···
void SetSource()
{
isPrepared = false;
bool hasSetSource = false;
···
else if (Element.Source is FileVideoSource)
{
string filename = (Element.Source as FileVideoSource).File;

if (!String.IsNullOrWhiteSpace(filename))
{
videoView.SetVideoPath(filename);
hasSetSource = true;
}
}
···
}
···
}
}

Manipulando arquivos do UWP


Ao manipular objetos do tipo FileVideoSource , a implementação do UWP do método SetSource precisa criar um
objeto StorageFile , abrir esse arquivo para leitura e passar o objeto de fluxo para o método SetSource do
MediaElement :
namespace FormsVideoLibrary.UWP
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, MediaElement>
{
protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)
{
···
async void SetSource()
{
bool hasSetSource = false;
···
else if (Element.Source is FileVideoSource)
{
// Code requires Pictures Library in Package.appxmanifest Capabilities to be enabled
string filename = (Element.Source as FileVideoSource).File;

if (!String.IsNullOrWhiteSpace(filename))
{
StorageFile storageFile = await StorageFile.GetFileFromPathAsync(filename);
IRandomAccessStreamWithContentType stream = await storageFile.OpenReadAsync();
Control.SetSource(stream, storageFile.ContentType);
hasSetSource = true;
}
}
···
}
···
}
}

Para cada plataforma, o vídeo começa a ser reproduzido quase que imediatamente após a origem do vídeo ser
definida, porque o arquivo está no dispositivo e não precisa ser baixado.

Links relacionados
Demonstrações do player de vídeo (amostra)
Escolhendo uma foto da biblioteca de imagens
Controles personalizados de transporte de vídeo
16/04/2019 • 17 minutes to read • Edit Online

Baixar o exemplo
Os controles de transporte de um player de vídeo incluem os botões que executam as funções Reproduzir,
Pausar e Parar. Em geral, esses botões são identificados com ícones conhecidos, em vez de um texto, e as funções
Reproduzir e Pausar geralmente são combinadas em um botão.
Por padrão, o VideoPlayer exibe controles de transporte compatíveis com cada plataforma. Quando você define a
propriedade AreTransportControlsEnabled como false , esses controles são suprimidos. Em seguida, você pode
controlar o VideoPlayer de forma programática ou fornecer seus próprios controles de transporte.

Os métodos Play, Pause e Stop


A classe VideoPlayer define três métodos chamados Play , Pause e Stop que são implementados pelo
acionamento de eventos:

namespace FormsVideoLibrary
{
public class VideoPlayer : View, IVideoPlayerController
{
···
public event EventHandler PlayRequested;

public void Play()


{
PlayRequested?.Invoke(this, EventArgs.Empty);
}

public event EventHandler PauseRequested;

public void Pause()


{
PauseRequested?.Invoke(this, EventArgs.Empty);
}

public event EventHandler StopRequested;

public void Stop()


{
StopRequested?.Invoke(this, EventArgs.Empty);
}
}
}

Os manipuladores de eventos para esses eventos são definidos pela classe VideoPlayerRenderer em cada
plataforma, conforme mostrado abaixo:
Implementações de transporte do iOS
A versão do iOS de VideoPlayerRenderer usa o método OnElementChanged para definir manipuladores para esses
três eventos quando a propriedade NewElement não é null e desanexa os manipuladores de eventos quando
OldElement não é null :
namespace FormsVideoLibrary.iOS
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, UIView>
{
AVPlayer player;
···
protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)
{
···
if (args.NewElement != null)
{
···
args.NewElement.PlayRequested += OnPlayRequested;
args.NewElement.PauseRequested += OnPauseRequested;
args.NewElement.StopRequested += OnStopRequested;
}

if (args.OldElement != null)
{
···
args.OldElement.PlayRequested -= OnPlayRequested;
args.OldElement.PauseRequested -= OnPauseRequested;
args.OldElement.StopRequested -= OnStopRequested;
}
}
···
// Event handlers to implement methods
void OnPlayRequested(object sender, EventArgs args)
{
player.Play();
}

void OnPauseRequested(object sender, EventArgs args)


{
player.Pause();
}

void OnStopRequested(object sender, EventArgs args)


{
player.Pause();
player.Seek(new CMTime(0, 1));
}
}
}

Os manipuladores de eventos são implementados com uma chamada aos métodos no objeto AVPlayer . Não há
nenhum método Stop para AVPlayer e, portanto, ele é simulado com a pausa do vídeo e movimentação da
posição para o início.
Implementações de transporte do Android
A implementação do Android é semelhante à implementação do iOS. Os manipuladores para as três funções são
definidos quando NewElement não é null e é desanexado quando OldElement não é null :
namespace FormsVideoLibrary.Droid
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, ARelativeLayout>
{
VideoView videoView;
···
protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)
{
···
if (args.NewElement != null)
{
···
args.NewElement.PlayRequested += OnPlayRequested;
args.NewElement.PauseRequested += OnPauseRequested;
args.NewElement.StopRequested += OnStopRequested;
}

if (args.OldElement != null)
{
···
args.OldElement.PlayRequested -= OnPlayRequested;
args.OldElement.PauseRequested -= OnPauseRequested;
args.OldElement.StopRequested -= OnStopRequested;
}
}
···
void OnPlayRequested(object sender, EventArgs args)
{
videoView.Start();
}

void OnPauseRequested(object sender, EventArgs args)


{
videoView.Pause();
}

void OnStopRequested(object sender, EventArgs args)


{
videoView.StopPlayback();
}
}
}

As três funções chamam os métodos definidos pela VideoView .


Implementações de transporte do UWP
A implementação do UWP das três funções de transporte é muito semelhante às implementações do iOS e do
Android:
namespace FormsVideoLibrary.UWP
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, MediaElement>
{
protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)
{
···
if (args.NewElement != null)
{
···
args.NewElement.PlayRequested += OnPlayRequested;
args.NewElement.PauseRequested += OnPauseRequested;
args.NewElement.StopRequested += OnStopRequested;
}

if (args.OldElement != null)
{
···
args.OldElement.PlayRequested -= OnPlayRequested;
args.OldElement.PauseRequested -= OnPauseRequested;
args.OldElement.StopRequested -= OnStopRequested;
}
}
···
// Event handlers to implement methods
void OnPlayRequested(object sender, EventArgs args)
{
Control.Play();
}

void OnPauseRequested(object sender, EventArgs args)


{
Control.Pause();
}

void OnStopRequested(object sender, EventArgs args)


{
Control.Stop();
}
}
}

O status do player de vídeo


A implementação das funções Reproduzir, Pausar e Parar não é suficiente para dar suporte aos controles de
transporte. Muitas vezes, os comandos Reproduzir e Pausar são implementados com o mesmo botão que muda
de aparência para indicar se o vídeo ainda está execução ou em pausa. Além disso, o botão nem deverá ser
habilitado se o vídeo ainda não tiver sido carregado.
Esses requisitos implicam que o player de vídeo precisa disponibilizar um status atual que indica se ele está
reproduzindo um vídeo ou em pausa ou se ele ainda não está pronto para reproduzir um vídeo. (Cada plataforma
também dá suporte a propriedades que indicam se o vídeo pode ser colocado em pausa ou pode ser movido para
uma nova posição, mas essas propriedades são aplicáveis para transmissão de vídeo, em vez de arquivos de
vídeo. Portanto, não há suporte para elas no VideoPlayer descrito aqui.)
O projeto VideoPlayerDemos inclui uma enumeração VideoStatus com três membros:
namespace FormsVideoLibrary
{
public enum VideoStatus
{
NotReady,
Playing,
Paused
}
}

A classe VideoPlayer define uma propriedade associável somente real chamada Status do tipo VideoStatus .
Essa propriedade é definida como somente leitura porque só deve ser definida no renderizador da plataforma:

using System;
using Xamarin.Forms;

namespace FormsVideoLibrary
{
public class VideoPlayer : View, IVideoPlayerController
{
···
// Status read-only property
private static readonly BindablePropertyKey StatusPropertyKey =
BindableProperty.CreateReadOnly(nameof(Status), typeof(VideoStatus), typeof(VideoPlayer),
VideoStatus.NotReady);

public static readonly BindableProperty StatusProperty = StatusPropertyKey.BindableProperty;

public VideoStatus Status


{
get { return (VideoStatus)GetValue(StatusProperty); }
}

VideoStatus IVideoPlayerController.Status
{
set { SetValue(StatusPropertyKey, value); }
get { return Status; }
}
···
}
}

Normalmente, uma propriedade associável somente leitura terá um acessador set particular na propriedade
Status para permitir que ela seja definida na classe. No entanto, para um derivado de View compatível com
renderizadores, a propriedade precisa ser definida fora da classe, mas apenas pelo renderizador da plataforma.
Por esse motivo, outra propriedade é definida com o nome IVideoPlayerController.Status . Essa é uma
implementação explícita da interface e foi possibilitada pela interface IVideoPlayerController implementada pela
classe VideoPlayer :

namespace FormsVideoLibrary
{
public interface IVideoPlayerController
{
VideoStatus Status { set; get; }

TimeSpan Duration { set; get; }


}
}

Isso é semelhante ao modo como o controle WebView usa a interface IWebViewController para implementar as
propriedades CanGoBack e CanGoForward . (Confira o código-fonte de WebView e seus renderizadores para obter
detalhes.)
Isso possibilita que uma classe externa a VideoPlayer defina a propriedade Status referenciando a interface
IVideoPlayerController . ( Você verá o código em breve.) A propriedade pode ser definida em outras classes
também, mas é improvável que ela seja definida inadvertidamente. O mais importante é que a propriedade
Status não pode ser definida por meio de uma associação de dados.

Para auxiliar os renderizadores a manter essa propriedade Status atualizada, a classe VideoPlayer define um
evento UpdateStatus que é disparado a cada décimo de segundo:

namespace FormsVideoLibrary
{
public class VideoPlayer : View, IVideoPlayerController
{
public event EventHandler UpdateStatus;

public VideoPlayer()
{
Device.StartTimer(TimeSpan.FromMilliseconds(100), () =>
{
UpdateStatus?.Invoke(this, EventArgs.Empty);
return true;
});
}
···
}
}

A configuração de status do iOS


O VideoPlayerRenderer do iOS define um manipulador para o evento UpdateStatus (e desanexa o manipulador
quando o elemento VideoPlayer subjacente está ausente) e usa o manipulador para definir a propriedade Status
:
namespace FormsVideoLibrary.iOS
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, UIView>
{
···
protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)
{
···
if (args.NewElement != null)
{
···
args.NewElement.UpdateStatus += OnUpdateStatus;
···
}

if (args.OldElement != null)
{
args.OldElement.UpdateStatus -= OnUpdateStatus;
···
}
}
···
void OnUpdateStatus(object sender, EventArgs args)
{
VideoStatus videoStatus = VideoStatus.NotReady;

switch (player.Status)
{
case AVPlayerStatus.ReadyToPlay:
switch (player.TimeControlStatus)
{
case AVPlayerTimeControlStatus.Playing:
videoStatus = VideoStatus.Playing;
break;

case AVPlayerTimeControlStatus.Paused:
videoStatus = VideoStatus.Paused;
break;
}
break;
}
}

((IVideoPlayerController)Element).Status = videoStatus;
···
}
···
}
}

Duas propriedades de AVPlayer devem ser acessadas: A propriedade Status do tipo AVPlayerStatus e a
propriedade TimeControlStatus do tipo AVPlayerTimeControlStatus . Observe que a propriedade Element (que é o
VideoPlayer ) precisa ser convertida em IVideoPlayerController para definir a propriedade Status .

A configuração de status de Android


A propriedade IsPlaying do VideoView do Android é um booliano que indica somente se o vídeo está sendo
reproduzido ou está em pausa. Para determinar se a VideoView ainda não pode reproduzir nem pausar o vídeo, o
evento Prepared de VideoView precisa ser manipulado. Esses dois manipuladores são definidos no método
OnElementChanged e são desanexados durante a substituição Dispose :
namespace FormsVideoLibrary.Droid
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, ARelativeLayout>
{
VideoView videoView;
···
bool isPrepared;

protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)


{
···
if (args.NewElement != null)
{
if (Control == null)
{
···
videoView.Prepared += OnVideoViewPrepared;
···
}
···
args.NewElement.UpdateStatus += OnUpdateStatus;
···
}

if (args.OldElement != null)
{
args.OldElement.UpdateStatus -= OnUpdateStatus;
···
}

protected override void Dispose(bool disposing)


{
if (Control != null && videoView != null)
{
videoView.Prepared -= OnVideoViewPrepared;
}
if (Element != null)
{
Element.UpdateStatus -= OnUpdateStatus;
}

base.Dispose(disposing);
}
···
}
}

O manipulador UpdateStatus usa o campo isPrepared (definido no manipulador Prepared ) e a propriedade


IsPlaying para definir a propriedade Status :
namespace FormsVideoLibrary.Droid
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, ARelativeLayout>
{
VideoView videoView;
···
bool isPrepared;
···
void OnVideoViewPrepared(object sender, EventArgs args)
{
isPrepared = true;
···
}
···
void OnUpdateStatus(object sender, EventArgs args)
{
VideoStatus status = VideoStatus.NotReady;

if (isPrepared)
{
status = videoView.IsPlaying ? VideoStatus.Playing : VideoStatus.Paused;
}
···
}
···
}
}

A configuração de status do UWP


O VideoPlayerRenderer do UWP usa o evento UpdateStatus , mas não precisa dele para definir a propriedade
Status . O MediaElement define um evento CurrentStateChanged que permite que o renderizador seja notificado
quando a propriedade CurrentState é alterada. A propriedade é desanexada na substituição Dispose :
namespace FormsVideoLibrary.UWP
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, MediaElement>
{
protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)
{
base.OnElementChanged(args);

if (args.NewElement != null)
{
if (Control == null)
{
···
mediaElement.CurrentStateChanged += OnMediaElementCurrentStateChanged;
};
···
}
···
}

protected override void Dispose(bool disposing)


{
if (Control != null)
{
···
Control.CurrentStateChanged -= OnMediaElementCurrentStateChanged;
}

base.Dispose(disposing);
}
···
}
}

A propriedade CurrentState é do tipo MediaElementState e é mapeada com facilidade para VideoStatus :

namespace FormsVideoLibrary.UWP
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, MediaElement>
{
···
void OnMediaElementCurrentStateChanged(object sender, RoutedEventArgs args)
{
VideoStatus videoStatus = VideoStatus.NotReady;

switch (Control.CurrentState)
{
case MediaElementState.Playing:
videoStatus = VideoStatus.Playing;
break;

case MediaElementState.Paused:
case MediaElementState.Stopped:
videoStatus = VideoStatus.Paused;
break;
}

((IVideoPlayerController)Element).Status = videoStatus;
}
···
}
}
Botões Reproduzir, Pausar e Parar
É problemático usar caracteres Unicode para imagens simbólicas de Reproduzir, Pausar e Parar. A seção
Diversos – Técnico do padrão Unicode define três caracteres de símbolo aparentemente apropriados para essa
finalidade. Elas são:
0x23F5 (triângulo médio preto apontando para a direita) ou para Reproduzir
0x23F8 (barra vertical dupla) ou para Pausar
0x23F9 (quadrado preto) ou para Parar
Independentemente de como esses símbolos são exibidos no navegador (e navegadores diferentes os tratarão de
maneiras diferentes), eles não são exibidos de maneira consistente nas plataformas compatíveis com o
Xamarin.Forms. Em dispositivos iOS e UWP, os caracteres Pausar e Parar têm uma aparência gráfica, com uma
tela de fundo 3D azul e um primeiro plano branco. Esse não é o caso no Android, em que o símbolo é
simplesmente azul. No entanto, o ponto de código 0x23F5 para Reproduzir não tem a mesma aparência no UWP
e nem mesmo é compatível com o iOS e o Android.
Por esse motivo, o ponto de código 0x23F5 não pode ser usado para Reproduzir. Um bom substituto é:
0x25B6 (triângulo preto apontando para a direita) ou ▶ para Reproduzir
Há suporte para isso em cada plataforma, exceto que ele é um triângulo preto simples que não se assemelha à
aparência 3D de Pausar e Parar. Uma possibilidade é seguir o ponto de código 0x25B6 com um código de
variante:
0x25B6 seguido por 0xFE0F (variante 16) ou ▶ para Reproduzir
Isso é o que é usado na marcação mostrada abaixo. No iOS, ele fornece o símbolo Reproduzir a mesma
aparência 3D dos botões Pausar e Parar, mas a variante não funciona no Android e no UWP.
A página Transporte personalizado define a propriedade AreTransportControlsEnabled como falso e inclui
um ActivityIndicator exibido quando o vídeo está sendo carregado e dois botões. Os objetos DataTrigger são
usados para habilitar e desabilitar o ActivityIndicator e os botões, bem como para alternar o primeiro botão
entre Reproduzir e Pausar:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:video="clr-namespace:FormsVideoLibrary"
x:Class="VideoPlayerDemos.CustomTransportPage"
Title="Custom Transport">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

<video:VideoPlayer x:Name="videoPlayer"
Grid.Row="0"
AutoPlay="False"
AreTransportControlsEnabled="False"
Source="{StaticResource BigBuckBunny}" />

<ActivityIndicator Grid.Row="0"
Color="Gray"
IsVisible="False">
<ActivityIndicator.Triggers>
<DataTrigger TargetType="ActivityIndicator"
Binding="{Binding Source={x:Reference videoPlayer},
Path=Status}"
Value="{x:Static video:VideoStatus.NotReady}">
<Setter Property="IsVisible" Value="True" />
<Setter Property="IsRunning" Value="True" />
<Setter Property="IsRunning" Value="True" />
</DataTrigger>
</ActivityIndicator.Triggers>
</ActivityIndicator>

<StackLayout Grid.Row="1"
Orientation="Horizontal"
Margin="0, 10"
BindingContext="{x:Reference videoPlayer}">

<Button Text="&#x25B6;&#xFE0F; Play"


HorizontalOptions="CenterAndExpand"
Clicked="OnPlayPauseButtonClicked">
<Button.Triggers>
<DataTrigger TargetType="Button"
Binding="{Binding Status}"
Value="{x:Static video:VideoStatus.Playing}">
<Setter Property="Text" Value="&#x23F8; Pause" />
</DataTrigger>

<DataTrigger TargetType="Button"
Binding="{Binding Status}"
Value="{x:Static video:VideoStatus.NotReady}">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Button.Triggers>
</Button>

<Button Text="&#x23F9; Stop"


HorizontalOptions="CenterAndExpand"
Clicked="OnStopButtonClicked">
<Button.Triggers>
<DataTrigger TargetType="Button"
Binding="{Binding Status}"
Value="{x:Static video:VideoStatus.NotReady}">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Button.Triggers>
</Button>
</StackLayout>
</Grid>
</ContentPage>

Gatilhos de dados são descritos em detalhes no artigo Gatilhos de dados.


O arquivo code-behind tem os manipuladores para os eventos Clicked do botão:
namespace VideoPlayerDemos
{
public partial class CustomTransportPage : ContentPage
{
public CustomTransportPage()
{
InitializeComponent();
}

void OnPlayPauseButtonClicked(object sender, EventArgs args)


{
if (videoPlayer.Status == VideoStatus.Playing)
{
videoPlayer.Pause();
}
else if (videoPlayer.Status == VideoStatus.Paused)
{
videoPlayer.Play();
}
}

void OnStopButtonClicked(object sender, EventArgs args)


{
videoPlayer.Stop();
}
}
}

Como AutoPlay é definido como false no arquivo CustomTransport.xaml, você precisará pressionar o botão
Reproduzir quando ele ficar habilitado para iniciar o vídeo. Os botões são definidos para que os caracteres
Unicode abordados acima sejam acompanhados por seus equivalentes de texto. Os botões têm uma aparência
consistente em cada plataforma durante a reprodução do vídeo:

Porém, no Android e no UWP, o botão Reproduzir é muito diferente quando o vídeo está em pausa:
Em um aplicativo de produção, provavelmente, você desejará usar suas próprias imagens de bitmap para os
botões para alcançar a uniformidade visual.

Links relacionados
Demonstrações do player de vídeo (amostra)
Posicionamento de vídeo personalizado
12/04/2019 • 17 minutes to read • Edit Online

Baixar o exemplo
Os controles de transporte implementados por cada plataforma incluem uma barra de posição. Essa barra é
semelhante a um controle deslizante ou a uma barra de rolagem e mostra a localização atual do vídeo dentro de
sua duração total. Além disso, o usuário pode manipular a barra de posição para mover para frente ou para trás
para uma nova posição no vídeo.
Este artigo mostra como é possível implementar sua própria barra de posição personalizada.

A propriedade Duration
Um item de informações que o VideoPlayer precisa para dar suporte a uma barra de posição personalizada é a
duração do vídeo. O VideoPlayer define uma propriedade Duration somente leitura do tipo TimeSpan :

namespace FormsVideoLibrary
{
public class VideoPlayer : View, IVideoPlayerController
{
···
// Duration read-only property
private static readonly BindablePropertyKey DurationPropertyKey =
BindableProperty.CreateReadOnly(nameof(Duration), typeof(TimeSpan), typeof(VideoPlayer), new
TimeSpan(),
propertyChanged: (bindable, oldValue, newValue) => ((VideoPlayer)bindable).SetTimeToEnd());

public static readonly BindableProperty DurationProperty = DurationPropertyKey.BindableProperty;

public TimeSpan Duration


{
get { return (TimeSpan)GetValue(DurationProperty); }
}

TimeSpan IVideoPlayerController.Duration
{
set { SetValue(DurationPropertyKey, value); }
get { return Duration; }
}
···
}
}

Como a propriedade Status descrita no artigo anterior, essa propriedade Duration é somente leitura. É definida
com uma BindablePropertyKey privada e pode ser definida apenas referenciando a interface
IVideoPlayerController , que inclui essa propriedade Duration :
namespace FormsVideoLibrary
{
public interface IVideoPlayerController
{
VideoStatus Status { set; get; }

TimeSpan Duration { set; get; }


}
}

Além disso, observe o manipulador de propriedade alterada que chama um método chamado SetTimeToEnd
descrito posteriormente neste artigo.
A duração de um vídeo não está disponível imediatamente depois que a propriedade Source de VideoPlayer for
definida. O arquivo de vídeo deve ser baixado parcialmente antes que o player de vídeo subjacente possa
determinar sua duração.
Veja como cada um dos renderizadores de plataforma obtém a duração do vídeo:
Duração do vídeo no iOS
No iOS, a duração de um vídeo é obtida com base na propriedade Duration de AVPlayerItem , mas não
imediatamente após a criação de AVPlayerItem . É possível definir um observador de iOS para a propriedade
Duration , mas o VideoPlayerRenderer obtém a duração no método UpdateStatus , chamado de 10 vezes por
segundo:

namespace FormsVideoLibrary.iOS
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, UIView>
{
···
void OnUpdateStatus(object sender, EventArgs args)
{
···
if (playerItem != null)
{
((IVideoPlayerController)Element).Duration = ConvertTime(playerItem.Duration);
···
}
}

TimeSpan ConvertTime(CMTime cmTime)


{
return TimeSpan.FromSeconds(Double.IsNaN(cmTime.Seconds) ? 0 : cmTime.Seconds);

}
···
}
}

O método ConvertTime converte um objeto CMTime em um TimeSpan valor.


Duração do vídeo no Android
A propriedade Duration do Android VideoView relata uma duração válida em milissegundos quando o evento
Prepared de VideoView é acionado. A classe VideoPlayerRenderer do Android usa esse manipulador para obter a
propriedade Duration :
namespace FormsVideoLibrary.Droid
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, ARelativeLayout>
{
···
void OnVideoViewPrepared(object sender, EventArgs args)
{
···
((IVideoPlayerController)Element).Duration = TimeSpan.FromMilliseconds(videoView.Duration);
}
···
}
}

Duração do vídeo na UWP


A propriedade NaturalDuration de MediaElement é um valor TimeSpan e torna-se válida quando MediaElement
aciona o evento MediaOpened :

namespace FormsVideoLibrary.UWP
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, MediaElement>
{
···
void OnMediaElementMediaOpened(object sender, RoutedEventArgs args)
{
((IVideoPlayerController)Element).Duration = Control.NaturalDuration.TimeSpan;
}
···
}
}

A propriedade Position
VideoPlayer também precisa de uma propriedade Position que aumenta de zero a Duration conforme o vídeo é
reproduzido. VideoPlayer implementa essa propriedade como a propriedade Position no MediaElement UWP,
que é uma propriedade associável normal com acessadores públicos set e get :

namespace FormsVideoLibrary
{
public class VideoPlayer : View, IVideoPlayerController
{
···
// Position property
public static readonly BindableProperty PositionProperty =
BindableProperty.Create(nameof(Position), typeof(TimeSpan), typeof(VideoPlayer), new TimeSpan(),
propertyChanged: (bindable, oldValue, newValue) => ((VideoPlayer)bindable).SetTimeToEnd());

public TimeSpan Position


{
set { SetValue(PositionProperty, value); }
get { return (TimeSpan)GetValue(PositionProperty); }
}
···
}
}

O acessador get retorna a posição atual do vídeo quando ele está sendo reproduzido, mas o acessador set é
projetado para responder à manipulação do usuário da barra de posição movendo a posição de vídeo para frente
ou para trás.
No iOS e Android, a propriedade que obtém a posição atual tem apenas um acessador get , e um método Seek
está disponível para executar essa segunda tarefa. Se você pensar a respeito, um método Seek separado parecerá
ser uma abordagem mais adequada do que uma única propriedade Position . Uma única propriedade Position
tem um problema inerente: Durante a reprodução do vídeo, a propriedade Position deve ser atualizada
continuamente para refletir a nova posição. Mas você não quer que a maioria das alterações à propriedade
Position faça o player de vídeo se mover para uma nova posição no vídeo. Se isso acontecesse, o player de vídeo
responderia buscando o último valor da propriedade Position e o vídeo não avançaria.
Apesar das dificuldades da implementação da propriedade Position com os acessadores set e get , essa
abordagem foi escolhida porque é consistente com a UWP MediaElement e tem uma grande vantagem na
associação de dados: A propriedade Position do VideoPlayer pode ser associada ao controle deslizante usado
para exibir a posição e para procurar uma nova posição. No entanto, várias precauções são necessárias ao
implementar essa propriedade Position para evitar loops de comentários.
Definir e obter a posição do iOS
No iOS, a propriedade CurrentTime do objeto AVPlayerItem indica a posição atual do vídeo sendo reproduzido. O
iOS VideoPlayerRenderer define a propriedade Position no manipulador UpdateStatus ao mesmo tempo em que
ele define a propriedade Duration :

namespace FormsVideoLibrary.iOS
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, UIView>
{
···
void OnUpdateStatus(object sender, EventArgs args)
{
···
if (playerItem != null)
{
···
((IElementController)Element).SetValueFromRenderer(VideoPlayer.PositionProperty,
ConvertTime(playerItem.CurrentTime));
}
}
···
}
}

O renderizador detecta quando o conjunto de propriedades Position de VideoPlayer foi alterado na substituição
do OnElementPropertyChanged , e usa esse novo valor para chamar um método Seek no objeto AVPlayer :
namespace FormsVideoLibrary.iOS
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, UIView>
{
···
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args)
{
···
else if (args.PropertyName == VideoPlayer.PositionProperty.PropertyName)
{
TimeSpan controlPosition = ConvertTime(player.CurrentTime);

if (Math.Abs((controlPosition - Element.Position).TotalSeconds) > 1)


{
player.Seek(CMTime.FromSeconds(Element.Position.TotalSeconds, 1));
}
}
}
···
}
}

Tenha em mente que sempre que a propriedade Position no VideoPlayer for definida com base no manipulador
OnUpdateStatus , a propriedade Position disparará um evento PropertyChanged , detectado na substituição do
OnElementPropertyChanged . Para a maioria dessas alterações, o método OnElementPropertyChanged não deve fazer
nada. Caso contrário, a cada alteração na posição do vídeo, ele seria ser movido para a mesma posição que ela
acabou de atingir!
Para evitar esse loop de comentários, o método OnElementPropertyChanged apenas chamará Seek quando a
diferença entre a propriedade Position e a posição atual do AVPlayer for maior que um segundo.
Definir e obter a posição do Android
Como acontece no renderizador do iOS, o VideoPlayerRenderer do Android define um novo valor para a
propriedade Position no manipulador OnUpdateStatus . A propriedade CurrentPosition de VideoView contém a
nova posição em unidades de milissegundos:

namespace FormsVideoLibrary.Droid
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, ARelativeLayout>
{
···
void OnUpdateStatus(object sender, EventArgs args)
{
···
TimeSpan timeSpan = TimeSpan.FromMilliseconds(videoView.CurrentPosition);
((IElementController)Element).SetValueFromRenderer(VideoPlayer.PositionProperty, timeSpan);
}
···
}
}

Além disso, como acontece no renderizador do iOS, o renderizador do Android chamará o método SeekTo de
VideoView quando a propriedade Position tiver sido alterada, mas somente quando a alteração for mais de um
segundo diferente do valor CurrentPosition de VideoView :
namespace FormsVideoLibrary.Droid
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, ARelativeLayout>
{
···
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args)
{
···
else if (args.PropertyName == VideoPlayer.PositionProperty.PropertyName)
{
if (Math.Abs(videoView.CurrentPosition - Element.Position.TotalMilliseconds) > 1000)
{
videoView.SeekTo((int)Element.Position.TotalMilliseconds);
}
}
}
···
}
}

Definir e obter a posição da UWP


O VideoPlayerRenderer da UWP manipula o Position da mesma maneira que os renderizadores do iOS e do
Android, mas, como a propriedade Position do MediaElement da UWP também é um valor TimeSpan , não é
necessária nenhuma conversão:

namespace FormsVideoLibrary.UWP
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, MediaElement>
{
···
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args)
{
···
else if (args.PropertyName == VideoPlayer.PositionProperty.PropertyName)
{
if (Math.Abs((Control.Position - Element.Position).TotalSeconds) > 1)
{
Control.Position = Element.Position;
}
}
}
···
void OnUpdateStatus(object sender, EventArgs args)
{
((IElementController)Element).SetValueFromRenderer(VideoPlayer.PositionProperty,
Control.Position);
}
···
}
}

Calculando uma propriedade TimeToEnd


Às vezes, os players de vídeo mostram o tempo restante no vídeo. Esse valor começa na duração do vídeo quando
o vídeo é iniciado e diminui para zero quando o vídeo é encerrado.
VideoPlayer inclui uma propriedade TimeToEnd somente leitura que é manipulada inteiramente dentro da classe
com base nas alterações às propriedades Duration e Position :
namespace FormsVideoLibrary
{
public class VideoPlayer : View, IVideoPlayerController
{
···
private static readonly BindablePropertyKey TimeToEndPropertyKey =
BindableProperty.CreateReadOnly(nameof(TimeToEnd), typeof(TimeSpan), typeof(VideoPlayer), new
TimeSpan());

public static readonly BindableProperty TimeToEndProperty = TimeToEndPropertyKey.BindableProperty;

public TimeSpan TimeToEnd


{
private set { SetValue(TimeToEndPropertyKey, value); }
get { return (TimeSpan)GetValue(TimeToEndProperty); }
}

void SetTimeToEnd()
{
TimeToEnd = Duration - Position;
}
···
}
}

O método SetTimeToEnd é chamado dos manipuladores de propriedade alterada de Duration e de Position .

Um controle deslizante personalizado para vídeo


É possível gravar um controle personalizado para uma barra de posição ou usar o Slider do Xamarin.Forms ou
uma classe derivada de Slider , como a seguinte classe PositionSlider . A classe define duas novas propriedades
denominadas Duration e Position do tipo TimeSpan que se destinam a ser associadas às duas propriedades de
mesmo nome no VideoPlayer . Observe que o modo de associação padrão da propriedade Position é
bidirecional:
namespace FormsVideoLibrary
{
public class PositionSlider : Slider
{
public static readonly BindableProperty DurationProperty =
BindableProperty.Create(nameof(Duration), typeof(TimeSpan), typeof(PositionSlider), new
TimeSpan(1),
propertyChanged: (bindable, oldValue, newValue) =>
{
double seconds = ((TimeSpan)newValue).TotalSeconds;
((PositionSlider)bindable).Maximum = seconds <= 0 ? 1 : seconds;
});

public TimeSpan Duration


{
set { SetValue(DurationProperty, value); }
get { return (TimeSpan)GetValue(DurationProperty); }
}

public static readonly BindableProperty PositionProperty =


BindableProperty.Create(nameof(Position), typeof(TimeSpan), typeof(PositionSlider), new
TimeSpan(0),
defaultBindingMode: BindingMode.TwoWay,
propertyChanged: (bindable, oldValue, newValue) =>
{
double seconds = ((TimeSpan)newValue).TotalSeconds;
((PositionSlider)bindable).Value = seconds;
});

public TimeSpan Position


{
set { SetValue(PositionProperty, value); }
get { return (TimeSpan)GetValue(PositionProperty); }
}

public PositionSlider()
{
PropertyChanged += (sender, args) =>
{
if (args.PropertyName == "Value")
{
TimeSpan newPosition = TimeSpan.FromSeconds(Value);

if (Math.Abs(newPosition.TotalSeconds - Position.TotalSeconds) / Duration.TotalSeconds >


0.01)
{
Position = newPosition;
}
}
};
}
}
}

O manipulador de propriedade alterada dos conjuntos de propriedades Duration define a propriedade Maximum
do Slider subjacente como a propriedade TotalSeconds do valor TimeSpan . Da mesma forma, o manipulador de
propriedade alterada de Position define a propriedade Value do Slider . Dessa forma, o Slider subjacente
controla a posição do PositionSlider .
O PositionSlider é atualizado do Slider subjacente em apenas uma instância: Quando o usuário manipula o
Slider para indicar que o vídeo deve ser avançado ou revertido para uma nova posição. Isso é detectado no
manipulador PropertyChanged no construtor do PositionSlider . O manipulador verifica uma alteração na
propriedade Value e, se for diferente da propriedade Position , então a propriedade Position será definida com
base na propriedade Value .
Em teoria, a instrução if interna poderia ser escrita da seguinte forma:

if (newPosition.Seconds != Position.Seconds)
{
Position = newPosition;
}

No entanto, a implementação do Android de Slider tem apenas 1.000 etapas distintas, independentemente das
configurações do Minimum e do Maximum . Se o comprimento de um vídeo for maior que 1.000 segundos, os dois
valores Position diferentes corresponderá à mesma configuração Value do Slider , e essa instrução if
dispararia um falso positivo para a manipulação de um usuário do Slider . É mais seguro verificar se a nova
posição e a existente são maiores do que um centésimo da duração geral.

Usando o PositionSlider
A documentação da UWP MediaElement avisa sobre a associação para a propriedade Position , porque a
propriedade é atualizada com frequência. A documentação recomenda que um temporizador seja usado para
consultar a propriedade Position .
É uma boa recomendação, mas as três classes VideoPlayerRenderer já estão usando indiretamente um
temporizador para atualizar a propriedade Position . A propriedade Position é alterada em um manipulador
para o evento UpdateStatus , que é disparado apenas 10 vezes por segundo.
Portanto, a propriedade Position do VideoPlayer pode ser associada à propriedade Position do PositionSlider
sem problemas de desempenho, conforme demonstrado na página Barra de Posição Personalizada:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:video="clr-namespace:FormsVideoLibrary"
x:Class="VideoPlayerDemos.CustomPositionBarPage"
Title="Custom Position Bar">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

<video:VideoPlayer x:Name="videoPlayer"
Grid.Row="0"
AreTransportControlsEnabled="False"
Source="{StaticResource ElephantsDream}" />

···

<StackLayout Grid.Row="1"
Orientation="Horizontal"
Margin="10, 0"
BindingContext="{x:Reference videoPlayer}">

<Label Text="{Binding Path=Position,


StringFormat='{0:hh\\:mm\\:ss}'}"
VerticalOptions="Center"/>

···

<Label Text="{Binding Path=TimeToEnd,


StringFormat='{0:hh\\:mm\\:ss}'}"
VerticalOptions="Center" />
</StackLayout>

<video:PositionSlider Grid.Row="2"
Margin="10, 0, 10, 10"
BindingContext="{x:Reference videoPlayer}"
Duration="{Binding Duration}"
Position="{Binding Position}">
<video:PositionSlider.Triggers>
<DataTrigger TargetType="video:PositionSlider"
Binding="{Binding Status}"
Value="{x:Static video:VideoStatus.NotReady}">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</video:PositionSlider.Triggers>
</video:PositionSlider>
</Grid>
</ContentPage>

As primeiras reticências (···) ocultam o ActivityIndicator ; é o mesmo da página Transporte Personalizada


anterior. Observe os dois elementos Label que exibem as propriedades Position e TimeToEnd . As reticências
entre esses dois elementos Label oculta os dois elementos Button mostrados na página Transporte
Personalizado para executar, pausar e parar. A lógica code-behind também é a mesma da página Transporte
Personalizado.
Isso conclui a discussão do VideoPlayer .

Links relacionados
Demonstrações do player de vídeo (amostra)
Associação de dados do Xamarin.Forms
12/04/2019 • 5 minutes to read • Edit Online

Baixar o exemplo
A associação de dados é a técnica de vinculação de propriedades de dois objetos para que as alterações em
uma propriedade sejam automaticamente refletidas na outra propriedade. A associação de dados é parte
integrante da arquitetura do aplicativo MVVM (Model-View -ViewModel).

O problema de associação de dados


Um aplicativo Xamarin.Forms consiste em uma ou mais páginas, cada uma das quais geralmente contém
vários objetos da interface do usuário chamados de exibições. Uma das principais tarefas do programa é
manter essas exibições sincronizadas e controlar os diversos valores ou seleções que elas representam. Muitas
vezes as exibições representam valores de uma fonte de dados subjacente, e o usuário manipula essas
exibições para alterar esses dados. Quando a exibição é alterada, os dados subjacentes devem refletir essa
alteração e, da mesma forma, quando os dados subjacentes são alterados, essa alteração deve ser refletida na
exibição.
Para que esse trabalho seja realizado com êxito, o programa deve ser notificado das alterações nessas
exibições ou nos dados subjacentes. A solução comum é definir eventos que sinalizam quando uma alteração
ocorre. É possível então instalar um manipulador de eventos que é notificado sobre essas alterações. Ele
responde transferindo dados de um objeto para outro. No entanto, quando há muitas exibições, também é
preciso que haja vários manipuladores de eventos, e há muito código envolvido.

A solução de associação de dados


A associação de dados automatiza esse trabalho e torna os manipuladores de eventos desnecessários. (No
entanto, os eventos ainda são necessários, porque a infraestrutura de associação de dados faz uso deles.)
Associações de dados podem ser implementadas no código ou em XAML, mas são muito mais comuns em
XAML, em que elas ajudam a reduzir o tamanho do arquivo code-behind. Substituindo o código procedural
em manipuladores de eventos por marcação ou código declarativo, o aplicativo é simplificado e esclarecido.
Um dos dois objetos envolvidos em uma associação de dados quase sempre é um elemento derivado de View
e que faz parte da interface visual de uma página. O outro objeto é uma das seguintes opções:
Outro derivado de View , geralmente na mesma página.
Um objeto em um arquivo de código.
Em programas de demonstração, tais como aqueles na amostra DataBindingDemos, associações de dados
entre dois derivados de View geralmente são mostrados para fins de clareza e simplicidade. No entanto, os
mesmos princípios podem ser aplicados às associações de dados entre um View e outros objetos. Quando um
aplicativo é compilado usando a arquitetura MVVM (Model-View -ViewModel), a classe com os dados
subjacentes é frequentemente chamada de um ViewModel.
Associações de dados são exploradas na seguinte série de artigos:

Associações básicas
Aprenda a diferença entre a origem e o destino da associação de dados e veja associações de dados simples
em código e em XAML.
Modo de associação
Descubra como o modo de associação pode controlar o fluxo de dados entre os dois objetos.

Formação de cadeia de caracteres


Use uma associação de dados para formatar e exibir objetos como cadeias de caracteres.

Caminho de associação
Aprofunde-se na propriedade Path da associação de dados para acessar subpropriedades e os membros da
coleção.

Conversores de associação de valor


Use conversores de valor de associação para alterar os valores dentro da associação de dados.

Fallbacks de associação
Torne as associações de dados mais robustas definindo valores de fallback que deverão ser usados se o
processo de associação falhar.

A interface de comando
Implemente a propriedade Command com associações de dados.

Associações compiladas
Use associações compiladas para melhorar o desempenho de associação de dados.

Links relacionados
Demonstrações de associação de dados (amostra)
Capítulo de associação de dados do catálogo de Xamarin.Forms
Extensões de marcação XAML
Associações básicas do Xamarin.Forms
12/04/2019 • 18 minutes to read • Edit Online

Baixar o exemplo
A associação de dados do Xamarin.Forms vincula um par de propriedades entre dois objetos e pelo menos um
deles geralmente é um objeto da interface do usuário. Esses dois objetos são chamados de destino e origem:
O destino é o objeto (e a propriedade) no qual a associação de dados é definida.
A origem é o objeto (e propriedade) referenciado pela associação de dados.
Às vezes, essa distinção pode ser um pouco confusa: No caso mais simples, os dados fluem da origem para o
destino, o que significa que o valor da propriedade de destino é definido pelo valor da propriedade da origem. No
entanto, em alguns casos, os dados podem fluir do destino para a origem ou em ambas os sentidos. Para evitar
confusão, tenha em mente que o destino é sempre o objeto no qual a associação de dados está definida, mesmo se
estiver fornecendo os dados em vez de recebendo.

Associações com um contexto de associação


Embora as associações de dados geralmente sejam especificadas inteiramente em XAML, é instrutivo observar as
associações de dados no código. A página Associação de código básica contém um arquivo XAML com um
Label e um Slider :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.BasicCodeBindingPage"
Title="Basic Code Binding">
<StackLayout Padding="10, 0">
<Label x:Name="label"
Text="TEXT"
FontSize="48"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />

<Slider x:Name="slider"
Maximum="360"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>

O Slider é definido para um intervalo de 0 a 360. A intenção deste programa é girar o Label manipulando o
Slider .
Sem associações de dados, você definiria o evento ValueChanged do Slider para um manipulador de eventos que
acessa a propriedade Value do Slider e define esse valor para a propriedade Rotation do Label . A associação
de dados automatiza esse trabalho. O manipulador de eventos e o código dentro dele não são mais necessários.
Você pode definir uma associação em uma instância de qualquer classe que deriva de BindableObject , que inclui
os derivativos Element , VisualElement , View e View . A associação é sempre definida no objeto de destino. A
associação faz referência ao objeto de origem. Para definir a associação de dados, use os seguintes dois membros
da classe de destino:
A propriedade BindingContext especifica o objeto de origem.
O método SetBinding especifica a propriedade de destino e a propriedade de origem.
Neste exemplo, o Label é o destino da associação e o Slider é a origem da associação. As alterações na origem
Slider afetam a rotação do destino Label . Os dados fluem da origem para o destino.

O método SetBinding definido pelo BindableObject tem um argumento do tipo BindingBase do qual a classe
Binding deriva, mas há outros métodos SetBinding definidos pela classe BindableObjectExtensions . O arquivo
code-behind no exemplo da Associação de código básica usa um método de extensão SetBinding mais simples
de sua classe.

public partial class BasicCodeBindingPage : ContentPage


{
public BasicCodeBindingPage()
{
InitializeComponent();

label.BindingContext = slider;
label.SetBinding(Label.RotationProperty, "Value");
}
}

O objeto Label é o destino da associação, portanto, é o objeto no qual essa propriedade é definida e no qual o
método é chamado. A propriedade BindingContext indica a origem da associação, que é o Slider .
O método SetBinding é chamado no destino da associação, mas especifica a propriedade de destino e a
propriedade de origem. A propriedade de destino é especificada como um objeto BindableProperty :
Label.RotationProperty . A propriedade de origem é especificada como uma cadeia de caracteres e indica a
propriedade Value de Slider .
O método SetBinding revela uma das regras de associações de dados mais importantes:
A propriedade de destino deve ter suporte de uma propriedade associável.
Essa regra implica que o objeto de destino deve ser uma instância de uma classe que deriva de BindableObject .
Confira o artigo Propriedades associáveis para obter uma visão geral de objetos associáveis e propriedades
associáveis.
Não há uma regra para a propriedade de origem, que é especificada como uma cadeia de caracteres.
Internamente, a reflexão é usada para acessar a propriedade real. Nesse caso específico, no entanto, a propriedade
Value também tem suporte de uma propriedade associável.

O código pode ser um pouco simplificado: A propriedade associável RotationProperty é definida por
VisualElement e herdada por Label e também por ContentPage , portanto, o nome de classe não é necessário na
chamada SetBinding :

label.SetBinding(RotationProperty, "Value");

No entanto, incluir o nome de classe é um bom lembrete do objeto de destino.


Ao manipular Slider ,o Label gira de acordo:
A página Associação de XAML básica é idêntica à Associação de código básica, exceto que ela define a
associação de dados inteira em XAML:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.BasicXamlBindingPage"
Title="Basic XAML Binding">
<StackLayout Padding="10, 0">
<Label Text="TEXT"
FontSize="80"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
BindingContext="{x:Reference Name=slider}"
Rotation="{Binding Path=Value}" />

<Slider x:Name="slider"
Maximum="360"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>

Assim como no código, a associação de dados é definida no objeto de destino, que é o Label . Duas extensões de
marcação XAML estão envolvidas. Estas são instantaneamente reconhecíveis pelos delimitadores de chaves:
A extensão de marcação x:Reference é necessária para fazer referência ao objeto de origem, que é o Slider
denominado slider .
A extensão de marcação Binding vincula a propriedade Rotation do Label à propriedade Value do Slider .
Para obter mais informações sobre extensões de marcação XAML, confira o artigo Extensões de marcação XAML.
A extensão de marcação x:Reference tem suporte da classe ReferenceExtension . Binding tem suporte da classe
BindingExtension . Como os prefixos de namespace de XML indicam, x:Reference faz parte da especificação
XAML 2009, enquanto Binding faz parte do Xamarin.Forms. Observe que não há aspas dentro das chaves.
É fácil esquecer-se da extensão de marcação x:Reference ao definir o BindingContext . É comum definir de modo
incorreto a propriedade diretamente para o nome da origem da associação, do seguinte modo:

BindingContext="slider"

Mas isso não é certo. Essa marcação define a propriedade BindingContext para um objeto string cujos
caracteres formam a palavra "slider".
Observe que a propriedade de origem é especificada com a propriedade Path do BindingExtension , que
corresponde à propriedade Path da classe Binding .
A marcação mostrada na página Associação de XAML básica pode ser simplificada: As extensões de marcação
XAML, como x:Reference e Binding , podem ter atributos de propriedade de conteúdo definidos, o que, para
extensões de marcação XAML, significa que o nome da propriedade não precisa aparecer. A propriedade Name é a
propriedade de conteúdo do x:Reference , e a propriedade Path é a propriedade de conteúdo do Binding , o que
significa que elas podem ser eliminadas das expressões:

<Label Text="TEXT"
FontSize="80"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
BindingContext="{x:Reference slider}"
Rotation="{Binding Value}" />

Associações sem um contexto de associação


A propriedade BindingContext é um componente importante de associações de dados, mas nem sempre é
necessária. O objeto de origem pode ser especificado na chamada SetBinding ou na extensão de marcação
Binding .

Isso é demonstrado no exemplo Associação de código alternativa. O arquivo XAML é semelhante ao exemplo
Associação de código básica, exceto que o Slider é definido para controlar a propriedade Scale do Label .
Por esse motivo, o Slider é definido para um intervalo de –2 a 2:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.AlternativeCodeBindingPage"
Title="Alternative Code Binding">
<StackLayout Padding="10, 0">
<Label x:Name="label"
Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />

<Slider x:Name="slider"
Minimum="-2"
Maximum="2"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>

O arquivo code-behind define a associação com o método SetBinding definido por BindableObject . O argumento
é um construtor para a classe Binding :

public partial class AlternativeCodeBindingPage : ContentPage


{
public AlternativeCodeBindingPage()
{
InitializeComponent();

label.SetBinding(Label.ScaleProperty, new Binding("Value", source: slider));


}
}
O construtor Binding tem seis parâmetros, portanto o parâmetro source é especificado com um argumento
nomeado. O argumento é o objeto slider .
Executar este programa pode ser um pouco surpreendente:

A tela do iOS à esquerda mostra como a tela aparece quando a página é exibida pela primeira vez. Onde está o
Label ?

O problema é que o Slider tem um valor inicial de 0. Isso faz com que a propriedade Scale do Label também
seja definida como 0, substituindo o valor padrão de 1. Isso resulta no Label sendo inicialmente invisível. Como
demonstram as capturas de tela do Android e da UWP (Plataforma Universal do Windows), você pode manipular
o Slider para fazer o Label aparecer novamente, mas seu desaparecimento inicial é desconcertante.
Você descobrirá no próximo artigo como evitar esse problema ao inicializar Slider do valor padrão da
propriedade Scale .

NOTE
A classe VisualElement define também as propriedades ScaleX e ScaleY , que podem dimensionar o VisualElement
de forma diferente nos sentidos horizontal e vertical.

A página Associação de XAML alternativa mostra a associação equivalente inteiramente em XAML:


<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.AlternativeXamlBindingPage"
Title="Alternative XAML Binding">
<StackLayout Padding="10, 0">
<Label Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Scale="{Binding Source={x:Reference slider},
Path=Value}" />

<Slider x:Name="slider"
Minimum="-2"
Maximum="2"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>

Agora a extensão de marcação Binding tem duas propriedades definidas, Source e Path , separadas por uma
vírgula. Se você preferir, elas poderão aparecer na mesma linha:

Scale="{Binding Source={x:Reference slider}, Path=Value}" />

A propriedade Source está definida para uma extensão de marcação x:Reference inserida que normalmente tem
a mesma sintaxe que a configuração de BindingContext . Observe que não há aspas entre as chaves e as duas
propriedades devem ser separadas por uma vírgula.
A propriedade de conteúdo da extensão de marcação Binding é Path , mas a parte Path= da extensão de
marcação só poderá ser eliminada se for a primeira propriedade na expressão. Para eliminar a parte Path= , você
precisa trocar as duas propriedades:

Scale="{Binding Value, Source={x:Reference slider}}" />

Embora as extensões de marcação XAML geralmente sejam delimitadas por chaves, elas também podem ser
expressas como elementos de objeto:

<Label Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand">
<Label.Scale>
<Binding Source="{x:Reference slider}"
Path="Value" />
</Label.Scale>
</Label>

Agora as propriedades Source e Path são atributos normais de XAML: Os valores aparecem entre aspas e os
atributos não são separados por uma vírgula. A extensão de marcação x:Reference também pode se tornar um
elemento de objeto:
<Label Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand">
<Label.Scale>
<Binding Path="Value">
<Binding.Source>
<x:Reference Name="slider" />
</Binding.Source>
</Binding>
</Label.Scale>
</Label>

Essa sintaxe não é comum, mas, às vezes, é necessária quando objetos complexos estão envolvidos.
Os exemplos mostrados até agora definem a propriedade BindingContext e a propriedade Source de Binding
para uma extensão de marcação x:Reference para fazer referência a outra exibição na página. Essas duas
propriedades são do tipo Object , e elas podem ser definidas para qualquer objeto que inclua as propriedades que
são adequadas para as origens da associação.
Nos próximos artigos, você descobrirá que pode definir a propriedade BindingContext ou Source para uma
extensão de marcação x:Static para fazer referência ao valor de uma propriedade estática ou campo ou para
uma extensão de marcação StaticResource para fazer referência a um objeto armazenado em um dicionário de
recursos ou diretamente a um objeto que é normalmente (mas nem sempre) uma instância de um ViewModel.
A propriedade BindingContext também pode ser definida como um objeto Binding , de modo que as
propriedades Source e Path de Binding definem o contexto de associação.

Herança de contexto de associação


Neste artigo, você viu que pode especificar o objeto de origem usando a propriedade BindingContext ou a
propriedade Source do objeto Binding . Se ambas estiverem definidas, a propriedade Source do Binding terá
precedência em relação a BindingContext .
A propriedade BindingContext tem uma característica muito importante:
A configuração da propriedade BindingContext é herdada por meio da árvore visual.
Como você verá, isso pode ser muito útil para simplificar expressões de associação e, em alguns casos, —
especialmente em cenários de MVVM (Model-View -ViewModel), — é essencial.
O exemplo Herança de contexto de associação é uma demonstração simples da herança de contexto de
associação:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.BindingContextInheritancePage"
Title="BindingContext Inheritance">
<StackLayout Padding="10">

<StackLayout VerticalOptions="FillAndExpand"
BindingContext="{x:Reference slider}">

<Label Text="TEXT"
FontSize="80"
HorizontalOptions="Center"
VerticalOptions="EndAndExpand"
Rotation="{Binding Value}" />

<BoxView Color="#800000FF"
WidthRequest="180"
HeightRequest="40"
HorizontalOptions="Center"
VerticalOptions="StartAndExpand"
Rotation="{Binding Value}" />
</StackLayout>

<Slider x:Name="slider"
Maximum="360" />

</StackLayout>
</ContentPage>

A propriedade BindingContext do StackLayout é definida para o objeto slider . Esse contexto de associação é
herdado por Label e BoxView , que têm suas propriedades Rotation definidas para a propriedade Value de
Slider :

No próximo artigo, você verá como o modo de associação pode alterar o fluxo de dados entre objetos de origem e
destino.

Links relacionados
Demonstrações de associação de dados (amostra)
Capítulo de associação de dados do catálogo de Xamarin.Forms
Vídeo relacionados
Saiba mais sobre o Xamarin Show no Channel 9 e no YouTube.
Modo de associação do Xamarin.Forms
12/04/2019 • 27 minutes to read • Edit Online

Baixar o exemplo
No artigo anterior, as páginas Associação de código alternativa e Associação de XAML alternativa
apresentavam um Label com sua propriedade Scale associada à propriedade Value de um Slider . Como o
valor inicial de Slider é 0, isso fez com que a propriedade Scale do Label fosse definida como 0 em vez de 1
e o Label desapareceu.
Na amostra DataBindingDemos, a página Associação inversa é semelhante aos programas do artigo anterior,
exceto que a associação de dados é definida no Slider em vez de no Label :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.ReverseBindingPage"
Title="Reverse Binding">
<StackLayout Padding="10, 0">

<Label x:Name="label"
Text="TEXT"
FontSize="80"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />

<Slider x:Name="slider"
VerticalOptions="CenterAndExpand"
Value="{Binding Source={x:Reference label},
Path=Opacity}" />
</StackLayout>
</ContentPage>

A princípio, isso pode parecer invertido: Agora o Label é a origem de associação de dados e o Slider é o
destino. A associação referencia a propriedade Opacity do Label , que tem um valor padrão igual a 1.
Como você pode esperar, o Slider é inicializada com o valor 1 do valor inicial Opacity de Label . Isso é
mostrado na captura de tela do iOS à esquerda:
Mas você pode estar surpreso de que o Slider continuará funcionando, como demonstram as capturas de tela
do Android e do UWP. Isso parece sugerir que a associação de dados funciona melhor quando o Slider é o
destino da associação em vez de Label , porque a inicialização funciona como poderíamos esperar.
A diferença entre a amostra Associação inversa e as amostras anteriores envolve o modo de associação.

O modo de associação padrão


O modo de associação é especificado com um membro da enumeração BindingMode :
Default
TwoWay – os dados fluem bidirecionalmente entre a origem e o destino
OneWay – os dados vão da origem para o destino
OneWayToSource – os dados fluem do destino para a origem
OneTime – os dados fluem da origem para o destino, mas somente quando o BindingContext é alterado
(novidade no Xamarin.Forms 3.0)

Cada propriedade associável tem um modo de associação padrão definido quando a propriedade associável é
criada, que está disponível na propriedade DefaultBindingMode do objeto BindableProperty . Esse modo de
associação padrão indica o modo em vigor quando essa propriedade é um destino da associação de dados.
O modo de associação padrão para a maioria das propriedades, como Rotation , Scale e Opacity , é OneWay .
Quando essas propriedades são destinos de associação de dados, a propriedade de destino é definida na origem.
No entanto, o modo de associação padrão para a propriedade Value de Slider é TwoWay . Isso significa que,
quando a propriedade Value é um destino da associação de dados, o destino é definido na origem (como de
costume), mas a origem também é definida no destino. Isso é o que permite que o Slider seja definido com
base no valor inicial Opacity .
Essa associação bidirecional pode parecer criar um loop infinito, mas isso não acontece. As propriedades
vinculáveis não sinalizam uma alteração de propriedade, a menos que a propriedade seja, de fato, alterada. Isso
impede um loop infinito.
Vinculações bidirecionais
A maioria das propriedades vinculáveis tem um modo de associação padrão igual a OneWay , mas as seguintes
propriedades têm um modo de associação padrão igual a TwoWay :
Propriedade Date de DatePicker
Propriedade Text de Editor , Entry , SearchBar e EntryCell
Propriedade IsRefreshing de ListView
Propriedade SelectedItem de MultiPage
Propriedades SelectedIndex e SelectedItem de Picker
Propriedade Value de Slider e Stepper
Propriedade IsToggled de Switch
Propriedade On de SwitchCell
Propriedade Time de TimePicker
Essas propriedades específicas são definidas como TwoWay por um motivo muito válido:
Quando as associações de dados são usadas com a arquitetura do aplicativo MVVM (Model-View -ViewModel), a
classe ViewModel é a origem da associação de dados e a View, que consiste em exibições como Slider , são
destinos de associação de dados. As associações de MVVM se parecem com a amostra Associação inversa
mais do que as associações das amostras anteriores. É muito provável que você deseje que cada exibição na
página seja inicializada com o valor da propriedade correspondente no ViewModel, mas as alterações na exibição
também devem afetar a propriedade de ViewModel.
As propriedades com modos de associação padrão iguais a TwoWay são as propriedades mais prováveis de
serem utilizadas em cenários de MVVM.
Associações unidirecionais para a origem
As propriedades vinculáveis somente leitura têm um modo de associação padrão igual a OneWayToSource . Há
apenas uma propriedade associável de leitura/gravação que tem um modo de associação padrão igual a
OneWayToSource :

Propriedade SelectedItem de ListView

A lógica é que uma associação na propriedade SelectedItem deve resultar na definição da origem da associação.
Um exemplo mais adiante neste artigo substitui esse comportamento.
Associações avulsas
Várias propriedades têm um modo de associação padrão do OneTime , incluindo a propriedade
IsTextPredictionEnabled de Entry .

Propriedades de destino com um modo de associação igual a OneTime são atualizadas somente quando o
contexto de associação é alterado. Para as associações nessas propriedades de destino, isso simplifica a
infraestrutura de associação porque não é necessário monitorar as alterações nas propriedades de origem.

ViewModels e notificações de alteração de propriedade


A página Seletor de cor simples demonstra o uso de um ViewModel simples. As associações de dados
permitem que o usuário selecione uma cor usando três elementos Slider para o matiz, a saturação e a
luminosidade.
O ViewModel é a origem da associação de dados. O ViewModel não define propriedades vinculáveis, mas
implementa um mecanismo de notificação que permite que a infraestrutura de associação seja notificada quando
o valor de uma propriedade é alterado. Esse mecanismo de notificação é a interface INotifyPropertyChanged , que
define uma única propriedade chamada PropertyChanged . Em geral, uma classe que implementa essa interface
dispara o evento quando uma de suas propriedades públicas altera o valor. O evento não precisa ser disparado se
a propriedade nunca é alterada. (A interface INotifyPropertyChanged também é implementada por
BindableObject e um evento PropertyChanged é disparado sempre que uma propriedade vinculável altera o
valor.)
A classe HslColorViewModel define cinco propriedades: As propriedades Hue , Saturation , Luminosity e Color
estão correlacionadas. Quando um dos três componentes de cor altera o valor, a propriedade Color é
recalculada e os eventos PropertyChanged são disparados para todas as quatro propriedades:

public class HslColorViewModel : INotifyPropertyChanged


{
Color color;
string name;

public event PropertyChangedEventHandler PropertyChanged;

public double Hue


{
set
{
if (color.Hue != value)
{
Color = Color.FromHsla(value, color.Saturation, color.Luminosity);
}
}
get
get
{
return color.Hue;
}
}

public double Saturation


{
set
{
if (color.Saturation != value)
{
Color = Color.FromHsla(color.Hue, value, color.Luminosity);
}
}
get
{
return color.Saturation;
}
}

public double Luminosity


{
set
{
if (color.Luminosity != value)
{
Color = Color.FromHsla(color.Hue, color.Saturation, value);
}
}
get
{
return color.Luminosity;
}
}

public Color Color


{
set
{
if (color != value)
{
color = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Hue"));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Saturation"));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Luminosity"));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Color"));

Name = NamedColor.GetNearestColorName(color);
}
}
get
{
return color;
}
}

public string Name


{
private set
{
if (name != value)
{
name = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Name"));
}
}
get
{
return name;
return name;
}
}
}

Quando a propriedade Color é alterada, o método GetNearestColorName estático na classe NamedColor (também
incluído na solução DataBindingDemos) obtém a cor nomeada mais próxima e define a propriedade Name .
Essa propriedade Name tem um acessador set particular e, portanto, não pode ser definida fora da classe.
Quando um ViewModel é definido como uma origem da associação, a infraestrutura de associação anexa um
manipulador ao evento PropertyChanged . Dessa forma, a associação pode ser notificada de alterações nas
propriedades e pode então definir as propriedades de destino com base nos valores alterados.
No entanto, quando uma propriedade de destino (ou a definição Binding de uma propriedade de destino) tem
um BindingMode igual a OneTime , não é necessário que a infraestrutura de associação anexe um manipulador no
evento PropertyChanged . A propriedade de destino é atualizada somente quando o BindingContext é alterado e
não quando a propriedade de origem em si é alterada.
O arquivo XAML Seletor de cor simples cria uma instância do HslColorViewModel no dicionário de recursos da
página e inicializa a propriedade Color . A propriedade BindingContext da Grid é definida como uma extensão
de associação StaticResource para referenciar esse recurso:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.SimpleColorSelectorPage">

<ContentPage.Resources>
<ResourceDictionary>
<local:HslColorViewModel x:Key="viewModel"
Color="MediumTurquoise" />

<Style TargetType="Slider">
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>

<Grid BindingContext="{StaticResource viewModel}">


<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>

<BoxView Color="{Binding Color}"


Grid.Row="0" />

<StackLayout Grid.Row="1"
Margin="10, 0">

<Label Text="{Binding Name}"


HorizontalTextAlignment="Center" />

<Slider Value="{Binding Hue}" />

<Slider Value="{Binding Saturation}" />

<Slider Value="{Binding Luminosity}" />


</StackLayout>
</Grid>
</ContentPage>
A BoxView , o Label e três exibições Slider herdam o contexto de associação da Grid . Essas exibições são
destinos de associação que referenciam as propriedades de origem no ViewModel. Para a propriedade Color de
BoxView e a propriedade Text de Label , as associações de dados são OneWay : As propriedades no modo de
exibição são definidas nas propriedades do ViewModel.
No entanto, a propriedade Value do Slider é TwoWay . Isso permite que cada Slider seja definido no
ViewModel e também que o ViewModel seja definido em cada Slider .
Quando o programa é executado pela primeira vez, a BoxView , o Label e três elementos Slider são definidos
no ViewModel com base na propriedade Color inicial definida quando foi criada uma instância do ViewModel.
Isso é mostrado na captura de tela do iOS à esquerda:

Conforme você manipula os controles deslizantes, a BoxView e o Label são atualizados de acordo, conforme
ilustrado pelas capturas de tela do Android e do UWP.
A criação de uma instância do ViewModel no dicionário de recursos é uma abordagem comum. Também é
possível criar uma instância do ViewModel dentro de marcas de elemento de propriedade para a propriedade
BindingContext . No arquivo XAML Seletor de cor simples, tente remover o HslColorViewModel do dicionário
de recursos e defini-lo como a propriedade BindingContext da Grid desta forma:

<Grid>
<Grid.BindingContext>
<local:HslColorViewModel Color="MediumTurquoise" />
</Grid.BindingContext>

···

</Grid>

O contexto de associação pode ser definido em uma variedade de formas. Às vezes, o arquivo code-behind cria
uma instância do ViewModel e o define como a propriedade BindingContext da página. Essas são todas
abordagens válidas.

Substituindo o modo de associação


Se o modo de associação padrão na propriedade de destino não é adequado para uma associação de dados
específica, é possível substituí-lo definindo a propriedade Mode de Binding (ou a propriedade Mode da extensão
de marcação Binding ) com um dos membros da enumeração BindingMode .
No entanto, a definição da propriedade Mode como TwoWay nem sempre funciona como esperado. Por exemplo,
tente modificar o arquivo XAML Associação de XAML alternativa para incluir TwoWay na definição de
associação:

<Label Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Scale="{Binding Source={x:Reference slider},
Path=Value,
Mode=TwoWay}" />

Pode ser esperado que o Slider seja inicializado com o valor inicial da propriedade Scale , que é 1, mas isso
não acontece. Quando uma associação TwoWay é inicializada, o destino é definido na origem primeiro, o que
significa que a propriedade Scale é definida com o valor padrão de Slider igual a 0. Quando a associação
TwoWay é definida no Slider , o Slider inicialmente é definido da origem.

Defina o modo de associação como OneWayToSource na amostra Associação de XAML alternativa:

<Label Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Scale="{Binding Source={x:Reference slider},
Path=Value,
Mode=OneWayToSource}" />

Agora o Slider é inicializado como 1 (o valor padrão de Scale ), mas a manipulação do Slider não afeta a
propriedade Scale e, portanto, isso não é muito útil.

NOTE
A classe VisualElement define também as propriedades ScaleX e ScaleY , que podem dimensionar o VisualElement
de forma diferente nos sentidos horizontal e vertical.

Uma aplicação muito útil de substituir o modo de associação padrão com TwoWay envolve a propriedade
SelectedItem de ListView . O modo de associação padrão é OneWayToSource . Quando uma associação de dados
é definida na propriedade SelectedItem para referenciar uma propriedade de origem em um ViewModel, essa
propriedade de origem é definida na seleção de ListView . No entanto, em algumas circunstâncias, também é
recomendável inicializar a ListView no ViewModel.
A página Configurações de exemplo demonstra essa técnica. Essa página representa uma implementação
simples de configurações de aplicativo, que frequentemente são definidas em um ViewModel, como este arquivo
SampleSettingsViewModel :

public class SampleSettingsViewModel : INotifyPropertyChanged


{
string name;
DateTime birthDate;
bool codesInCSharp;
double numberOfCopies;
NamedColor backgroundNamedColor;

public event PropertyChangedEventHandler PropertyChanged;

public SampleSettingsViewModel(IDictionary<string, object> dictionary)


{
Name = GetDictionaryEntry<string>(dictionary, "Name");
BirthDate = GetDictionaryEntry(dictionary, "BirthDate", new DateTime(1980, 1, 1));
CodesInCSharp = GetDictionaryEntry<bool>(dictionary, "CodesInCSharp");
NumberOfCopies = GetDictionaryEntry(dictionary, "NumberOfCopies", 1.0);
BackgroundNamedColor = NamedColor.Find(GetDictionaryEntry(dictionary, "BackgroundNamedColor",
"White"));
}

public string Name


{
set { SetProperty(ref name, value); }
get { return name; }
}

public DateTime BirthDate


{
set { SetProperty(ref birthDate, value); }
get { return birthDate; }
}

public bool CodesInCSharp


{
set { SetProperty(ref codesInCSharp, value); }
get { return codesInCSharp; }
}

public double NumberOfCopies


{
set { SetProperty(ref numberOfCopies, value); }
get { return numberOfCopies; }
}

public NamedColor BackgroundNamedColor


{
set
{
if (SetProperty(ref backgroundNamedColor, value))
{
OnPropertyChanged("BackgroundColor");
}
}
get { return backgroundNamedColor; }
}

public Color BackgroundColor


{
get { return BackgroundNamedColor?.Color ?? Color.White; }
}

public void SaveState(IDictionary<string, object> dictionary)


{
dictionary["Name"] = Name;
dictionary["BirthDate"] = BirthDate;
dictionary["CodesInCSharp"] = CodesInCSharp;
dictionary["NumberOfCopies"] = NumberOfCopies;
dictionary["BackgroundNamedColor"] = BackgroundNamedColor.Name;
}

T GetDictionaryEntry<T>(IDictionary<string, object> dictionary, string key, T defaultValue = default(T))


{
return dictionary.ContainsKey(key) ? (T)dictionary[key] : defaultValue;
}

bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)


{
if (Object.Equals(storage, value))
return false;

storage = value;
OnPropertyChanged(propertyName);
return true;
}

protected void OnPropertyChanged([CallerMemberName] string propertyName = null)


{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}

Cada configuração de aplicativo é uma propriedade salva no dicionário de propriedades do Xamarin.Forms em


um método chamado SaveState e carregado desse dicionário no construtor. Na parte inferior da classe estão
dois métodos que ajudam a simplificar ViewModels e torná-lo menos propenso a erros. O método
OnPropertyChanged na parte inferior tem um parâmetro opcional que é definido como a propriedade de chamada.
Isso previne erros de ortografia ao especificar o nome da propriedade como uma cadeia de caracteres.
O método SetProperty na classe faz ainda mais: Ele compara o valor que está sendo definido como a
propriedade com o valor armazenado como um campo e apenas chama OnPropertyChanged quando os dois
valores não são iguais.
A classe define duas propriedades para a cor do plano de fundo: A propriedade
SampleSettingsViewModel
BackgroundNamedColor é do tipo NamedColor , que é uma classe que também está incluída na solução
DataBindingDemos. A propriedade BackgroundColor é do tipo Color e é obtida da propriedade Color do
objeto NamedColor .
A classe NamedColor usa a reflexão do .NET para enumerar todos os campos públicos estáticos na estrutura
Color do Xamarin.Forms e armazená-los com seus nomes em uma coleção acessível na propriedade estática
All :

public class NamedColor : IEquatable<NamedColor>, IComparable<NamedColor>


{
// Instance members
private NamedColor()
{
}

public string Name { private set; get; }

public string FriendlyName { private set; get; }

public Color Color { private set; get; }

public string RgbDisplay { private set; get; }

public bool Equals(NamedColor other)


{
return Name.Equals(other.Name);
}

public int CompareTo(NamedColor other)


{
return Name.CompareTo(other.Name);
}

// Static members
static NamedColor()
{
List<NamedColor> all = new List<NamedColor>();
StringBuilder stringBuilder = new StringBuilder();

// Loop through the public static fields of the Color structure.


foreach (FieldInfo fieldInfo in typeof(Color).GetRuntimeFields())
{
{
if (fieldInfo.IsPublic &&
fieldInfo.IsStatic &&
fieldInfo.FieldType == typeof(Color))
{
// Convert the name to a friendly name.
string name = fieldInfo.Name;
stringBuilder.Clear();
int index = 0;

foreach (char ch in name)


{
if (index != 0 && Char.IsUpper(ch))
{
stringBuilder.Append(' ');
}
stringBuilder.Append(ch);
index++;
}

// Instantiate a NamedColor object.


Color color = (Color)fieldInfo.GetValue(null);

NamedColor namedColor = new NamedColor


{
Name = name,
FriendlyName = stringBuilder.ToString(),
Color = color,
RgbDisplay = String.Format("{0:X2}-{1:X2}-{2:X2}",
(int)(255 * color.R),
(int)(255 * color.G),
(int)(255 * color.B))
};

// Add it to the collection.


all.Add(namedColor);
}
}
all.TrimExcess();
all.Sort();
All = all;
}

public static IList<NamedColor> All { private set; get; }

public static NamedColor Find(string name)


{
return ((List<NamedColor>)All).Find(nc => nc.Name == name);
}

public static string GetNearestColorName(Color color)


{
double shortestDistance = 1000;
NamedColor closestColor = null;

foreach (NamedColor namedColor in NamedColor.All)


{
double distance = Math.Sqrt(Math.Pow(color.R - namedColor.Color.R, 2) +
Math.Pow(color.G - namedColor.Color.G, 2) +
Math.Pow(color.B - namedColor.Color.B, 2));

if (distance < shortestDistance)


{
shortestDistance = distance;
closestColor = namedColor;
}
}
return closestColor.Name;
}
}
}

A classe no projeto DataBindingDemos define uma propriedade chamada Settings do tipo


App
SampleSettingsViewModel . Essa propriedade é inicializada quando é criada uma instância da classe App e o
método SaveState é chamado quando o método OnSleep é chamado:

public partial class App : Application


{
public App()
{
InitializeComponent();

Settings = new SampleSettingsViewModel(Current.Properties);

MainPage = new NavigationPage(new MainPage());


}

public SampleSettingsViewModel Settings { private set; get; }

protected override void OnStart()


{
// Handle when your app starts
}

protected override void OnSleep()


{
// Handle when your app sleeps
Settings.SaveState(Current.Properties);
}

protected override void OnResume()


{
// Handle when your app resumes
}
}

Para obter mais informações sobre os métodos de ciclo de vida do aplicativo, confira o artigo Ciclo de vida do
aplicativo.
Quase todo o restante é manipulado no arquivo SampleSettingsPage.xaml. O BindingContext da página é
definido usando uma extensão de marcação Binding : A origem da associação é a propriedade estática
Application.Current , que é a instância da classe App no projeto e o Path é definido como a propriedade
Settings , que é o objeto SampleSettingsViewModel :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.SampleSettingsPage"
Title="Sample Settings"
BindingContext="{Binding Source={x:Static Application.Current},
Path=Settings}">

<StackLayout BackgroundColor="{Binding BackgroundColor}"


Padding="10"
Spacing="10">

<StackLayout Orientation="Horizontal">
<Label Text="Name: "
VerticalOptions="Center" />

<Entry Text="{Binding Name}"


Placeholder="your name"
HorizontalOptions="FillAndExpand"
VerticalOptions="Center" />
VerticalOptions="Center" />
</StackLayout>

<StackLayout Orientation="Horizontal">
<Label Text="Birth Date: "
VerticalOptions="Center" />

<DatePicker Date="{Binding BirthDate}"


HorizontalOptions="FillAndExpand"
VerticalOptions="Center" />
</StackLayout>

<StackLayout Orientation="Horizontal">
<Label Text="Do you code in C#? "
VerticalOptions="Center" />

<Switch IsToggled="{Binding CodesInCSharp}"


VerticalOptions="Center" />
</StackLayout>

<StackLayout Orientation="Horizontal">
<Label Text="Number of Copies: "
VerticalOptions="Center" />

<Stepper Value="{Binding NumberOfCopies}"


VerticalOptions="Center" />

<Label Text="{Binding NumberOfCopies}"


VerticalOptions="Center" />
</StackLayout>

<Label Text="Background Color:" />

<ListView x:Name="colorListView"
ItemsSource="{x:Static local:NamedColor.All}"
SelectedItem="{Binding BackgroundNamedColor, Mode=TwoWay}"
VerticalOptions="FillAndExpand"
RowHeight="40">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<BoxView Color="{Binding Color}"
HeightRequest="32"
WidthRequest="32"
VerticalOptions="Center" />

<Label Text="{Binding FriendlyName}"


FontSize="24"
VerticalOptions="Center" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>

Todos os filhos da página herdam o contexto de associação. A maioria das outras associações nesta página são
propriedades em SampleSettingsViewModel . A propriedade BackgroundColor é usada para definir a propriedade
BackgroundColor do StackLayout e as propriedades Entry , DatePicker , Switch e Stepper são associadas a
outras propriedades no ViewModel.
A propriedade ItemsSource da ListView é definida como a propriedade estática NamedColor.All . Isso preenche
a ListView com todas as instâncias de NamedColor . Para cada item em ListView , o contexto de associação para
o item é definido como um objeto NamedColor . A BoxView e o Label na ViewCell estão associados às
propriedades em NamedColor .
A propriedade SelectedItem da é do tipo
ListView NamedColor e está associada à propriedade
BackgroundNamedColor de SampleSettingsViewModel :

SelectedItem="{Binding BackgroundNamedColor, Mode=TwoWay}"

O modo de associação padrão de SelectedItem é OneWayToSource , que define a propriedade de ViewModel do


item selecionado. O modo TwoWay permite que o SelectedItem seja inicializado no ViewModel.
No entanto, quando o SelectedItem é definido desta forma, a ListView não rola a tela automaticamente para
mostrar o item selecionado. Um pouco de código no arquivo code-behind é necessário:

public partial class SampleSettingsPage : ContentPage


{
public SampleSettingsPage()
{
InitializeComponent();

if (colorListView.SelectedItem != null)
{
colorListView.ScrollTo(colorListView.SelectedItem,
ScrollToPosition.MakeVisible,
false);
}
}
}

A captura de tela do iOS à esquerda mostra o programa quando ele é executado pela primeira vez. O construtor
em SampleSettingsViewModel inicializa a cor da tela de fundo como branca e isto é o que é selecionado na
ListView :

As outras duas capturas de tela mostram as configurações alteradas. Ao experimentar com essa página, lembre-
se de colocar o programa no modo de suspensão ou encerrá-lo no dispositivo ou no emulador em que está
sendo executado. O encerramento do programa no depurador do Visual Studio não chamará a substituição
OnSleep na classe App .

No próximo artigo, você verá como especificar a Formatação da cadeia de caracteres de associações de dados
que são definidas na propriedade Text de Label .
Links relacionados
Demonstrações de associação de dados (amostra)
Capítulo de associação de dados do catálogo de Xamarin.Forms
Formatação de cadeia de caracteres do
Xamarin.Forms
12/04/2019 • 8 minutes to read • Edit Online

Baixar o exemplo
Às vezes, é conveniente usar associações de dados para exibir a representação de cadeia de caracteres de um
objeto ou um valor. Por exemplo, talvez você deseje usar um Label para exibir o valor atual de um Slider . Nesta
associação de dados, o Slider é a origem e o destino é a propriedade Text do Label .
Ao exibir cadeias de caracteres no código, a ferramenta mais avançada é o método estático String.Format . A
cadeia de caracteres de formatação inclui códigos de formatação para diversos tipos de objetos, sendo que você
pode incluir outros textos junto com os valores que estão sendo formatados. Confira o artigo Formatando tipos
no .NET para obter mais informações sobre a formatação da cadeia de caracteres.

A propriedade StringFormat
Este recurso é levado para as associações de dados: Você define a propriedade StringFormat de Binding (ou a
propriedade StringFormat da extensão de marcação Binding ) como uma cadeia de caracteres de formatação
padrão do .NET com um espaço reservado:

<Slider x:Name="slider" />


<Label Text="{Binding Source={x:Reference slider},
Path=Value,
StringFormat='The slider value is {0:F2}'}" />

Observe que a cadeia de caracteres de formatação é delimitada por caracteres de aspas simples (apóstrofo) para
ajudar o analisador de XAML a evitar tratar as chaves como outra extensão de marcação XAML. De outra forma,
essa cadeia de caracteres sem o caractere de aspas simples é a mesma cadeia de caracteres usada para exibir um
valor de ponto flutuante em uma chamada a String.Format . Uma especificação de formatação de F2 faz com
que o valor seja exibido com duas casas decimais.
A propriedade StringFormat só faz sentido quando a propriedade de destino é do tipo string e o modo de
associação é OneWay ou TwoWay . Para vinculações bidirecionais, o StringFormat só é aplicável a valores que
passam da origem para o destino.
Como você verá no próximo artigo sobre o Caminho de associação, as associações de dados podem se tornar
muito complexas e complicadas. Ao depurar essas associações de dados, você pode adicionar um Label ao
arquivo XAML com um StringFormat para exibir alguns resultados intermediários. Mesmo se você usá-lo
somente para exibir o tipo de um objeto, isso pode ser útil.
A página Formatação da cadeia de caracteres ilustra vários usos da propriedade StringFormat :
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
x:Class="DataBindingDemos.StringFormattingPage"
Title="String Formatting">

<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Label">
<Setter Property="HorizontalTextAlignment" Value="Center" />
</Style>

<Style TargetType="BoxView">
<Setter Property="Color" Value="Blue" />
<Setter Property="HeightRequest" Value="2" />
<Setter Property="Margin" Value="0, 5" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>

<StackLayout Margin="10">
<Slider x:Name="slider" />
<Label Text="{Binding Source={x:Reference slider},
Path=Value,
StringFormat='The slider value is {0:F2}'}" />

<BoxView />

<TimePicker x:Name="timePicker" />


<Label Text="{Binding Source={x:Reference timePicker},
Path=Time,
StringFormat='The TimeSpan is {0:c}'}" />

<BoxView />

<Entry x:Name="entry" />


<Label Text="{Binding Source={x:Reference entry},
Path=Text,
StringFormat='The Entry text is &quot;{0}&quot;'}" />

<BoxView />

<StackLayout BindingContext="{x:Static sys:DateTime.Now}">


<Label Text="{Binding}" />
<Label Text="{Binding Path=Ticks,
StringFormat='{0:N0} ticks since 1/1/1'}" />
<Label Text="{Binding StringFormat='The {{0:MMMM}} specifier produces {0:MMMM}'}" />
<Label Text="{Binding StringFormat='The long date is {0:D}'}" />
</StackLayout>

<BoxView />

<StackLayout BindingContext="{x:Static sys:Math.PI}">


<Label Text="{Binding}" />
<Label Text="{Binding StringFormat='PI to 4 decimal points = {0:F4}'}" />
<Label Text="{Binding StringFormat='PI in scientific notation = {0:E7}'}" />
</StackLayout>
</StackLayout>
</ContentPage>

As associações no Slider e no TimePicker mostram o uso de especificações de formato específicas aos tipos de
dados double e TimeSpan . O StringFormat que exibe o texto na exibição Entry demonstra como especificar
aspas duplas na cadeia de caracteres de formatação com o uso da entidade HTML &quot; .
A próxima seção do arquivo XAML é um StackLayout com um BindingContext definido como uma extensão de
marcação x:Static que referencia a propriedade estática DateTime.Now . A primeira associação não tem
nenhuma propriedade:

<Label Text="{Binding}" />

Isso apenas exibe o valor DateTime do BindingContext com a formatação padrão. A segunda associação exibe a
propriedade Ticks de DateTime , enquanto as outras duas associações exibem o próprio DateTime com
formatação específica. Observe este StringFormat :

<Label Text="{Binding StringFormat='The {{0:MMMM}} specifier produces {0:MMMM}'}" />

Caso precise exibir chaves direitas ou esquerdas na cadeia de caracteres de formatação, basta usar um par de
chaves.
A última seção define o BindingContext com valor de Math.PI e o exibe com a formatação padrão e dois tipos
diferentes de formatação numérica.
Este é o programa em execução:

ViewModels e formatação de cadeia de caracteres


Quando estiver usando Label e StringFormat para exibir o valor de uma exibição que também é o destino de
um ViewModel, você poderá definir a associação na exibição como o Label ou no ViewModel como a Label .
Em geral, a segunda abordagem é melhor porque verifica se as associações entre o View e o ViewModel estão
funcionando.
Essa abordagem é apresentada na amostra Melhor Seletor de Cor, que usa o mesmo ViewModel do programa
Seletor de Cor Simples mostrado no artigo Modo de associação:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.BetterColorSelectorPage"
Title="Better Color Selector">

<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Slider">
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
</Style>

<Style TargetType="Label">
<Setter Property="HorizontalTextAlignment" Value="Center" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>

<StackLayout>
<StackLayout.BindingContext>
<local:HslColorViewModel Color="Sienna" />
</StackLayout.BindingContext>

<BoxView Color="{Binding Color}"


VerticalOptions="FillAndExpand" />

<StackLayout Margin="10, 0">


<Label Text="{Binding Name}" />

<Slider Value="{Binding Hue}" />


<Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}" />

<Slider Value="{Binding Saturation}" />


<Label Text="{Binding Saturation, StringFormat='Saturation = {0:F2}'}" />

<Slider Value="{Binding Luminosity}" />


<Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}" />
</StackLayout>
</StackLayout>
</ContentPage>

Agora há três pares de elementos Slider e Label associados à mesma propriedade de origem no objeto
HslColorViewModel . A única diferença é que Label tem uma propriedade StringFormat para exibir cada valor
Slider .
Você deve estar se perguntando como poderá exibir valores RGB (vermelho, verde, azul) em formato hexadecimal
tradicional de dois dígitos. Esses valores inteiros não estão diretamente disponíveis na estrutura Color . Uma
solução é calcular valores inteiros dos componentes de cor dentro do ViewModel e expô-los como propriedades.
Em seguida, você pode formatá-los usando a especificação de formatação X2 .
Outra abordagem é mais geral: Você pode gravar um conversor de valor de associação como abordado no artigo
posterior, Conversores de valor de associação.
No entanto, o próximo artigo explora o Caminho de associação com mais detalhes e mostra como você pode
usá-lo para referenciar subpropriedades e itens em coleções.

Links relacionados
Demonstrações de associação de dados (amostra)
Capítulo de associação de dados do catálogo de Xamarin.Forms
Caminho de associação do Xamarin.Forms
12/04/2019 • 6 minutes to read • Edit Online

Baixar o exemplo
Em todos os exemplos anteriores de associação de dados, a propriedade Path da classe Binding (ou a
propriedade Path da extensão de marcação Binding ) foi definida como uma única propriedade. Na verdade, é
possível definir Path como uma subpropriedade (uma propriedade de uma propriedade) ou como um membro
de uma coleção.
Por exemplo, suponha que a página contenha um TimePicker :

<TimePicker x:Name="timePicker">

A propriedade Time de TimePicker é do tipo TimeSpan , mas talvez você deseje criar uma associação de dados
que referencie a propriedade TotalSeconds desse valor TimeSpan . Esta é a associação de dados:

{Binding Source={x:Reference timePicker},


Path=Time.TotalSeconds}

A propriedade Time é do tipo TimeSpan , que tem uma propriedade TotalSeconds . As propriedades Time e
TotalSeconds são simplesmente conectadas com um ponto. Os itens da cadeia de caracteres Path sempre se
referem a propriedades e não aos tipos dessas propriedades.
Esse exemplo e vários outros são mostrados na página Variações de caminho:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:globe="clr-namespace:System.Globalization;assembly=mscorlib"
x:Class="DataBindingDemos.PathVariationsPage"
Title="Path Variations"
x:Name="page">
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Label">
<Setter Property="FontSize" Value="Large" />
<Setter Property="HorizontalTextAlignment" Value="Center" />
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>

<StackLayout Margin="10, 0">


<TimePicker x:Name="timePicker" />

<Label Text="{Binding Source={x:Reference timePicker},


Path=Time.TotalSeconds,
StringFormat='{0} total seconds'}" />

<Label Text="{Binding Source={x:Reference page},


Path=Content.Children.Count,
StringFormat='There are {0} children in this StackLayout'}" />

<Label Text="{Binding Source={x:Static globe:CultureInfo.CurrentCulture},


Path=DateTimeFormat.DayNames[3],
StringFormat='The middle day of the week is {0}'}" />

<Label>
<Label.Text>
<Binding Path="DateTimeFormat.DayNames[3]"
StringFormat="The middle day of the week in France is {0}">
<Binding.Source>
<globe:CultureInfo>
<x:Arguments>
<x:String>fr-FR</x:String>
</x:Arguments>
</globe:CultureInfo>
</Binding.Source>
</Binding>
</Label.Text>
</Label>

<Label Text="{Binding Source={x:Reference page},


Path=Content.Children[1].Text.Length,
StringFormat='The second Label has {0} characters'}" />
</StackLayout>
</ContentPage>

No segundo Label , a origem da associação é a página propriamente dita. A propriedade Content é do tipo
StackLayout , que tem uma propriedade Children do tipo IList<View> , que, por sua vez, tem uma propriedade
Count que indica o número de filhos.

Caminhos com indexadores


A associação no terceiro Label nas páginas Variações de caminho referencia a classe CultureInfo no
namespace System.Globalization :
<Label Text="{Binding Source={x:Static globe:CultureInfo.CurrentCulture},
Path=DateTimeFormat.DayNames[3],
StringFormat='The middle day of the week is {0}'}" />

A origem é definida como a propriedade estática CultureInfo.CurrentCulture , que é um objeto do tipo


CultureInfo . Esse classe define uma propriedade chamada DateTimeFormat do tipo DateTimeFormatInfo que
contém uma coleção DayNames . O índice seleciona o quarto item.
O quarto Label faz algo similar, mas para a cultura associada à França. A propriedade Source da associação é
definida como o objeto CultureInfo com um construtor:

<Label>
<Label.Text>
<Binding Path="DateTimeFormat.DayNames[3]"
StringFormat="The middle day of the week in France is {0}">
<Binding.Source>
<globe:CultureInfo>
<x:Arguments>
<x:String>fr-FR</x:String>
</x:Arguments>
</globe:CultureInfo>
</Binding.Source>
</Binding>
</Label.Text>
</Label>

Confira Passando argumentos de construtor para obter mais detalhes sobre como especificar argumentos de
construtor em XAML.
Por fim, o último exemplo é semelhante ao segundo, exceto que ele referencia um dos filhos do StackLayout :

<Label Text="{Binding Source={x:Reference page},


Path=Content.Children[1].Text.Length,
StringFormat='The first Label has {0} characters'}" />

Esse filho é um Label , que tem uma propriedade Text do tipo String , que, por sua vez, tem uma propriedade
Length . O primeiro Label relata o TimeSpan definido no TimePicker ; portanto, quando esse texto é alterado, o
último Label também é alterado.
Este é o programa em execução:
Caminhos complexos de depuração
Definições de caminhos complexos podem ser difíceis de construir: Você precisa saber o tipo de cada
subpropriedade ou o tipo dos itens na coleção para adicionar corretamente a próxima subpropriedade, mas os
tipos propriamente ditos não são exibidos no caminho. Uma boa técnica é criar o caminho de forma incremental e
examinar os resultados intermediários. Para esse último exemplo, você pode começar sem nenhuma definição de
Path :

<Label Text="{Binding Source={x:Reference page},


StringFormat='{0}'}" />

Isso exibe o tipo da origem da associação ou DataBindingDemos.PathVariationsPage . Você sabe que


PathVariationsPage deriva de ContentPage e, portanto, ele tem uma propriedade Content :

<Label Text="{Binding Source={x:Reference page},


Path=Content,
StringFormat='{0}'}" />

O tipo da propriedade Content agora é revelado como sendo Xamarin.Forms.StackLayout . Adicione a propriedade
Children ao Path e o tipo será Xamarin.Forms.ElementCollection'1[Xamarin.Forms.View] , que é uma classe interna
do Xamarin.Forms, mas, obviamente, um tipo de coleção. Adicione um índice a ele e o tipo será
Xamarin.Forms.Label . Continue dessa maneira.

Como o Xamarin.Forms processa o caminho de associação, ele instala um manipulador PropertyChanged em


qualquer objeto no caminho que implementa a interface INotifyPropertyChanged . Por exemplo, a associação final
reage a uma alteração no primeiro Label porque a propriedade Text é alterada.
Se uma propriedade no caminho de associação não implementar INotifyPropertyChanged , todas as alterações a
essa propriedade serão ignoradas. Algumas alterações podem invalidar por completo o caminho de associação.
Portanto, você deverá usar essa técnica somente quando a cadeia de caracteres de propriedades e
subpropriedades nunca se tornarem inválidas.

Links relacionados
Demonstrações de associação de dados (amostra)
Capítulo de associação de dados do catálogo de Xamarin.Forms
Conversores de valor de associação do
Xamarin.Forms
12/04/2019 • 17 minutes to read • Edit Online

Baixar o exemplo
Normalmente, associações de dados transferem dados de uma propriedade de origem para uma propriedade de
destino e, em alguns casos, da propriedade de destino para a propriedade de origem. Essa transferência é simples
quando as propriedades de origem e de destino são do mesmo tipo ou quando um tipo pode ser convertido para
outro por meio de uma conversão implícita. Quando não é esse o caso, é necessário realizar uma conversão de
tipo.
No artigo Formatação de Cadeia de Caracteres, você viu como é possível usar a propriedade StringFormat de
uma associação de dados para converter qualquer tipo em uma cadeia de caracteres. Para outros tipos de
conversões, você precisa escrever código especializado em uma classe que implementa a interface
IValueConverter . ( A Plataforma Universal do Windows contém uma classe semelhante chamada IValueConverter
no namespace Windows.UI.Xaml.Data , mas essa IValueConverter está no namespace Xamarin.Forms .) As classes
que implementam IValueConverter são denominadas conversores de valor, mas também são conhecidas como
conversores de associação ou conversores de valor de associação.

A interface IValueConverter
Digamos que você queira definir uma associação de dados em que a propriedade de origem é do tipo int , mas a
propriedade de destino é um bool . Você quer que essa associação de dados produza um valor de false quando
a origem do inteiro for igual a 0 e, caso contrário, true .
É possível fazer isso com uma classe que implemente a interface IValueConverter :

public class IntToBoolConverter : IValueConverter


{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (int)value != 0;
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return (bool)value ? 1 : 0;
}
}

Você define uma instância dessa classe como a propriedade Converter da classe Binding ou como a propriedade
Converter da extensão de marcação Binding . Essa classe se torna parte da associação de dados.

O método Convert é chamado quando dados são passados da origem para o destino nas associações OneWay ou
TwoWay . O parâmetro value é o objeto ou o valor da origem da associação de dados. O método deve retornar
um valor com o tipo do destino da associação de dados. O método mostrado aqui converte o parâmetro value
para um int e, em seguida, o compara com 0 para um valor retornado de bool .
O método ConvertBack é chamado quando dados são passados do destino para a origem nas associações
TwoWay ou OneWayToSource . ConvertBack realiza a conversão oposta: Ele pressupõe que o parâmetro value é um
bool do destino e o converte em um valor retornado de int para a fonte.
Se a associação de dados também incluir uma configuração de StringFormat , o conversor de valor será invocado
antes que o resultado seja formatado como uma cadeia de caracteres.
A página Habilitar Botões no exemplo Demonstrações de Associação de Dados demonstra como usar esse
conversor de valor em uma associação de dados. É criada uma instância de IntToBoolConverter no dicionário de
recursos da página. Em seguida, ele é referenciado com uma extensão de marcação StaticResource para definir a
propriedade Converter nas duas associações de dados. É muito comum compartilhar conversores de dados entre
várias associações de dados na página:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.EnableButtonsPage"
Title="Enable Buttons">
<ContentPage.Resources>
<ResourceDictionary>
<local:IntToBoolConverter x:Key="intToBool" />
</ResourceDictionary>
</ContentPage.Resources>

<StackLayout Padding="10, 0">


<Entry x:Name="entry1"
Text=""
Placeholder="enter search term"
VerticalOptions="CenterAndExpand" />

<Button Text="Search"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
IsEnabled="{Binding Source={x:Reference entry1},
Path=Text.Length,
Converter={StaticResource intToBool}}" />

<Entry x:Name="entry2"
Text=""
Placeholder="enter destination"
VerticalOptions="CenterAndExpand" />

<Button Text="Submit"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
IsEnabled="{Binding Source={x:Reference entry2},
Path=Text.Length,
Converter={StaticResource intToBool}}" />
</StackLayout>
</ContentPage>

Se um conversor de valor for usado em várias páginas de seu aplicativo, você poderá criar uma instância dele no
dicionário de recursos no arquivo App.xaml.
A página Habilitar Botões demonstra uma necessidade comum quando um Button executa uma operação com
base no texto que o usuário digita em uma exibição de Entry . Se nada tiver sido digitado no Entry , o Button
deverá ser desabilitado. Cada Button contém uma associação de dados em sua propriedade IsEnabled . A origem
da associação de dados é a propriedade Length da propriedade Text do Entry correspondente. Se essa
propriedade Length não for 0, o conversor de valor retornará true e Button será habilitado:
Observe que a propriedade Text em cada Entry é inicializada como uma cadeia de caracteres vazia. A
propriedade Text é null por padrão e a associação de dados não funcionará nesse caso.
Alguns conversores de valor são escritos especificamente para aplicativos específicos, enquanto outros são
generalizados. Se você souber que um conversor de valor será usado apenas em associações de OneWay , o
método ConvertBack poderá simplesmente retornar null .
O método Convert mostrado acima supõe implicitamente que o argumento value é do tipo int e que o valor
retornado deve ser do tipo bool . Da mesma forma, o método ConvertBack supõe que o argumento value é do
tipo bool e que o valor retornado é int . Se não for esse o caso, ocorrerá uma exceção de tempo de execução.
Você pode escrever conversores de valor de forma que eles sejam mais generalizados e aceitem vários tipos de
dados diferentes. Os métodos Convert e ConvertBack podem usar os operadores as ou is com o parâmetro
value ou podem chamar GetType nesse parâmetro para determinar seu tipo e, em seguida, fazer algo
apropriado. O tipo esperado do valor retornado de cada método é determinado pelo parâmetro targetType . Às
vezes, conversores de valor são usados com associações de dados com tipos de destino diferentes. O conversor de
valor pode usar o argumento targetType para executar uma conversão para o tipo correto.
Se a conversão que está sendo executada for diferente para culturas diferentes, use o parâmetro culture para
essa finalidade. O argumento parameter para Convert e ConvertBack é abordado posteriormente neste artigo.

Propriedades do conversor de associação


As classes do conversor de valor podem ter propriedades e parâmetros genéricos. Este conversor de valor
específico converte um bool da origem para um objeto do tipo T para o destino:
public class BoolToObjectConverter<T> : IValueConverter
{
public T TrueObject { set; get; }

public T FalseObject { set; get; }

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (bool)value ? TrueObject : FalseObject;
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((T)value).Equals(TrueObject);
}
}

A página Alternar Indicadores demonstra como ele pode ser usado para exibir o valor de uma exibição de
Switch . Embora seja comum para instanciar os conversores de valor como recursos em um dicionário de
recursos, esta página demonstra uma alternativa: Cada conversor de valor é instanciado entre marcas de elemento
de propriedade Binding.Converter . O x:TypeArguments indica o argumento genérico e TrueObject e FalseObject
são configurados como objetos desse tipo:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.SwitchIndicatorsPage"
Title="Switch Indicators">
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Label">
<Setter Property="FontSize" Value="18" />
<Setter Property="VerticalOptions" Value="Center" />
</Style>

<Style TargetType="Switch">
<Setter Property="VerticalOptions" Value="Center" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>

<StackLayout Padding="10, 0">


<StackLayout Orientation="Horizontal"
VerticalOptions="CenterAndExpand">
<Label Text="Subscribe?" />
<Switch x:Name="switch1" />
<Label>
<Label.Text>
<Binding Source="{x:Reference switch1}"
Path="IsToggled">
<Binding.Converter>
<local:BoolToObjectConverter x:TypeArguments="x:String"
TrueObject="Of course!"
FalseObject="No way!" />
</Binding.Converter>
</Binding>
</Label.Text>
</Label>
</StackLayout>

<StackLayout Orientation="Horizontal"
VerticalOptions="CenterAndExpand">
<Label Text="Allow popups?" />
<Switch x:Name="switch2" />
<Label>
<Label>
<Label.Text>
<Binding Source="{x:Reference switch2}"
Path="IsToggled">
<Binding.Converter>
<local:BoolToObjectConverter x:TypeArguments="x:String"
TrueObject="Yes"
FalseObject="No" />
</Binding.Converter>
</Binding>
</Label.Text>
<Label.TextColor>
<Binding Source="{x:Reference switch2}"
Path="IsToggled">
<Binding.Converter>
<local:BoolToObjectConverter x:TypeArguments="Color"
TrueObject="Green"
FalseObject="Red" />
</Binding.Converter>
</Binding>
</Label.TextColor>
</Label>
</StackLayout>

<StackLayout Orientation="Horizontal"
VerticalOptions="CenterAndExpand">
<Label Text="Learn more?" />
<Switch x:Name="switch3" />
<Label FontSize="18"
VerticalOptions="Center">
<Label.Style>
<Binding Source="{x:Reference switch3}"
Path="IsToggled">
<Binding.Converter>
<local:BoolToObjectConverter x:TypeArguments="Style">
<local:BoolToObjectConverter.TrueObject>
<Style TargetType="Label">
<Setter Property="Text" Value="Indubitably!" />
<Setter Property="FontAttributes" Value="Italic, Bold" />
<Setter Property="TextColor" Value="Green" />
</Style>
</local:BoolToObjectConverter.TrueObject>

<local:BoolToObjectConverter.FalseObject>
<Style TargetType="Label">
<Setter Property="Text" Value="Maybe later" />
<Setter Property="FontAttributes" Value="None" />
<Setter Property="TextColor" Value="Red" />
</Style>
</local:BoolToObjectConverter.FalseObject>
</local:BoolToObjectConverter>
</Binding.Converter>
</Binding>
</Label.Style>
</Label>
</StackLayout>
</StackLayout>
</ContentPage>

No último dos três pares de Switch e Label , o argumento genérico é definido como Style e objetos Style
inteiros são fornecidos para os valores de TrueObject e FalseObject . Eles substituem o estilo implícito de Label
definido no dicionário de recursos, portanto, as propriedades do estilo são atribuídas explicitamente ao Label .
Ativar/desativar o Switch faz com que o Label correspondente reflita a alteração:
Também é possível usar Triggers para implementar alterações semelhantes na interface do usuário com base em
outras exibições.

Parâmetros do conversor de associação


A classe Binding define uma propriedade ConverterParameter e a extensão de marcação Binding também define
uma propriedade ConverterParameter . Se essa propriedade for definida, o valor será passado para os métodos
Convert e ConvertBack como o argumento parameter . Mesmo se a instância do conversor de valor for
compartilhada entre várias associações de dados, o ConverterParameter poderá ser diferente para realizar
conversões de alguma forma diferentes.
O uso de ConverterParameter é demonstrado com um programa de seleção de cor. Nesse caso, o
RgbColorViewModel tem três propriedades do tipo double denominadas Red , Green , e Blue que ele usa para
construir um valor de Color :

public class RgbColorViewModel : INotifyPropertyChanged


{
Color color;
string name;

public event PropertyChangedEventHandler PropertyChanged;

public double Red


{
set
{
if (color.R != value)
{
Color = new Color(value, color.G, color.B);
}
}
get
{
return color.R;
}
}

public double Green


{
set
{
if (color.G != value)
{
{
Color = new Color(color.R, value, color.B);
}
}
get
{
return color.G;
}
}

public double Blue


{
set
{
if (color.B != value)
{
Color = new Color(color.R, color.G, value);
}
}
get
{
return color.B;
}
}

public Color Color


{
set
{
if (color != value)
{
color = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Red"));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Green"));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Blue"));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Color"));

Name = NamedColor.GetNearestColorName(color);
}
}
get
{
return color;
}
}

public string Name


{
private set
{
if (name != value)
{
name = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Name"));
}
}
get
{
return name;
}
}
}

As propriedades Red , Green e Blue variam entre 0 e 1. No entanto, talvez você prefira que os componentes
sejam exibidos como valores hexadecimais de dois dígitos.
Para exibi-los como valores hexadecimais em XAML, eles devem ser multiplicados por 255, convertidos em um
inteiro e, em seguida, formatados com uma especificação de "X2" na propriedade StringFormat . As duas
primeiras tarefas (multiplicar por 255 e converter em um número inteiro) podem ser realizadas pelo conversor de
valor. Para tornar o conversor de valor tão generalizado quanto possível, o fator de multiplicação pode ser
especificado com a propriedade ConverterParameter , o que significa que ele insere os métodos Convert e
ConvertBack como o argumento parameter :

public class DoubleToIntConverter : IValueConverter


{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (int)Math.Round((double)value * GetParameter(parameter));
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return (int)value / GetParameter(parameter);
}

double GetParameter(object parameter)


{
if (parameter is double)
return (double)parameter;

else if (parameter is int)


return (int)parameter;

else if (parameter is string)


return double.Parse((string)parameter);

return 1;
}
}

O Convert é convertido de um double para int ao multiplicar pelo valor de parameter ; o ConvertBack divide o
argumento value inteiro pelo parameter e retorna um resultado double . (No programa mostrado abaixo, o
conversor de valor é usado apenas para formatação da cadeia de caracteres e, portanto, ConvertBack não é
usado.)
O tipo do argumento parameter provavelmente será diferente dependendo de a associação de dados estar
definida no código ou em XAML. Se a propriedade ConverterParameter de Binding estiver definida no código,
será provável que ela esteja definida como um valor numérico:

binding.ConverterParameter = 255;

A propriedade ConverterParameter é do tipo Object , portanto, o compilador de C# interpreta o literal 255 como
um número inteiro e define a propriedade com esse valor.
Em XAML, no entanto, é provável que o ConverterParameter esteja definido desta forma:

<Label Text="{Binding Red,


Converter={StaticResource doubleToInt},
ConverterParameter=255,
StringFormat='Red = {0:X2}'}" />

O 255 é semelhante a um número, mas como ConverterParameter é do tipo Object , o analisador de XAML trata
o 255 como uma cadeia de caracteres.
Por esse motivo, o conversor de valor mostrado acima inclui um método GetParameter separado que lida com os
casos de parameter ser do tipo double , int ou string .
A página Seletor de Cor RGB cria uma instância de DoubleToIntConverter em seu dicionário de recursos após a
definição de dois estilos implícitos:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.RgbColorSelectorPage"
Title="RGB Color Selector">
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Slider">
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
</Style>

<Style TargetType="Label">
<Setter Property="HorizontalTextAlignment" Value="Center" />
</Style>

<local:DoubleToIntConverter x:Key="doubleToInt" />


</ResourceDictionary>
</ContentPage.Resources>

<StackLayout>
<StackLayout.BindingContext>
<local:RgbColorViewModel Color="Gray" />
</StackLayout.BindingContext>

<BoxView Color="{Binding Color}"


VerticalOptions="FillAndExpand" />

<StackLayout Margin="10, 0">


<Label Text="{Binding Name}" />

<Slider Value="{Binding Red}" />


<Label Text="{Binding Red,
Converter={StaticResource doubleToInt},
ConverterParameter=255,
StringFormat='Red = {0:X2}'}" />

<Slider Value="{Binding Green}" />


<Label Text="{Binding Green,
Converter={StaticResource doubleToInt},
ConverterParameter=255,
StringFormat='Green = {0:X2}'}" />

<Slider Value="{Binding Blue}" />


<Label>
<Label.Text>
<Binding Path="Blue"
StringFormat="Blue = {0:X2}"
Converter="{StaticResource doubleToInt}">
<Binding.ConverterParameter>
<x:Double>255</x:Double>
</Binding.ConverterParameter>
</Binding>
</Label.Text>
</Label>
</StackLayout>
</StackLayout>
</ContentPage>

Os valores das propriedades Red e Green são exibidos com uma extensão de marcação Binding . A propriedade
Blue , no entanto, instancia a classe Binding para demonstrar como um valor de double explícito pode ser
definido como a propriedade ConverterParameter .
Este é o resultado:

Links relacionados
Demonstrações de associação de dados (amostra)
Capítulo de associação de dados do catálogo de Xamarin.Forms
Fallbacks de associação do Xamarin.Forms
12/04/2019 • 7 minutes to read • Edit Online

Baixar o exemplo
Às vezes, as associações de dados falham porque a origem da associação não pode ser resolvida ou porque a
associação tem êxito, mas retorna um valor null . Embora esses cenários possam ser manipulados com
conversores de valor ou outro código adicional, as associações de dados poderão se tornar mais robustas com a
definição de valores de fallback a serem usados se o processo de associação falhar. Isso pode ser feito com a
definição das propriedades FallbackValue e TargetNullValue em uma expressão de associação. Como essas
propriedades residem na classe BindingBase , elas podem ser usadas com associações, associações compiladas e
com a extensão de marcação Binding .

NOTE
O uso das propriedades FallbackValue e TargetNullValue em uma expressão de associação é opcional.

Definindo um valor de fallback


A propriedade FallbackValue permite a definição de um valor de fallback que será usado quando a origem da
associação não puder ser resolvida. Um cenário comum para definir essa propriedade é ao fazer a associação a
propriedades de origem que podem não existir em todos os objetos em uma coleção associada de tipos
heterogêneos.
A página MonkeyDetail ilustra a definição da propriedade FallbackValue :

<Label Text="{Binding Population, FallbackValue='Population size unknown'}"


... />

A associação no Label definirá um valor FallbackValue que será definido no destino se a origem da associação
não puder ser resolvida. Portanto, o valor definido pela propriedade FallbackValue será exibido se a propriedade
Population não existir no objeto associado. Observe que aqui o valor da propriedade FallbackValue é delimitado
por caracteres de aspas simples (apóstrofo).
Em vez de definir os valores da propriedade FallbackValue de forma embutida, recomendamos defini-los como
recursos em um ResourceDictionary . A vantagem dessa abordagem é que esses valores são definidos uma única
vez em uma só localização e são mais facilmente localizáveis. Em seguida, os recursos podem ser recuperados
usando a extensão de marcação StaticResource :

<Label Text="{Binding Population, FallbackValue={StaticResource populationUnknown}}"


... />

NOTE
Não é possível definir a propriedade FallbackValue com uma expressão de associação.

Este é o programa em execução:


Quando a propriedade FallbackValue não está definida em uma expressão de associação e o caminho de
associação ou parte do caminho não está resolvido, BindableProperty.DefaultValue é definido no destino. No
entanto, quando a propriedade FallbackValue está definida e o caminho de associação ou parte do caminho não
está resolvido, o valor da propriedade de valor FallbackValue é definido no destino. Portanto, na página
MonkeyDetail, o Label exibe "Tamanho da população desconhecido", porque o objeto associado não tem uma
propriedade Population .

IMPORTANT
Um conversor de valor definido não é executado em uma expressão de associação quando a propriedade FallbackValue
está definida.

Definindo um valor de substituição nulo


A propriedade TargetNullValue permite a definição de um valor de substituição que será usado quando a origem
da associação for resolvida, mas o valor for null . Um cenário comum para definir essa propriedade é ao associar
as propriedades de origem que podem ser null em uma coleção associada.
A página Monkeys ilustra a definição da propriedade TargetNullValue :

<ListView ItemsSource="{Binding Monkeys}"


...>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
...
<Image Source="{Binding ImageUrl,
TargetNullValue='https://upload.wikimedia.org/wikipedia/commons/2/20/Point_d_interrogation.jpg'}"
... />
...
<Label Text="{Binding Location, TargetNullValue='Location unknown'}"
... />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

As associações no Image e Label definem valores TargetNullValue que serão aplicados se o caminho de
associação retornar null . Portanto, os valores definidos pelas propriedades TargetNullValue serão exibidos para
todos os objetos na coleção em que as propriedades ImageUrl e Location não estiverem definidas. Observe que
aqui os valores da propriedade TargetNullValue são delimitados por caracteres de aspas simples (apóstrofo).
Em vez de definir os valores da propriedade TargetNullValue de forma embutida, recomendamos defini-los como
recursos em um ResourceDictionary . A vantagem dessa abordagem é que esses valores são definidos uma única
vez em uma só localização e são mais facilmente localizáveis. Em seguida, os recursos podem ser recuperados
usando a extensão de marcação StaticResource :
<Image Source="{Binding ImageUrl, TargetNullValue={StaticResource fallbackImageUrl}}"
... />
<Label Text="{Binding Location, TargetNullValue={StaticResource locationUnknown}}"
... />

NOTE
Não é possível definir a propriedade TargetNullValue com uma expressão de associação.

Este é o programa em execução:

Quando a propriedade TargetNullValue não estiver definida em uma expressão de associação, um valor de
origem igual a null será convertido se um conversor de valor for definido, formatado se um StringFormat for
definido e o resultado será então definido no destino. No entanto, quando a propriedade TargetNullValue for
definida, um valor de origem igual a null será convertido se um conversor de valor for definido e se ele ainda for
null após a conversão, o valor da propriedade TargetNullValue será definido no destino.

IMPORTANT
A formatação de cadeia de caracteres não é aplicada em uma expressão de associação quando a propriedade
TargetNullValue está definida.

Links relacionados
Demonstrações de associação de dados (amostra)
A interface de comando do Xamarin.Forms
12/04/2019 • 30 minutes to read • Edit Online

Baixar o exemplo
Na arquitetura MVVM (Model-View -ViewModel), as associações de dados são definidas entre propriedades no
ViewModel, que geralmente é uma classe derivada de INotifyPropertyChanged , e propriedades no View, que
geralmente é o arquivo XAML. Às vezes, um aplicativo tem necessidades que vão além dessas associações de
propriedade ao exigir que o usuário inicie os comandos que afetam algo no ViewModel. Esses comandos
geralmente são sinalizados por cliques de botões ou toques de dedos e são tradicionalmente processados no
arquivo code-behind em um manipulador para o evento Clicked do Button ou o evento Tapped de um
TapGestureRecognizer .

A interface de comando oferece uma abordagem alternativa à implementação de comandos, que é bem mais
adequada à arquitetura MVVM. O próprio ViewModel pode conter comandos, que são métodos executados em
reação a uma atividade específica no View, como um clique Button . Associações de dados são definidas entre
esses comandos e o Button .
Para permitir uma associação de dados entre um Button e um ViewModel, o Button define duas propriedades:
Command do tipo System.Windows.Input.ICommand
CommandParameter do tipo Object

Para usar a interface de comando, defina uma associação de dados que direcione a propriedade Command do
Button , em que a origem é uma propriedade no ViewModel do tipo ICommand . O ViewModel contém um código
associado a essa propriedade ICommand executada quando se clica no botão. É possível definir CommandParameter
como dados arbitrários para distinguir entre vários botões se eles forem todos associados à mesma propriedade
ICommand no ViewModel.

As propriedades Command e CommandParameter também são definidas pelas seguintes classes:


MenuItem e ToolbarItem , portanto, derivado de MenuItem
TextCell e ImageCell , portanto, derivado de TextCell
TapGestureRecognizer

SearchBar define uma propriedade SearchCommand do tipo ICommand e uma propriedade SearchCommandParameter
. A propriedade RefreshCommand de ListView também é do tipo ICommand .
Todos esses comandos podem ser manipulados dentro de um ViewModel, de forma que ele não dependa do
objeto específico da interface do usuário no View.

A interface ICommand
A interface System.Windows.Input.ICommand não faz parte do Xamarin.Forms. Ela é definida no lugar do
namespace System.Windows.Input e consiste em dois métodos e um evento:
public interface ICommand
{
public void Execute (Object parameter);

public bool CanExecute (Object parameter);

public event EventHandler CanExecuteChanged;


}

Para usar a interface de comando, o ViewModel contém as propriedades do tipo ICommand :

public ICommand MyCommand { private set; get; }

O ViewModel também deve referenciar uma classe que implementa a interface ICommand . Essa classe será
descrita em breve. No View, a propriedade Command de um Button é associada a essa propriedade:

<Button Text="Execute command"


Command="{Binding MyCommand}" />

Quando o usuário pressiona o Button , o Button chama o método Execute no objeto ICommand associado a sua
propriedade Command . Essa é a parte mais simples da interface de comando.
O método CanExecute é mais complexo. Quando a associação é definida na propriedade Command do Button
pela primeira vez e quando a associação de dados é alterada de alguma forma, o Button chama o método
CanExecute no objeto ICommand . Se CanExecute retornar false , então o Button se desabilitará. Isso indica que
o comando específico não está disponível no momento ou é inválido.
O Button também anexa um manipulador no evento CanExecuteChanged de ICommand . O evento é acionado de
dentro do ViewModel. Quando o evento é acionado, o Button chama o CanExecute novamente. O Button
habilita a si mesmo se o CanExecute retorna true e desabilita a si mesmo se CanExecute retorna false .

IMPORTANT
Não use a propriedade IsEnabled de Button se estiver usando a interface de comando.

A classe de comando
Quando o ViewModel define uma propriedade do tipo ICommand , ele também deve conter ou referenciar uma
classe que implementa a interface ICommand . Essa classe deverá conter ou referenciar os métodos Execute e
CanExecute e acionar o evento CanExecuteChanged sempre que o método CanExecute puder retornar um valor
diferente.
É possível gravar essa classe sozinho ou usar uma classe que alguém tenha gravado. Como o ICommand faz parte
do Microsoft Windows, ele tem sido usado por anos com aplicativos da MVVM do Windows. Usar uma classe do
Windows que implementa o ICommand permite que você compartilhe seus ViewModels entre aplicativos do
Windows e aplicativos Xamarin.Forms.
Se o compartilhamento de ViewModels entre o Windows e o Xamarin.Forms não for uma preocupação, você
poderá usar a classe Command ou Command<T> incluída no Xamarin.Forms para implementar a interface ICommand .
Essas classes permitem que você especifique os corpos dos métodos Execute e CanExecute em construtores de
classe. Use Command<T> quando você usar a propriedade CommandParameter para distinguir entre vários modos de
exibição associados à mesma propriedade ICommand , e a classe Command mais simples quando isso não for um
requisito.
Comando básico
A página Entrada de pessoa no programa Demonstrações de associação de dados demonstra alguns
comandos simples implementados em um ViewModel.
O PersonViewModel define três propriedades denominadas Name , Age e Skills que definem uma pessoa. Essa
classe não contém nenhuma propriedade ICommand :

public class PersonViewModel : INotifyPropertyChanged


{
string name;
double age;
string skills;

public event PropertyChangedEventHandler PropertyChanged;

public string Name


{
set { SetProperty(ref name, value); }
get { return name; }
}

public double Age


{
set { SetProperty(ref age, value); }
get { return age; }
}

public string Skills


{
set { SetProperty(ref skills, value); }
get { return skills; }
}

public override string ToString()


{
return Name + ", age " + Age;
}

bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)


{
if (Object.Equals(storage, value))
return false;

storage = value;
OnPropertyChanged(propertyName);
return true;
}

protected void OnPropertyChanged([CallerMemberName] string propertyName = null)


{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}

O PersonCollectionViewModel mostrado a seguir cria novos objetos do tipo PersonViewModel e permite que o
usuário preencha os dados. Para essa finalidade, a classe define propriedades IsEditing do tipo bool e
PersonEdit do tipo PersonViewModel . Além disso, a classe define três propriedades do tipo ICommand e uma
propriedade chamada Persons do tipo IList<PersonViewModel> :
public class PersonCollectionViewModel : INotifyPropertyChanged
{
PersonViewModel personEdit;
bool isEditing;

public event PropertyChangedEventHandler PropertyChanged;

···

public bool IsEditing


{
private set { SetProperty(ref isEditing, value); }
get { return isEditing; }
}

public PersonViewModel PersonEdit


{
set { SetProperty(ref personEdit, value); }
get { return personEdit; }
}

public ICommand NewCommand { private set; get; }

public ICommand SubmitCommand { private set; get; }

public ICommand CancelCommand { private set; get; }

public IList<PersonViewModel> Persons { get; } = new ObservableCollection<PersonViewModel>();

bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)


{
if (Object.Equals(storage, value))
return false;

storage = value;
OnPropertyChanged(propertyName);
return true;
}

protected void OnPropertyChanged([CallerMemberName] string propertyName = null)


{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}

Essa listagem abreviada não inclui o construtor da classe, que é onde as três propriedades do tipo ICommand são
definidas, que serão mostradas em breve. Observe que as alterações nas três propriedades do tipo ICommand e a
propriedade Persons não faz os eventos PropertyChanged serem acionados. Todas essas propriedades são
definidas quando a classe é criada pela primeira vez e não são alteradas depois disso.
Antes de examinar o construtor da classe PersonCollectionViewModel , vamos examinar se há o programa Entrada
de pessoa no arquivo XAML. Ele contém um Grid com sua propriedade BindingContext definida como o
PersonCollectionViewModel . O Grid contém um Button com o texto Novo com sua propriedade Command
associada à propriedade NewCommand no ViewModel, um formulário de entrada com propriedades associadas à
propriedade IsEditing , bem como propriedades de PersonViewModel e mais dois botões associados às
propriedades SubmitCommand e CancelCommand do ViewModel. O último ListView exibe a coleção de pessoas já
que já entraram:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.PersonEntryPage"
Title="Person Entry">
Title="Person Entry">
<Grid Margin="10">
<Grid.BindingContext>
<local:PersonCollectionViewModel />
</Grid.BindingContext>

<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>

<!-- New Button -->


<Button Text="New"
Grid.Row="0"
Command="{Binding NewCommand}"
HorizontalOptions="Start" />

<!-- Entry Form -->


<Grid Grid.Row="1"
IsEnabled="{Binding IsEditing}">

<Grid BindingContext="{Binding PersonEdit}">


<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>

<Label Text="Name: " Grid.Row="0" Grid.Column="0" />


<Entry Text="{Binding Name}"
Grid.Row="0" Grid.Column="1" />

<Label Text="Age: " Grid.Row="1" Grid.Column="0" />


<StackLayout Orientation="Horizontal"
Grid.Row="1" Grid.Column="1">
<Stepper Value="{Binding Age}"
Maximum="100" />
<Label Text="{Binding Age, StringFormat='{0} years old'}"
VerticalOptions="Center" />
</StackLayout>

<Label Text="Skills: " Grid.Row="2" Grid.Column="0" />


<Entry Text="{Binding Skills}"
Grid.Row="2" Grid.Column="1" />

</Grid>
</Grid>

<!-- Submit and Cancel Buttons -->


<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>

<Button Text="Submit"
Grid.Column="0"
Command="{Binding SubmitCommand}"
VerticalOptions="CenterAndExpand" />

<Button Text="Cancel"
Grid.Column="1"
Command="{Binding CancelCommand}"
Command="{Binding CancelCommand}"
VerticalOptions="CenterAndExpand" />
</Grid>

<!-- List of Persons -->


<ListView Grid.Row="3"
ItemsSource="{Binding Persons}" />
</Grid>
</ContentPage>

Veja como funciona: O usuário primeiro pressiona o botão Novo. Isso habilita o formulário de entrada, mas
desabilita o botão Novo. O usuário insere, então, um nome, idade e habilidades. A qualquer momento durante a
edição, o usuário pode pressionar o botão Cancelar para recomeçar. Somente depois que um nome e uma idade
válida forem inseridos, o botão Enviar será habilitado. Pressionar esse botão Enviar transfere a pessoa para a
coleção exibida pelo ListView . Depois que o botão Cancelar ou Enviar é pressionado, o formulário de entrada é
limpo e o botão Novo é habilitado novamente.
A tela do iOS à esquerda mostra o layout antes que uma idade válida seja inserida. As telas do Android e da
UWP mostram o botão Enviar habilitado depois que uma idade é definida:

O programa não tem nenhum recurso para editar entradas existentes nem salva as entradas quando você sai da
página.
Toda a lógica dos botões Novo, Enviar, e Cancelar é tratado em PersonCollectionViewModel por meio das
definições das propriedades NewCommand , SubmitCommand e CancelCommand . O construtor do
PersonCollectionViewModel define essas três propriedades para objetos do tipo Command .

Um construtor da classe Command permite que você passe argumentos do tipo Action e Func<bool>
correspondentes aos métodos Execute e CanExecute . É mais fácil definir essas ações e funções como funções
lambda direto no construtor Command . Veja a definição do objeto Command para a propriedade NewCommand :
public class PersonCollectionViewModel : INotifyPropertyChanged
{

···

public PersonCollectionViewModel()
{
NewCommand = new Command(
execute: () =>
{
PersonEdit = new PersonViewModel();
PersonEdit.PropertyChanged += OnPersonEditPropertyChanged;
IsEditing = true;
RefreshCanExecutes();
},
canExecute: () =>
{
return !IsEditing;
});

···

void OnPersonEditPropertyChanged(object sender, PropertyChangedEventArgs args)


{
(SubmitCommand as Command).ChangeCanExecute();
}

void RefreshCanExecutes()
{
(NewCommand as Command).ChangeCanExecute();
(SubmitCommand as Command).ChangeCanExecute();
(CancelCommand as Command).ChangeCanExecute();
}

···

Quando o usuário clica no botão Novo, a função execute passada para o construtor Command é executada. Isso
cria um novo objeto PersonViewModel , define um manipulador no evento PropertyChanged desse objeto, define
IsEditing como true e chama o método RefreshCanExecutes definido após o construtor.

Além de implementar a interface ICommand , a classe Command também define um método chamado
ChangeCanExecute . O ViewModel deve chamar ChangeCanExecute para uma propriedade ICommand sempre que
acontecer qualquer coisa que possa alterar o valor retornado do método CanExecute . Uma chamada ao
ChangeCanExecute faz a classe Command acionar o método CanExecuteChanged . O Button anexou um manipulador
para o evento, responde chamando CanExecute novamente e permitindo que se baseie no valor retornado desse
método.
Quando o método execute de NewCommand chama RefreshCanExecutes , a propriedade NewCommand obtém uma
chamada a ChangeCanExecute , e o Button chama o método canExecute , que agora retorna false porque a
propriedade IsEditing agora é true .
O manipulador PropertyChanged do novo objeto PersonViewModel chama o método ChangeCanExecute de
SubmitCommand . Veja como essa propriedade de comando é implementada:
public class PersonCollectionViewModel : INotifyPropertyChanged
{

···

public PersonCollectionViewModel()
{

···

SubmitCommand = new Command(


execute: () =>
{
Persons.Add(PersonEdit);
PersonEdit.PropertyChanged -= OnPersonEditPropertyChanged;
PersonEdit = null;
IsEditing = false;
RefreshCanExecutes();
},
canExecute: () =>
{
return PersonEdit != null &&
PersonEdit.Name != null &&
PersonEdit.Name.Length > 1 &&
PersonEdit.Age > 0;
});

···
}

···

A função para SubmitCommand é chamada sempre que há uma propriedade alterada no objeto
canExecute
PersonViewModel que está sendo editado. Ela retorna true somente quando a propriedade Name tem pelo
menos um caractere de comprimento e Age é maior que 0. Nesse momento, o botão Enviar fica habilitado.
A função execute para Enviar remove o manipulador de propriedade alterada do PersonViewModel , adiciona o
objeto à coleção Persons e retorna tudo para as condições iniciais.
A função execute para o botão Cancelar faz tudo o que o botão Enviar faz, exceto adicionar o objeto à coleção:
public class PersonCollectionViewModel : INotifyPropertyChanged
{

···

public PersonCollectionViewModel()
{

···

CancelCommand = new Command(


execute: () =>
{
PersonEdit.PropertyChanged -= OnPersonEditPropertyChanged;
PersonEdit = null;
IsEditing = false;
RefreshCanExecutes();
},
canExecute: () =>
{
return IsEditing;
});
}

···

O método canExecute retorna true a qualquer momento que um PersonViewModel está sendo editado.
Essas técnicas poderiam ser adaptadas para cenários mais complexos: Uma propriedade no
PersonCollectionViewModel poderia estar associada à propriedade SelectedItem do ListView para editar itens
existentes e o botão Excluir poderia ser adicionado para excluir esses itens.
Não é necessário definir os métodos execute e canExecute como funções lambda. É possível gravá-los como
métodos privados regulares no ViewModel e referenciá-los nos construtores Command . No entanto, essa
abordagem tende a resultar em uma grande quantidade de métodos referenciados apenas uma vez no
ViewModel.

Uso de parâmetros de comando


Às vezes, é conveniente para um ou mais botões (ou outros objetos da interface do usuário) compartilhar a
mesma propriedade ICommand no ViewModel. Nesse caso, você usa a propriedade CommandParameter para
distinguir entre os botões.
É possível continuar usando a classe Command para essas propriedades ICommand compartilhadas. A classe define
um construtor alternativo que aceita os métodos execute e canExecute com parâmetros do tipo Object . Isso é
como o CommandParameter é passado para esses métodos.
No entanto, ao usar CommandParameter , é mais fácil de usar a classe Command<T> genérica para especificar o tipo
do objeto definido como CommandParameter . Os métodos execute e canExecute que você especificar têm
parâmetros desse tipo.
A página Teclado decimal ilustra essa técnica mostrando como implementar um teclado numérico para inserir
números decimais. O BindingContext para o Grid é um DecimalKeypadViewModel . A propriedade Entry desse
ViewModel está associada à propriedade Text de um Label . Todos os objetos Button estão associados a vários
comandos no ViewModel: ClearCommand , BackspaceCommand e DigitCommand :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.DecimalKeypadPage"
Title="Decimal Keyboard">

<Grid WidthRequest="240"
HeightRequest="480"
ColumnSpacing="2"
RowSpacing="2"
HorizontalOptions="Center"
VerticalOptions="Center">

<Grid.BindingContext>
<local:DecimalKeypadViewModel />
</Grid.BindingContext>

<Grid.Resources>
<ResourceDictionary>
<Style TargetType="Button">
<Setter Property="FontSize" Value="32" />
<Setter Property="BorderWidth" Value="1" />
<Setter Property="BorderColor" Value="Black" />
</Style>
</ResourceDictionary>
</Grid.Resources>

<Label Text="{Binding Entry}"


Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3"
FontSize="32"
LineBreakMode="HeadTruncation"
VerticalTextAlignment="Center"
HorizontalTextAlignment="End" />

<Button Text="CLEAR"
Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"
Command="{Binding ClearCommand}" />

<Button Text="&#x21E6;"
Grid.Row="1" Grid.Column="2"
Command="{Binding BackspaceCommand}" />

<Button Text="7"
Grid.Row="2" Grid.Column="0"
Command="{Binding DigitCommand}"
CommandParameter="7" />

<Button Text="8"
Grid.Row="2" Grid.Column="1"
Command="{Binding DigitCommand}"
CommandParameter="8" />

<Button Text="9"
Grid.Row="2" Grid.Column="2"
Command="{Binding DigitCommand}"
CommandParameter="9" />

<Button Text="4"
Grid.Row="3" Grid.Column="0"
Command="{Binding DigitCommand}"
CommandParameter="4" />

<Button Text="5"
Grid.Row="3" Grid.Column="1"
Command="{Binding DigitCommand}"
CommandParameter="5" />

<Button Text="6"
Grid.Row="3" Grid.Column="2"
Command="{Binding DigitCommand}"
CommandParameter="6" />
CommandParameter="6" />

<Button Text="1"
Grid.Row="4" Grid.Column="0"
Command="{Binding DigitCommand}"
CommandParameter="1" />

<Button Text="2"
Grid.Row="4" Grid.Column="1"
Command="{Binding DigitCommand}"
CommandParameter="2" />

<Button Text="3"
Grid.Row="4" Grid.Column="2"
Command="{Binding DigitCommand}"
CommandParameter="3" />

<Button Text="0"
Grid.Row="5" Grid.Column="0" Grid.ColumnSpan="2"
Command="{Binding DigitCommand}"
CommandParameter="0" />

<Button Text="&#x00B7;"
Grid.Row="5" Grid.Column="2"
Command="{Binding DigitCommand}"
CommandParameter="." />
</Grid>
</ContentPage>

Os 11 botões para os 10 dígitos e o ponto decimal compartilham uma associação a DigitCommand . O


CommandParameter faz distinção entre esses botões. O valor definido como CommandParameter geralmente é o
mesmo que o texto exibido pelo botão, exceto para o ponto decimal, que, para fins de esclarecimento, é exibido
com um caractere de ponto no meio.
Veja o programa em ação:

Observe que o botão para o ponto decimal em todas as três capturas de tela está desabilitado, porque o número
inserido já contém um ponto decimal.
O DecimalKeypadViewModel define uma propriedade Entry do tipo string (que é a única propriedade que
dispara um evento PropertyChanged ) e três propriedades do tipo ICommand :
public class DecimalKeypadViewModel : INotifyPropertyChanged
{
string entry = "0";

public event PropertyChangedEventHandler PropertyChanged;

···

public string Entry


{
private set
{
if (entry != value)
{
entry = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Entry"));
}
}
get
{
return entry;
}
}

public ICommand ClearCommand { private set; get; }

public ICommand BackspaceCommand { private set; get; }

public ICommand DigitCommand { private set; get; }


}

O botão correspondente ao ClearCommand está sempre habilitado e simplesmente define a entrada de volta para
"0":

public class DecimalKeypadViewModel : INotifyPropertyChanged


{

···

public DecimalKeypadViewModel()
{
ClearCommand = new Command(
execute: () =>
{
Entry = "0";
RefreshCanExecutes();
});

···

void RefreshCanExecutes()
{
((Command)BackspaceCommand).ChangeCanExecute();
((Command)DigitCommand).ChangeCanExecute();
}

···

Como o botão sempre está habilitado, não é necessário especificar um argumento canExecute no construtor
Command .
A lógica para inserir números e backspace é um pouco complicada, porque se nenhum dígito foi inserido, a
propriedade Entry será a cadeia de caracteres "0". Se o usuário digitar mais zeros, então o Entry ainda conterá
apenas um zero. Se o usuário digita qualquer outro dígito, esse dígito substitui o zero. Mas se o usuário digita um
ponto decimal antes de qualquer outro dígito, então Entry é a cadeia de caracteres "0".
O botão Backspace é habilitado apenas quando o comprimento da entrada é maior que 1 ou se Entry não é
igual à cadeia de caracteres "0":

public class DecimalKeypadViewModel : INotifyPropertyChanged


{

···

public DecimalKeypadViewModel()
{

···

BackspaceCommand = new Command(


execute: () =>
{
Entry = Entry.Substring(0, Entry.Length - 1);
if (Entry == "")
{
Entry = "0";
}
RefreshCanExecutes();
},
canExecute: () =>
{
return Entry.Length > 1 || Entry != "0";
});

···

···

A lógica para a função execute do botão Backspace garante que o Entry é pelo menos uma cadeia de
caracteres de comprimento "0".
A propriedade DigitCommandestá associada a 11 botões, cada um dos quais identifica-se com a propriedade
CommandParameter . O DigitCommand poderia ser definido como uma instância da classe Command regular, mas é
mais fácil usar a classe genérica Command<T> . Ao usar a interface de comando com o XAML, as propriedades
CommandParameter geralmente são cadeias de caracteres e esse é o tipo de argumento genérico. As funções
execute e canExecute têm argumentos do tipo string :
public class DecimalKeypadViewModel : INotifyPropertyChanged
{

···

public DecimalKeypadViewModel()
{

···

DigitCommand = new Command<string>(


execute: (string arg) =>
{
Entry += arg;
if (Entry.StartsWith("0") && !Entry.StartsWith("0."))
{
Entry = Entry.Substring(1);
}
RefreshCanExecutes();
},
canExecute: (string arg) =>
{
return !(arg == "." && Entry.Contains("."));
});
}

···

O método execute acrescenta o argumento de cadeia de caracteres à propriedade Entry . No entanto, se o


resultado começar com um zero (mas não um zero e um ponto decimal), esse zero inicial deverá ser removido
usando a função Substring .
O método canExecute retornará false somente se o argumento for o ponto decimal (que indica que o ponto
decimal está sendo pressionado) e Entry já contém um ponto decimal.
Todos os métodos execute chamam RefreshCanExecutes , que chama ChangeCanExecute para DigitCommand e
ClearCommand . Isso garante que o ponto decimal e os botões backspace estão habilitados ou desabilitados com
base na sequência atual de dígitos inseridos.

Como adicionar comandos a exibições existentes


Se desejar usar a interface de comando com exibições não compatíveis com ela, será possível usar um
comportamento do Xamarin.Forms que converte um evento em um comando. Isso é descrito no artigo
EventToCommandBehavior reutilizável.

Comando assíncrono para menus de navegação


Comandos são convenientes para implementar os menus de navegação, como o do programa Demonstrações
de associação de dados em si. Veja uma parte do MainPage.xaml:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.MainPage"
Title="Data Binding Demos"
Padding="10">
<TableView Intent="Menu">
<TableRoot>
<TableSection Title="Basic Bindings">

<TextCell Text="Basic Code Binding"


Detail="Define a data-binding in code"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:BasicCodeBindingPage}" />

<TextCell Text="Basic XAML Binding"


Detail="Define a data-binding in XAML"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:BasicXamlBindingPage}" />

<TextCell Text="Alternative Code Binding"


Detail="Define a data-binding in code without a BindingContext"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:AlternativeCodeBindingPage}" />

···

</TableSection>
</TableRoot>
</TableView>
</ContentPage>

Ao usar comandos com XAML, as propriedades CommandParameter geralmente são definidas como cadeias de
caracteres. No entanto, nesse caso, uma extensão de marcação XAML é usada para que o CommandParameter seja
do tipo System.Type .
Cada propriedade Command está associada a uma propriedade chamada NavigateCommand . Se a propriedade
estiver definida no arquivo code-behind, MainPage.xaml.cs:

public partial class MainPage : ContentPage


{
public MainPage()
{
InitializeComponent();

NavigateCommand = new Command<Type>(


async (Type pageType) =>
{
Page page = (Page)Activator.CreateInstance(pageType);
await Navigation.PushAsync(page);
});

BindingContext = this;
}

public ICommand NavigateCommand { private set; get; }


}

O construtor define a propriedade NavigateCommand como um método execute que cria a instância do parâmetro
System.Type e navega até ela. Como a chamada PushAsync requer um operador await , o método execute deve
ser sinalizado como assíncrono. Isso é feito com a palavra-chave async antes da lista de parâmetros.
O construtor também define o BindingContext da página como a si mesmo para que as associações referenciem
o NavigateCommand nessa classe.
A ordem do código nesse construtor faz a diferença: A chamada InitializeComponent causa a análise do XAML,
mas, nesse momento, a associação a uma propriedade denominada NavigateCommand não pode ser resolvida,
porque BindingContext está definido como null . Se o BindingContext for definido no construtor antes de
NavigateCommand ser definido, a associação poderá ser resolvida quando BindingContext for definido, mas, nesse
momento, NavigateCommand ainda será null . Definir NavigateCommand após BindingContext não terá efeito na
associação, porque uma alteração no NavigateCommand não dispara um evento PropertyChanged , e a associação
não sabe que NavigateCommand é válido agora.
Definir NavigateCommand e BindingContext (em qualquer ordem) antes da chamada a InitializeComponent
funcionará, porque os componentes da associação são definidos quando o analisador XAML encontra a definição
da associação.
Às vezes, as associações de dados podem ser complicadas, mas, como você viu nessa série de artigos, elas são
poderosas e versáteis e ajudam bastante a organizar seu código separando a lógica subjacente da interface do
usuário.

Links relacionados
Demonstrações de associação de dados (amostra)
Capítulo de associação de dados do catálogo de Xamarin.Forms
Associações compiladas do Xamarin.Forms
12/04/2019 • 13 minutes to read • Edit Online

Baixar o exemplo
Associações compiladas são resolvidas mais rapidamente do que associações clássicas, melhorando assim o
desempenho da associação de dados em aplicativos do Xamarin.Forms.
Associações de dados têm dois problemas principais:
1. Não há validação em tempo de compilação para expressões de associação. Em vez disso, as associações são
resolvidas em tempo de execução. Sendo assim, associações inválidas não são detectadas até o tempo de
execução, quando o aplicativo não se comporta conforme esperado ou mensagens de erro são exibidas.
2. Elas não são econômicas. Associações são resolvidas em tempo de execução usando a inspeção de objeto para
uso geral (reflexão), e a sobrecarga de fazer isso varia de uma plataforma para outra.
Associações compiladas melhoram o desempenho de associação de dados em aplicativos do Xamarin.Forms
resolvendo expressões de associação em tempo de compilação, em vez de tempo de execução. Além disso, essa
validação em tempo de compilação das expressões de associação permite uma melhor experiência de solução de
problemas para o desenvolvedor porque associações inválidas são relatadas como erros de build.
O processo para usar associações compiladas é:
1. Habilitar a compilação de XAML. Para obter mais informações sobre a compilação de XAML, confira
Compilação de XAML.
2. Definir um atributo x:DataType em um VisualElement como o tipo do objeto ao qual VisualElement e seus
filhos se associarão. Observe que esse atributo pode ser redefinido em qualquer localização de uma hierarquia
de exibição.

NOTE
É recomendável definir o atributo x:DataType no mesmo nível da hierarquia de exibição em que BindingContext está
definido.

No tempo de compilação de XAML, as expressões de associação inválidas serão relatadas como erros de build.
No entanto, o compilador XAML relatará um erro de build somente para a primeira expressão de associação
inválida que encontrar. Expressões de associação válidas definidas no VisualElement ou em seus filhos serão
compiladas, independentemente de BindingContext estar definido no XAML ou no código. Compilar uma
expressão de associação gera o código compilado que obterá um valor de uma propriedade na origem e o
definirá na propriedade de destino especificada na marcação. Além disso, dependendo da expressão de
associação, o código gerado poderá observar alterações no valor da propriedade de origem e atualizar a
propriedade de destino, e pode enviar por push alterações do destino para a origem.

IMPORTANT
Atualmente, associações compiladas estão desabilitadas para expressões de associação que definem a propriedade Source
. Isso acontece porque a propriedade Source sempre é definida usando a extensão de marcação x:Reference , que não
pode ser resolvida em tempo de compilação.
Usando associações compiladas
A página Seletor de Cores Compilado demonstra como usar associações compiladas entre as exibições do
Xamarin.Forms e as propriedades de ViewModel:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.CompiledColorSelectorPage"
Title="Compiled Color Selector">
...
<StackLayout x:DataType="local:HslColorViewModel">
<StackLayout.BindingContext>
<local:HslColorViewModel Color="Sienna" />
</StackLayout.BindingContext>
<BoxView Color="{Binding Color}"
... />
<StackLayout Margin="10, 0">
<Label Text="{Binding Name}" />
<Slider Value="{Binding Hue}" />
<Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}" />
<Slider Value="{Binding Saturation}" />
<Label Text="{Binding Saturation, StringFormat='Saturation = {0:F2}'}" />
<Slider Value="{Binding Luminosity}" />
<Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}" />
</StackLayout>
</StackLayout>
</ContentPage>

O StackLayout raiz instancia o HslColorViewModel e inicializa a propriedade Color dentro de marcas de


elemento de propriedade para a propriedade BindingContext . Esse StackLayout raiz também define o atributo
x:DataType como o tipo ViewModel, indicando que as expressões de associação na hierarquia de exibição do
StackLayout raiz serão compiladas. Isso pode ser verificado alterando qualquer uma das expressões de
associação para se associar a uma propriedade de ViewModel inexistente, o que causará um erro de build.

IMPORTANT
O atributo x:DataType pode ser redefinido em qualquer ponto de uma hierarquia de exibição.

Os elementos BoxView , Label e as exibições Slider herdam o contexto de associação da StackLayout . Essas
exibições são destinos de associação que referenciam as propriedades de origem no ViewModel. Para as
propriedades BoxView.Color e Label.Text , as associações de dados são OneWay – as propriedades na exibição
são definidas nas propriedades do ViewModel. No entanto, a propriedade Slider.Value usa uma associação
TwoWay . Isso permite que cada Slider seja definido no ViewModel e também que o ViewModel seja definido
em cada Slider .
Quando o aplicativo é executado pela primeira vez, os elementos BoxView , Label e Slider são definidos no
ViewModel com base na propriedade Color inicial definida quando foi criada uma instância do ViewModel. Isso
é mostrado nas seguintes capturas de tela:
Conforme os controles deslizantes são manipulados, os elementos BoxView e Label são atualizados.
Para obter mais informações sobre o seletor de cores, confira ViewModels e notificações de alteração de
propriedade.

Usando associações compiladas em um DataTemplate


Associações em um DataTemplate são interpretadas no contexto do objeto que está sendo modelado. Portanto,
ao usar associações compiladas em um DataTemplate , o DataTemplate precisa declarar o tipo de seu objeto de
dados usando o atributo x:DataType .
A página Lista de Cores Compilada demonstra como usar associações compiladas em um DataTemplate :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.CompiledColorListPage"
Title="Compiled Color List">
<Grid>
...
<ListView x:Name="colorListView"
ItemsSource="{x:Static local:NamedColor.All}"
... >
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:NamedColor">
<ViewCell>
<StackLayout Orientation="Horizontal">
<BoxView Color="{Binding Color}"
... />
<Label Text="{Binding FriendlyName}"
... />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<!-- The BoxView doesn't use compiled bindings -->
<BoxView Color="{Binding Source={x:Reference colorListView}, Path=SelectedItem.Color}"
... />
</Grid>
</ContentPage>

A propriedade ListView.ItemsSource é definida como a propriedade estática NamedColor.All . A classe


NamedColor usa a reflexão do .NET para enumerar todos os campos públicos estáticos na estrutura Color e
armazená-los com seus nomes em uma coleção acessível na propriedade estática All . Portanto, o ListView é
preenchido com todas as instâncias de NamedColor . Para cada item em ListView , o contexto de associação para o
item é definido como um objeto NamedColor . Os elementos BoxView e Label no ViewCell estão associados às
propriedades em NamedColor .
Observe que o DataTemplate define o atributo x:DataType como o tipo NamedColor , indicando que as expressões
de associação na hierarquia de exibição DataTemplate serão compiladas. Isso pode ser verificado alterando
qualquer uma das expressões de associação para se associar a uma propriedade NamedColor inexistente, o que
causará um erro de build.
Quando o aplicativo é executado pela primeira vez, o ListView é preenchido com instâncias de NamedColor .
Quando um item no ListView é selecionado, a propriedade BoxView.Color é definida como a cor do item
selecionado no ListView :

Selecionar outros itens no ListView atualiza a cor do BoxView .

Combinando associações compiladas com associações clássicas


Expressões de associação são compiladas apenas para a hierarquia de exibição em que o atributo x:DataType
está definido. Por outro lado, exibições em uma hierarquia na qual o atributo x:DataType não está definido
usarão associações clássicas. Portanto, é possível combinar associações compiladas e associações clássicas em
uma página. Por exemplo, na seção anterior, os modos de exibição dentro do DataTemplate usam associações
compiladas, enquanto o BoxView definido como a cor selecionada no ListView não faz isso.
Estruturar cuidadosamente os atributos x:DataType , portanto, pode levar a uma página que usa associações
compiladas e clássicas. Como alternativa, o atributo x:DataType pode ser redefinido a qualquer momento em
uma hierarquia de exibição como null usando a extensão de marcação x:Null . Fazer isso indica que qualquer
expressão de associação de dentro da hierarquia de exibição usará associações clássicas. A página Associações
Mistas demonstra essa abordagem:
<StackLayout x:DataType="local:HslColorViewModel">
<StackLayout.BindingContext>
<local:HslColorViewModel Color="Sienna" />
</StackLayout.BindingContext>
<BoxView Color="{Binding Color}"
VerticalOptions="FillAndExpand" />
<StackLayout x:DataType="{x:Null}"
Margin="10, 0">
<Label Text="{Binding Name}" />
<Slider Value="{Binding Hue}" />
<Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}" />
<Slider Value="{Binding Saturation}" />
<Label Text="{Binding Saturation, StringFormat='Saturation = {0:F2}'}" />
<Slider Value="{Binding Luminosity}" />
<Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}" />
</StackLayout>
</StackLayout>

O StackLayout raiz define o atributo x:DataType como o tipo HslColorViewModel , indicando que as expressões
de associação na hierarquia de exibição StackLayout raiz serão compiladas. No entanto, o StackLayout interno
redefine o atributo x:DataType como null com a expressão de marcação x:Null . Portanto, as expressões de
associação no StackLayout interno usam associações clássicas. Somente o BoxView , dentro da hierarquia de
exibição StackLayout raiz, usa associações compiladas.
Para obter mais informações sobre a expressão de marcação x:Null , confira Extensão de marcação x:Null.

Desempenho
Associações compiladas melhoram o desempenho da associação de dados, com benefícios de desempenho
variáveis. Testes de unidade revelam que:
Uma associação compilada que usa notificação de alteração de propriedade (ou seja, uma associação OneWay ,
OneWayToSource ou TwoWay ) é resolvida aproximadamente oito vezes mais rápido do que uma associação
clássica.
Uma associação compilada que não usa notificação de alteração de propriedade (ou seja, uma associação
OneTime ) é resolvida aproximadamente vinte vezes mais rápido do que uma associação clássica.
Definir o BindingContext em uma associação compilada que usa notificação de alteração de propriedade (ou
seja, uma associação OneWay , OneWayToSource ou TwoWay ) é aproximadamente cinco vezes mais rápido do
que definir o BindingContext em uma associação clássica.
Definir o BindingContext em uma associação compilada que não usa notificação de alteração de propriedade
(ou seja, uma associação OneTime ), é aproximadamente sete vezes mais rápido do que definir o
BindingContext em uma associação clássica.

Essas diferenças de desempenho podem aumentar em dispositivos móveis, dependendo da plataforma usada, da
versão do sistema operacional usado e do dispositivo no qual o aplicativo está em execução.

Links relacionados
Demonstrações de associação de dados (amostra)
Xamarin.Forms DependencyService
12/04/2019 • 2 minutes to read • Edit Online

Baixar o exemplo
O Xamarin.Forms permite aos desenvolvedores definir o comportamento em projetos específicos a uma
plataforma. O DependencyService, em seguida, localiza a implementação de plataforma certa, permitindo que
o código compartilhado acesse a funcionalidade nativa.
Este guia é composto dos seguintes artigos:
Introdução – apresenta a arquitetura geral do conceito DependencyService .
Implementando a conversão de texto em fala – apresenta um exemplo de como usar o sistema de texto
em fala nativo de cada plataforma.
Verificando a orientação do dispositivo – apresenta um exemplo de como usar APIs da plataforma nativa
para determinar a orientação do dispositivo.
Obtendo informações sobre a bateria – apresenta um exemplo de como usar APIs nativas para obter
informações sobre o status da bateria.
Escolhendo uma foto na biblioteca – apresenta um exemplo de como usar APIs nativas para escolher
uma foto da biblioteca de imagens do telefone.

Links relacionados
Usando o DependencyService (amostra)
DependencyService (amostra)
Amostras do Xamarin.Forms
Introdução a DependencyService
12/04/2019 • 6 minutes to read • Edit Online

Baixar o exemplo

Visão geral
O DependencyService permite que os aplicativos chamem a funcionalidade específica da plataforma usando código
compartilhado. Essa funcionalidade permite que os aplicativos do Xamarin.Forms façam qualquer coisa que um
aplicativo nativo pode fazer.
DependencyServiceé um localizador de serviço. Na prática, uma interface é definida e DependencyService localiza a
implementação correta da interface entre os vários projetos da plataforma.

NOTE
Por padrão, o DependencyService resolverá somente as implementações de plataforma que têm construtores sem
parâmetros. No entanto, é possível injetar no Xamarin.Forms um método de resolução de dependência que um contêiner de
injeção de dependências ou métodos de fábrica para resolver implementações da plataforma. Essa abordagem pode ser
usada para resolver implementações da plataforma que têm construtores com parâmetros. Para obter mais informações,
confira Resolução de dependências no Xamarin.Forms.

Como DependencyService funciona


Aplicativos do Xamarin.Forms precisam de quatro componentes para usar DependencyService :
Interface – A funcionalidade necessária é definida por uma interface no código compartilhado.
Implementação por plataforma – Classes que implementam a interface devem ser adicionadas a cada
projeto de plataforma.
Registro – Cada classe de implementação deve ser registrado no DependencyService por meio de um atributo
de metadados. O registro permite que DependencyService localize a classe de implementação e a forneça no
lugar da interface em tempo de execução.
Chamada para DependencyService – O código compartilhado precisa chamar DependencyService
explicitamente para solicitar implementações da interface.
Observe que é necessário fornecer implementações para cada projeto de plataforma em sua solução. Projetos de
plataforma sem implementações falharão em tempo de execução.
A estrutura do aplicativo é explicada pelo diagrama a seguir:
Interface
A interface que você elaborar definirá como você interage com a funcionalidade específica da plataforma. Tenha
cuidado se você estiver desenvolvendo um componente para ser compartilhado como um componente ou pacote
do NuGet. O design da API pode levar ao sucesso ou à falha de um pacote. O exemplo a seguir especifica uma
interface simples para falar o texto que permite que haja flexibilidade para especificar as palavras a serem faladas,
mas deixa que a implementação seja personalizada para cada plataforma:

public interface ITextToSpeech {


void Speak ( string text ); //note that interface members are public by default
}

Implementação por plataforma


Após uma interface adequada ser criada, essa interface deverá ser implementada no projeto para cada plataforma
de destino. Por exemplo, a classe a seguir implementa a interface ITextToSpeech no iOS:

namespace UsingDependencyService.iOS
{
public class TextToSpeech_iOS : ITextToSpeech
{
public void Speak (string text)
{
var speechSynthesizer = new AVSpeechSynthesizer ();

var speechUtterance = new AVSpeechUtterance (text) {


Rate = AVSpeechUtterance.MaximumSpeechRate/4,
Voice = AVSpeechSynthesisVoice.FromLanguage ("en-US"),
Volume = 0.5f,
PitchMultiplier = 1.0f
};

speechSynthesizer.SpeakUtterance (speechUtterance);
}
}
}

Registro
Cada implementação da interface precisa ser registrada no DependencyService com um atributo de metadados. O
código a seguir registra a implementação para o iOS:

[assembly: Dependency (typeof (TextToSpeech_iOS))]


namespace UsingDependencyService.iOS
{
...
}

Juntando tudo, a implementação específica da plataforma terá esta aparência:

[assembly: Dependency (typeof (TextToSpeech_iOS))]


namespace UsingDependencyService.iOS
{
public class TextToSpeech_iOS : ITextToSpeech
{
public void Speak (string text)
{
var speechSynthesizer = new AVSpeechSynthesizer ();

var speechUtterance = new AVSpeechUtterance (text) {


Rate = AVSpeechUtterance.MaximumSpeechRate/4,
Voice = AVSpeechSynthesisVoice.FromLanguage ("en-US"),
Volume = 0.5f,
PitchMultiplier = 1.0f
};

speechSynthesizer.SpeakUtterance (speechUtterance);
}
}
}

Observe que o registro é executado no nível de namespace, e não no nível da classe.


Compilação .NET Native na Plataforma Universal do Windows
Projetos da UWP que usam a opção de compilação .NET Native devem seguir uma configuração ligeiramente
diferente ao inicializar o Xamarin.Forms. A compilação .NET Native também requer um registro ligeiramente
diferente para serviços de dependência.
No arquivo App.xaml.cs, registre manualmente cada serviço de dependência definido no projeto da UWP
usando o método Register<T> , conforme mostrado abaixo:

Xamarin.Forms.Forms.Init(e, assembliesToInclude);
// register the dependencies in the same
Xamarin.Forms.DependencyService.Register<TextToSpeechImplementation>();

Observação: o registro manual usando Register<T> é eficaz somente em builds de Versão que usam a compilação
.NET Native. Se você omitir essa linha, builds de Depuração ainda funcionarão, mas builds de Versão falharão ao
carregar o serviço de dependência.
Chamada para DependencyService
Após o projeto ter sido configurado com uma interface comum e com implementações para cada plataforma, use
DependencyService para obter a implementação correta em tempo de execução:

DependencyService.Get<ITextToSpeech>().Speak("Hello from Xamarin Forms");

DependencyService.Get<T> encontrará a implementação correta da interface T .


Estrutura da solução
A solução de exemplo UsingDependencyService é mostrada abaixo para iOS e Android, com as alterações de
código descritas acima realçadas.

NOTE
Você precisa fornecer uma implementação no projeto de cada plataforma. Se nenhuma implementação da Interface estiver
registrada, o DependencyService não poderá resolver o método Get<T>() em tempo de execução.

Links relacionados
DependencyServiceSample
Amostras do Xamarin.Forms
Implementando a conversão de texto em fala
12/04/2019 • 5 minutes to read • Edit Online

Baixar o exemplo
Este artigo orientará você na criação de um aplicativo multiplataforma que usa DependencyService para acessar
APIs de conversão de texto em fala nativas:
Criando a Interface – compreenda como a interface é criada em código compartilhado.
Implementação de iOS – saiba como implementar a interface em código nativo para iOS.
Implementação de Android – saiba como implementar a interface em código nativo para Android.
Implementação de UWP – saiba como implementar a interface em código nativo para a UWP (Plataforma
Universal do Windows).
Implementação em código compartilhado – saiba como usar DependencyService para fazer chamadas na
implementação nativa usando código compartilhado.
O aplicativo que usa DependencyService terá a seguinte estrutura:

Criando a Interface
Primeiro, crie no código compartilhado uma interface que expressa a funcionalidade que você planeja
implementar. Neste exemplo, a interface contém um único método, Speak :

public interface ITextToSpeech


{
void Speak (string text);
}

A codificação nessa interface no código compartilhado permitirá que o aplicativo Xamarin.Forms acesse as APIs
de fala em cada plataforma.
NOTE
Classes que implementam a interface devem ter um construtor sem parâmetros para trabalhar com DependencyService .

Implementação de iOS
A interface deve ser implementada em cada projeto de aplicativo específico da plataforma. Observe que a classe
tem um construtor sem parâmetros, de modo que DependencyService pode criar novas instâncias.

[assembly: Dependency(typeof(TextToSpeechImplementation))]
namespace DependencyServiceSample.iOS
{

public class TextToSpeechImplementation : ITextToSpeech


{
public TextToSpeechImplementation() { }

public void Speak(string text)


{
var speechSynthesizer = new AVSpeechSynthesizer();
var speechUtterance = new AVSpeechUtterance(text)
{
Rate = AVSpeechUtterance.MaximumSpeechRate / 4,
Voice = AVSpeechSynthesisVoice.FromLanguage("en-US"),
Volume = 0.5f,
PitchMultiplier = 1.0f
};

speechSynthesizer.SpeakUtterance(speechUtterance);
}
}
}

O atributo [assembly] registra a classe como uma implementação da interface de ITextToSpeech , o que significa
que DependencyService.Get<ITextToSpeech>() pode ser usado no código compartilhado para criar uma instância
dele.

Implementação de Android
O código do Android é mais complexo que a versão do iOS. Ele precisa ter acesso ao contexto do Android atual,
que é exposto pela propriedade MainActivity.Instance :

public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity


{
internal static MainActivity Instance { get; private set; }

protected override void OnCreate(Bundle bundle)


{
...
}
}

ele requer a implementação da classe para herdar do Java.Lang.Object específico ao Android e implementar a
interface de IOnInitListener .
[assembly: Dependency(typeof(TextToSpeechImplementation))]
namespace DependencyServiceSample.Droid
{
public class TextToSpeechImplementation : Java.Lang.Object, ITextToSpeech, TextToSpeech.IOnInitListener
{
TextToSpeech speaker;
string toSpeak;

public void Speak(string text)


{
toSpeak = text;
if (speaker == null)
{
speaker = new TextToSpeech(MainActivity.Instance, this);
}
else
{
speaker.Speak(toSpeak, QueueMode.Flush, null, null);
}
}

public void OnInit(OperationResult status)


{
if (status.Equals(OperationResult.Success))
{
speaker.Speak(toSpeak, QueueMode.Flush, null, null);
}
}
}
}

O atributo [assembly] registra a classe como uma implementação da interface de ITextToSpeech , o que significa
que DependencyService.Get<ITextToSpeech>() pode ser usado no código compartilhado para criar uma instância
dele.

Implementação na Plataforma Universal do Windows


A Plataforma Universal do Windows tem uma API de fala no namespace Windows.Media.SpeechSynthesis . A única
ressalva é que é necessário se lembrar de marcar a capacidade Microfone no manifesto; caso contrário, o acesso
às APIs de fala será bloqueado.

[assembly:Dependency(typeof(TextToSpeechImplementation))]
public class TextToSpeechImplementation : ITextToSpeech
{
public async void Speak(string text)
{
var mediaElement = new MediaElement();
var synth = new Windows.Media.SpeechSynthesis.SpeechSynthesizer();
var stream = await synth.SynthesizeTextToStreamAsync(text);

mediaElement.SetSource(stream, stream.ContentType);
mediaElement.Play();
}
}

O atributo [assembly] registra a classe como uma implementação da interface de ITextToSpeech , o que significa
que DependencyService.Get<ITextToSpeech>() pode ser usado no código compartilhado para criar uma instância
dele.

Implementação em código compartilhado


Agora, podemos escrever e testar o código compartilhado que acessa a interface de conversão de texto em fala.
Essa página simples inclui um botão que dispara a funcionalidade de fala. Ela usa DependencyService para obter
uma instância da interface – de ITextToSpeech em tempo de execução. Essa instância será a implementação
específica da plataforma com acesso completo ao SDK nativo.

public MainPage ()
{
var speak = new Button {
Text = "Hello, Forms !",
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.CenterAndExpand,
};
speak.Clicked += (sender, e) => {
DependencyService.Get<ITextToSpeech>().Speak("Hello from Xamarin Forms");
};
Content = speak;
}

Executar esse aplicativo no iOS, no Android ou na UWP e pressionar o botão fará com que o aplicativo fale com
você usando o SDK de fala nativo de cada plataforma.

Links relacionados
Usando DependencyService (amostra)
DependencyServiceSample
Verificando a orientação do dispositivo
12/04/2019 • 6 minutes to read • Edit Online

Baixar o exemplo
Este artigo mostra como usar DependencyService para verificar a orientação do dispositivo do código
compartilhado usando as APIs nativas de cada plataforma. Este passo a passo se baseia no plug-in
DeviceOrientation de Ali Özgür. Confira o Repositório do GitHub para obter mais informações.

Criando a Interface – compreenda como a interface é criada em código compartilhado.


Implementação de iOS – saiba como implementar a interface em código nativo para iOS.
Implementação de Android – saiba como implementar a interface em código nativo para Android.
Implementação de UWP – saiba como implementar a interface em código nativo para a UWP (Plataforma
Universal do Windows).
Implementação em código compartilhado – saiba como usar DependencyService para fazer chamadas na
implementação nativa usando código compartilhado.
O aplicativo que usa DependencyService terá a seguinte estrutura:

NOTE
É possível detectar se o dispositivo está com orientação de retrato ou paisagem no código compartilhado, conforme
demonstrado em Orientação do Dispositivo. O método descrito neste artigo usa recursos nativos para obter mais
informações sobre a orientação, incluindo se o dispositivo está de cabeça para baixo.

Criando a Interface
Primeiro, crie no código compartilhado uma interface que expressa a funcionalidade que você planeja
implementar. Neste exemplo, a interface contém um único método:
namespace DependencyServiceSample.Abstractions
{
public enum DeviceOrientations
{
Undefined,
Landscape,
Portrait
}

public interface IDeviceOrientation


{
DeviceOrientations GetOrientation();
}
}

A codificação nessa interface no código compartilhado permitirá que o aplicativo Xamarin.Forms acesse as APIs
de orientação do dispositivo em cada plataforma.

NOTE
Classes que implementam a interface devem ter um construtor sem parâmetros para trabalhar com DependencyService .

Implementação de iOS
A Interface deve ser implementada em cada projeto de aplicativo específico da plataforma. Observe que a classe
tem um construtor sem parâmetros, de modo que DependencyService pode criar novas instâncias:

using UIKit;
using Foundation;

namespace DependencyServiceSample.iOS
{
public class DeviceOrientationImplementation : IDeviceOrientation
{
public DeviceOrientationImplementation(){ }

public DeviceOrientations GetOrientation()


{
var currentOrientation = UIApplication.SharedApplication.StatusBarOrientation;
bool isPortrait = currentOrientation == UIInterfaceOrientation.Portrait
|| currentOrientation == UIInterfaceOrientation.PortraitUpsideDown;

return isPortrait ? DeviceOrientations.Portrait: DeviceOrientations.Landscape;


}
}
}

Por fim, adicione este atributo [assembly] acima da classe (e fora dos namespaces definidos), incluindo as
instruções using :

using UIKit;
using Foundation;
using DependencyServiceSample.iOS; //enables registration outside of namespace

[assembly: Xamarin.Forms.Dependency (typeof (DeviceOrientationImplementation))]


namespace DependencyServiceSample.iOS {
...

Esse atributo registra a classe como uma implementação da Interface de IDeviceOrientation , o que significa que
DependencyService.Get<IDeviceOrientation> pode ser usado no código compartilhado para criar uma instância
dele.

Implementação de Android
O código a seguir implementa IDeviceOrientation no Android:

using DependencyServiceSample.Droid;
using Android.Hardware;

namespace DependencyServiceSample.Droid
{
public class DeviceOrientationImplementation : IDeviceOrientation
{
public DeviceOrientationImplementation() { }

public static void Init() { }

public DeviceOrientations GetOrientation()


{
IWindowManager windowManager =
Android.App.Application.Context.GetSystemService(Context.WindowService).JavaCast<IWindowManager>();

var rotation = windowManager.DefaultDisplay.Rotation;


bool isLandscape = rotation == SurfaceOrientation.Rotation90 || rotation ==
SurfaceOrientation.Rotation270;
return isLandscape ? DeviceOrientations.Landscape : DeviceOrientations.Portrait;
}
}
}

Adicione este atributo [assembly] acima da classe (e fora dos namespaces definidos), incluindo as instruções
using :

using DependencyServiceSample.Droid; //enables registration outside of namespace


using Android.Hardware;

[assembly: Xamarin.Forms.Dependency (typeof (DeviceOrientationImplementation))]


namespace DependencyServiceSample.Droid {
...

Esse atributo registra a classe como uma implementação da Interface de IDeviceOrientaiton , o que significa que
DependencyService.Get<IDeviceOrientation> pode ser usado no código compartilhado para criar uma instância
dele.

Implementação na Plataforma Universal do Windows


O código a seguir implementa a interface IDeviceOrientation na Plataforma Universal do Windows:
namespace DependencyServiceSample.WindowsPhone
{
public class DeviceOrientationImplementation : IDeviceOrientation
{
public DeviceOrientationImplementation() { }

public DeviceOrientations GetOrientation()


{
var orientation = Windows.UI.ViewManagement.ApplicationView.GetForCurrentView().Orientation;
if (orientation == Windows.UI.ViewManagement.ApplicationViewOrientation.Landscape) {
return DeviceOrientations.Landscape;
}
else {
return DeviceOrientations.Portrait;
}
}
}
}

Adicione o atributo [assembly] acima da classe (e fora dos namespaces definidos), incluindo as instruções using :

using DependencyServiceSample.WindowsPhone; //enables registration outside of namespace

[assembly: Dependency(typeof(DeviceOrientationImplementation))]
namespace DependencyServiceSample.WindowsPhone {
...

Esse atributo registra a classe como uma implementação da Interface de DeviceOrientationImplementation , o que
significa que DependencyService.Get<IDeviceOrientation> pode ser usado no código compartilhado para criar uma
instância dele.

Implementação em código compartilhado


Agora, podemos escrever e testar o código compartilhado que acessa a interface IDeviceOrientation . Esta página
simples inclui um botão que atualiza seu próprio texto com base na orientação do dispositivo. Ela usa
DependencyService para obter uma instância da interface – de IDeviceOrientation em tempo de execução. Essa
instância será a implementação específica da plataforma com acesso completo ao SDK nativo:
public MainPage ()
{
var orient = new Button {
Text = "Get Orientation",
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.CenterAndExpand,
};
orient.Clicked += (sender, e) => {
var orientation = DependencyService.Get<IDeviceOrientation>().GetOrientation();
switch(orientation){
case DeviceOrientations.Undefined:
orient.Text = "Undefined";
break;
case DeviceOrientations.Landscape:
orient.Text = "Landscape";
break;
case DeviceOrientations.Portrait:
orient.Text = "Portrait";
break;
}
};
Content = orient;
}

Executar esse aplicativo no iOS, no Android ou na plataformas Windows e pressionar o botão fará com que o
texto do botão seja atualizado com a orientação do dispositivo.

Links relacionados
Usando o DependencyService (amostra)
DependencyService (amostra)
Amostras do Xamarin.Forms
Verificando o status da bateria
12/04/2019 • 9 minutes to read • Edit Online

Baixar o exemplo
Este artigo descreve como criar um aplicativo que verifica o status da bateria. Este artigo se baseia o plug-in
Battery de James Montemagno. Para obter mais informações, confira o Repositório do GitHub.
Como o Xamarin.Forms não inclui a funcionalidade para verificar o status atual da bateria, esse aplicativo
precisará usar DependencyService para tirar proveito de APIs nativas. Este artigo abordará as etapas a seguir para
usar DependencyService :
Criando a Interface – compreenda como a interface é criada em código compartilhado.
Implementação de iOS – saiba como implementar a interface em código nativo para iOS.
Implementação de Android – saiba como implementar a interface em código nativo para Android.
Implementação da Plataforma Universal do Windows – saiba como implementar a interface em código
nativo para a UWP (Plataforma Universal do Windows).
Implementação em código compartilhado – saiba como usar DependencyService para fazer chamadas na
implementação nativa usando código compartilhado.
Quando concluído, o aplicativo que usa DependencyService terá a seguinte estrutura:

Criando a Interface
Primeiro, crie no código compartilhado uma interface que expressa a funcionalidade desejada. No caso de um
aplicativo de verificação de bateria, as informações relevantes são o percentual de bateria restante, se o dispositivo
está sendo carregado ou não e como o dispositivo está recebendo energia:
namespace DependencyServiceSample
{
public enum BatteryStatus
{
Charging,
Discharging,
Full,
NotCharging,
Unknown
}

public enum PowerSource


{
Battery,
Ac,
Usb,
Wireless,
Other
}

public interface IBattery


{
int RemainingChargePercent { get; }
BatteryStatus Status { get; }
PowerSource PowerSource { get; }
}
}

A codificação nessa interface no código compartilhado permitirá que o aplicativo Xamarin.Forms acesse as APIs
de gerenciamento de energia em cada plataforma.

NOTE
Classes que implementam a interface devem ter um construtor sem parâmetros para trabalhar com DependencyService .
Construtores não podem ser definidos pelas interfaces.

Implementação de iOS
A interface IBattery deve ser implementada em cada projeto de aplicativo específico da plataforma. A
implementação do iOS usará as APIs de UIDevice nativas para acessar as informações da bateria. Observe que a
classe a seguir tem um construtor sem parâmetros, de modo que DependencyService pode criar novas instâncias:
using UIKit;
using Foundation;
using DependencyServiceSample.iOS;

namespace DependencyServiceSample.iOS
{
public class BatteryImplementation : IBattery
{
public BatteryImplementation()
{
UIDevice.CurrentDevice.BatteryMonitoringEnabled = true;
}

public int RemainingChargePercent


{
get
{
return (int)(UIDevice.CurrentDevice.BatteryLevel * 100F);
}
}

public BatteryStatus Status


{
get
{
switch (UIDevice.CurrentDevice.BatteryState)
{
case UIDeviceBatteryState.Charging:
return BatteryStatus.Charging;
case UIDeviceBatteryState.Full:
return BatteryStatus.Full;
case UIDeviceBatteryState.Unplugged:
return BatteryStatus.Discharging;
default:
return BatteryStatus.Unknown;
}
}
}

public PowerSource PowerSource


{
get
{
switch (UIDevice.CurrentDevice.BatteryState)
{
case UIDeviceBatteryState.Charging:
return PowerSource.Ac;
case UIDeviceBatteryState.Full:
return PowerSource.Ac;
case UIDeviceBatteryState.Unplugged:
return PowerSource.Battery;
default:
return PowerSource.Other;
}
}
}
}
}

Por fim, adicione este atributo [assembly] acima da classe (e fora dos namespaces definidos), incluindo as
instruções using :
using UIKit;
using Foundation;
using DependencyServiceSample.iOS;//necessary for registration outside of namespace

[assembly: Xamarin.Forms.Dependency (typeof (BatteryImplementation))]


namespace DependencyServiceSample.iOS
{
public class BatteryImplementation : IBattery {
...

Esse atributo registra a classe como uma implementação da Interface de IBattery , o que significa que
DependencyService.Get<IBattery> pode ser usado em código compartilhado para criar uma instância dele:

Implementação de Android
A implementação do Android usa a API Android.OS.BatteryManager . Essa implementação é mais complexa do que
a versão do iOS, exigindo verificações para lidar com a falta de permissões da bateria:

using System;
using Android;
using Android.Content;
using Android.App;
using Android.OS;
using BatteryStatus = Android.OS.BatteryStatus;
using DependencyServiceSample.Droid;

namespace DependencyServiceSample.Droid
{
public class BatteryImplementation : IBattery
{
private BatteryBroadcastReceiver batteryReceiver;
public BatteryImplementation() { }

public int RemainingChargePercent


{
get
{
try
{
using (var filter = new IntentFilter(Intent.ActionBatteryChanged))
{
using (var battery = Application.Context.RegisterReceiver(null, filter))
{
var level = battery.GetIntExtra(BatteryManager.ExtraLevel, -1);
var scale = battery.GetIntExtra(BatteryManager.ExtraScale, -1);

return (int)Math.Floor(level * 100D / scale);


}
}
}
catch
{
System.Diagnostics.Debug.WriteLine ("Ensure you have android.permission.BATTERY_STATS");
throw;
}

}
}

public DependencyServiceSample.BatteryStatus Status


{
get
{
try
{
{
using (var filter = new IntentFilter(Intent.ActionBatteryChanged))
{
using (var battery = Application.Context.RegisterReceiver(null, filter))
{
int status = battery.GetIntExtra(BatteryManager.ExtraStatus, -1);
var isCharging = status == (int)BatteryStatus.Charging || status == (int)BatteryStatus.Full;

var chargePlug = battery.GetIntExtra(BatteryManager.ExtraPlugged, -1);


var usbCharge = chargePlug == (int)BatteryPlugged.Usb;
var acCharge = chargePlug == (int)BatteryPlugged.Ac;
bool wirelessCharge = false;
wirelessCharge = chargePlug == (int)BatteryPlugged.Wireless;

isCharging = (usbCharge || acCharge || wirelessCharge);


if (isCharging)
return DependencyServiceSample.BatteryStatus.Charging;

switch(status)
{
case (int)BatteryStatus.Charging:
return DependencyServiceSample.BatteryStatus.Charging;
case (int)BatteryStatus.Discharging:
return DependencyServiceSample.BatteryStatus.Discharging;
case (int)BatteryStatus.Full:
return DependencyServiceSample.BatteryStatus.Full;
case (int)BatteryStatus.NotCharging:
return DependencyServiceSample.BatteryStatus.NotCharging;
default:
return DependencyServiceSample.BatteryStatus.Unknown;
}
}
}
}
catch
{
System.Diagnostics.Debug.WriteLine ("Ensure you have android.permission.BATTERY_STATS");
throw;
}
}
}

public PowerSource PowerSource


{
get
{
try
{
using (var filter = new IntentFilter(Intent.ActionBatteryChanged))
{
using (var battery = Application.Context.RegisterReceiver(null, filter))
{
int status = battery.GetIntExtra(BatteryManager.ExtraStatus, -1);
var isCharging = status == (int)BatteryStatus.Charging || status == (int)BatteryStatus.Full;

var chargePlug = battery.GetIntExtra(BatteryManager.ExtraPlugged, -1);


var usbCharge = chargePlug == (int)BatteryPlugged.Usb;
var acCharge = chargePlug == (int)BatteryPlugged.Ac;

bool wirelessCharge = false;


wirelessCharge = chargePlug == (int)BatteryPlugged.Wireless;

isCharging = (usbCharge || acCharge || wirelessCharge);

if (!isCharging)
return DependencyServiceSample.PowerSource.Battery;
else if (usbCharge)
return DependencyServiceSample.PowerSource.Usb;
else if (acCharge)
return DependencyServiceSample.PowerSource.Ac;
else if (wirelessCharge)
return DependencyServiceSample.PowerSource.Wireless;
else
return DependencyServiceSample.PowerSource.Other;
}
}
}
catch
{
System.Diagnostics.Debug.WriteLine ("Ensure you have android.permission.BATTERY_STATS");
throw;
}
}
}
}
}

Adicione este atributo [assembly] acima da classe (e fora dos namespaces definidos), incluindo as instruções
using :

...
using BatteryStatus = Android.OS.BatteryStatus;
using DependencyServiceSample.Droid; //enables registration outside of namespace

[assembly: Xamarin.Forms.Dependency (typeof (BatteryImplementation))]


namespace DependencyServiceSample.Droid
{
public class BatteryImplementation : IBattery {
...

Esse atributo registra a classe como uma implementação da Interface de IBattery , o que significa que
DependencyService.Get<IBattery> pode ser usado no código compartilhado para criar uma instância dele.

Implementação na Plataforma Universal do Windows


A implementação da UWP usa as APIs de Windows.Devices.Power para obter informações sobre o status da
bateria:

using DependencyServiceSample.UWP;
using Xamarin.Forms;

[assembly: Dependency(typeof(BatteryImplementation))]
namespace DependencyServiceSample.UWP
{
public class BatteryImplementation : IBattery
{
private BatteryStatus status = BatteryStatus.Unknown;
Windows.Devices.Power.Battery battery;

public BatteryImplementation()
{
}

private Windows.Devices.Power.Battery DefaultBattery


{
get
{
return battery ?? (battery = Windows.Devices.Power.Battery.AggregateBattery);
}
}

public int RemainingChargePercent


{
get
{
var finalReport = DefaultBattery.GetReport();
var finalPercent = -1;

if (finalReport.RemainingCapacityInMilliwattHours.HasValue &&
finalReport.FullChargeCapacityInMilliwattHours.HasValue)
{
finalPercent = (int)((finalReport.RemainingCapacityInMilliwattHours.Value /
(double)finalReport.FullChargeCapacityInMilliwattHours.Value) * 100);
}
return finalPercent;
}
}

public BatteryStatus Status


{
get
{
var report = DefaultBattery.GetReport();
var percentage = RemainingChargePercent;

if (percentage >= 1.0)


{
status = BatteryStatus.Full;
}
else if (percentage < 0)
{
status = BatteryStatus.Unknown;
}
else
{
switch (report.Status)
{
case Windows.System.Power.BatteryStatus.Charging:
status = BatteryStatus.Charging;
break;
case Windows.System.Power.BatteryStatus.Discharging:
status = BatteryStatus.Discharging;
break;
case Windows.System.Power.BatteryStatus.Idle:
status = BatteryStatus.NotCharging;
break;
case Windows.System.Power.BatteryStatus.NotPresent:
status = BatteryStatus.Unknown;
break;
}
}
return status;
}
}

public PowerSource PowerSource


{
get
{
if (status == BatteryStatus.Full || status == BatteryStatus.Charging)
{
return PowerSource.Ac;
}
return PowerSource.Battery;
}
}
}
}
O atributo [assembly] acima da declaração de namespace registra a classe como uma implementação da interface
de IBattery , o que significa que DependencyService.Get<IBattery> pode ser usado em código compartilhado para
criar uma instância dele.

Implementação em código compartilhado


Agora que a interface foi implementada para cada plataforma, o aplicativo compartilhado pode ser escrito de
forma a tirar proveito dela. O aplicativo será composto por uma página com um botão que, quando tocado,
atualiza seu texto com o status da bateria atual. Ele usa o DependencyService para obter uma instância da interface
IBattery . Em tempo de execução, essa instância será a implementação específica da plataforma com acesso
completo ao SDK nativo.

public MainPage ()
{
var button = new Button {
Text = "Click for battery info",
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.CenterAndExpand,
};
button.Clicked += (sender, e) => {
var bat = DependencyService.Get<IBattery>();

switch (bat.PowerSource){
case PowerSource.Battery:
button.Text = "Battery - ";
break;
case PowerSource.Ac:
button.Text = "AC - ";
break;
case PowerSource.Usb:
button.Text = "USB - ";
break;
case PowerSource.Wireless:
button.Text = "Wireless - ";
break;
case PowerSource.Other:
default:
button.Text = "Other - ";
break;
}
switch (bat.Status){
case BatteryStatus.Charging:
button.Text += "Charging";
break;
case BatteryStatus.Discharging:
button.Text += "Discharging";
break;
case BatteryStatus.NotCharging:
button.Text += "Not Charging";
break;
case BatteryStatus.Full:
button.Text += "Full";
break;
case BatteryStatus.Unknown:
default:
button.Text += "Unknown";
break;
}
};
Content = button;
}

Executar esse aplicativo no iOS, no Android ou na UWP e pressionar o botão fará com que o texto do botão seja
atualizado para refletir o status de alimentação atual do dispositivo.

Links relacionados
DependencyService (amostra)
Usando o DependencyService (amostra)
Amostras do Xamarin.Forms
Escolhendo uma foto da biblioteca de imagens
12/04/2019 • 11 minutes to read • Edit Online

Baixar o exemplo
Este artigo descreve a criação de um aplicativo que permite que o usuário escolha uma foto da biblioteca de
imagens de seu telefone. Como o Xamarin.Forms não inclui essa funcionalidade, é necessário usar
DependencyService para acessar APIs nativas em cada plataforma. Este artigo abordará as etapas a seguir para
usar DependencyService para essa tarefa:
Criando a Interface – compreenda como a interface é criada em código compartilhado.
Implementação de iOS – saiba como implementar a interface em código nativo para iOS.
Implementação de Android – saiba como implementar a interface em código nativo para Android.
Implementação da Plataforma Universal do Windows – saiba como implementar a interface em código
nativo para a UWP (Plataforma Universal do Windows).
Implementação em código compartilhado – saiba como usar DependencyService para fazer chamadas na
implementação nativa usando código compartilhado.

Criando a Interface
Primeiro, crie no código compartilhado uma interface que expressa a funcionalidade desejada. No caso de um
aplicativo de seleção de fotos, é necessário apenas um método. Ele é definido na interface IPicturePicker na
biblioteca do .NET Standard do código de exemplo:

namespace DependencyServiceSample
{
public interface IPicturePicker
{
Task<Stream> GetImageStreamAsync();
}
}

O método GetImageStreamAsync é definido como assíncrono porque ele deve ser retornado rapidamente, mas ele
não pode retornar um objeto Stream para a foto selecionada até que o usuário tenha navegado na biblioteca de
imagens e selecionado uma.
Essa interface é implementada em todas as plataformas usando código específico da plataforma.

Implementação de iOS
A implementação de iOS da interface IPicturePicker usa o UIImagePickerController conforme descrito em
Escolher uma foto da galeria e no código de exemplo.
A implementação de iOS está contida na classe PicturePickerImplementation no projeto do iOS do código de
exemplo. Para tornar essa classe visível para o gerenciador do DependencyService , ela deve ser identificada com
um atributo [ assembly ] do tipo Dependency , e a classe deve ser pública e implementar explicitamente a interface
IPicturePicker :
[assembly: Dependency (typeof (PicturePickerImplementation))]

namespace DependencyServiceSample.iOS
{
public class PicturePickerImplementation : IPicturePicker
{
TaskCompletionSource<Stream> taskCompletionSource;
UIImagePickerController imagePicker;

public Task<Stream> GetImageStreamAsync()


{
// Create and define UIImagePickerController
imagePicker = new UIImagePickerController
{
SourceType = UIImagePickerControllerSourceType.PhotoLibrary,
MediaTypes =
UIImagePickerController.AvailableMediaTypes(UIImagePickerControllerSourceType.PhotoLibrary)
};

// Set event handlers


imagePicker.FinishedPickingMedia += OnImagePickerFinishedPickingMedia;
imagePicker.Canceled += OnImagePickerCancelled;

// Present UIImagePickerController;
UIWindow window = UIApplication.SharedApplication.KeyWindow;
var viewController = window.RootViewController;
viewController.PresentModalViewController(imagePicker, true);

// Return Task object


taskCompletionSource = new TaskCompletionSource<Stream>();
return taskCompletionSource.Task;
}
...
}
}

O método GetImageStreamAsync cria um UIImagePickerController e o inicializa para selecionar imagens da


biblioteca de fotos. São necessários dois manipuladores de eventos: Um para quando o usuário seleciona uma
foto e outro para quando o usuário cancela a exibição da biblioteca de fotos. O PresentModalViewController , em
seguida, exibe a biblioteca de fotos para o usuário.
Neste ponto, o método GetImageStreamAsync deve retornar um objeto Task<Stream> para o código que o está
chamando. Essa tarefa é concluída somente quando o usuário termina de interagir com a biblioteca de fotos e um
dos manipuladores de eventos é chamado. Para situações como essa, a classe TaskCompletionSource é essencial.
A classe fornece um objeto Task do tipo genérico adequado para retornar do método GetImageStreamAsync , e
mais tarde a classe poderá ser sinalizada quando a tarefa for concluída.
O manipulador de eventos FinishedPickingMedia é chamado quando o usuário seleciona uma imagem. No
entanto, o manipulador fornece um objeto UIImage e o Task deve retornar um objeto Stream do .NET. Isso é
feito em duas etapas: Primeiro, o objeto UIImage é convertido em um arquivo JPEG na memória armazenada
em um objeto NSData e, em seguida, o objeto NSData é convertido em um objeto Stream do .NET. Uma
chamada para o método SetResult do objeto TaskCompletionSource conclui a tarefa fornecendo o objeto Stream
:
namespace DependencyServiceSample.iOS
{
public class PicturePickerImplementation : IPicturePicker
{
TaskCompletionSource<Stream> taskCompletionSource;
UIImagePickerController imagePicker;
...
void OnImagePickerFinishedPickingMedia(object sender, UIImagePickerMediaPickedEventArgs args)
{
UIImage image = args.EditedImage ?? args.OriginalImage;

if (image != null)
{
// Convert UIImage to .NET Stream object
NSData data = image.AsJPEG(1);
Stream stream = data.AsStream();

UnregisterEventHandlers();

// Set the Stream as the completion of the Task


taskCompletionSource.SetResult(stream);
}
else
{
UnregisterEventHandlers();
taskCompletionSource.SetResult(null);
}
imagePicker.DismissModalViewController(true);
}

void OnImagePickerCancelled(object sender, EventArgs args)


{
UnregisterEventHandlers();
taskCompletionSource.SetResult(null);
imagePicker.DismissModalViewController(true);
}

void UnregisterEventHandlers()
{
imagePicker.FinishedPickingMedia -= OnImagePickerFinishedPickingMedia;
imagePicker.Canceled -= OnImagePickerCancelled;
}
}
}

Um aplicativo iOS requer permissão do usuário para acessar a biblioteca de fotos do telefone. Adicione o
seguinte à seção dict do arquivo Info.plist:

<key>NSPhotoLibraryUsageDescription</key>
<string>Picture Picker uses photo library</string>

Implementação de Android
A implementação de Android usa a técnica descrita em Selecionar uma imagem e o código de exemplo. No
entanto, o método que é chamado quando o usuário selecionou uma imagem da biblioteca de imagens é uma
substituição de OnActivityResult em uma classe que deriva de Activity . Por esse motivo, a classe
MainActivity normal no projeto do Android foi complementada com um campo, uma propriedade e uma
substituição do método OnActivityResult :
public class MainActivity : FormsAppCompatActivity
{
...
// Field, property, and method for Picture Picker
public static readonly int PickImageId = 1000;

public TaskCompletionSource<Stream> PickImageTaskCompletionSource { set; get; }

protected override void OnActivityResult(int requestCode, Result resultCode, Intent intent)


{
base.OnActivityResult(requestCode, resultCode, intent);

if (requestCode == PickImageId)
{
if ((resultCode == Result.Ok) && (intent != null))
{
Android.Net.Uri uri = intent.Data;
Stream stream = ContentResolver.OpenInputStream(uri);

// Set the Stream as the completion of the Task


PickImageTaskCompletionSource.SetResult(stream);
}
else
{
PickImageTaskCompletionSource.SetResult(null);
}
}
}
}

A substituição OnActivityResult indica o arquivo de imagem selecionado com um objeto Uri do Android, mas
ele pode ser convertido em um objeto Stream do .NET chamando o método OpenInputStream do objeto
ContentResolver que foi obtido da propriedade ContentResolver da atividade.

Assim como a implementação do iOS, a implementação do Android usa um TaskCompletionSource para sinalizar
quando a tarefa foi concluída. Esse objeto TaskCompletionSource é definido como uma propriedade pública na
classe MainActivity . Isso permite que a propriedade seja referenciada na classe PicturePickerImplementation no
projeto do Android. Essa é a classe com o método GetImageStreamAsync :
[assembly: Dependency(typeof(PicturePickerImplementation))]

namespace DependencyServiceSample.Droid
{
public class PicturePickerImplementation : IPicturePicker
{
public Task<Stream> GetImageStreamAsync()
{
// Define the Intent for getting images
Intent intent = new Intent();
intent.SetType("image/*");
intent.SetAction(Intent.ActionGetContent);

// Start the picture-picker activity (resumes in MainActivity.cs)


MainActivity.Instance.StartActivityForResult(
Intent.CreateChooser(intent, "Select Picture"),
MainActivity.PickImageId);

// Save the TaskCompletionSource object as a MainActivity property


MainActivity.Instance.PickImageTaskCompletionSource = new TaskCompletionSource<Stream>();

// Return Task object


return MainActivity.Instance.PickImageTaskCompletionSource.Task;
}
}
}

Esse método acessa a classe MainActivity para várias finalidades: para a propriedade Instance , para o campo
PickImageId , para a propriedade TaskCompletionSource e para chamar StartActivityForResult . O método é
definido pela classe FormsAppCompatActivity , que é a classe base de MainActivity .

Implementação da UWP
Diferente das implementações de iOS e Android, a implementação do seletor de fotos na Plataforma Universal
do Windows não requer a classe TaskCompletionSource . A classe PicturePickerImplementation usa a classe
FileOpenPicker para ter acesso à biblioteca de fotos. Como o método PickSingleFileAsync de FileOpenPicker é
assíncrono, o método GetImageStreamAsync pode simplesmente usar await com esse método (e outros métodos
assíncronos) e retornar um objeto Stream :
[assembly: Dependency(typeof(PicturePickerImplementation))]

namespace DependencyServiceSample.UWP
{
public class PicturePickerImplementation : IPicturePicker
{
public async Task<Stream> GetImageStreamAsync()
{
// Create and initialize the FileOpenPicker
FileOpenPicker openPicker = new FileOpenPicker
{
ViewMode = PickerViewMode.Thumbnail,
SuggestedStartLocation = PickerLocationId.PicturesLibrary,
};

openPicker.FileTypeFilter.Add(".jpg");
openPicker.FileTypeFilter.Add(".jpeg");
openPicker.FileTypeFilter.Add(".png");

// Get a file and return a Stream


StorageFile storageFile = await openPicker.PickSingleFileAsync();

if (storageFile == null)
{
return null;
}

IRandomAccessStreamWithContentType raStream = await storageFile.OpenReadAsync();


return raStream.AsStreamForRead();
}
}
}

Implementação em código compartilhado


Agora que a interface foi implementada para cada plataforma, o aplicativo na biblioteca do .NET Standard pode
tirar proveito dela.
A classe App cria um Button para escolher uma foto:

Button pickPictureButton = new Button


{
Text = "Pick Photo",
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.CenterAndExpand
};
stack.Children.Add(pickPictureButton);

O manipulador Clicked usa a classe DependencyService para chamar GetImageStreamAsync . Isso resulta em uma
chamada no projeto da plataforma. Se o método retornar um objeto Stream , o manipulador criará um elemento
Image para a imagem com um TapGestureRecognizer e substituirá o StackLayout na página pelo Image :
pickPictureButton.Clicked += async (sender, e) =>
{
pickPictureButton.IsEnabled = false;
Stream stream = await DependencyService.Get<IPicturePicker>().GetImageStreamAsync();

if (stream != null)
{
Image image = new Image
{
Source = ImageSource.FromStream(() => stream),
BackgroundColor = Color.Gray
};

TapGestureRecognizer recognizer = new TapGestureRecognizer();


recognizer.Tapped += (sender2, args) =>
{
(MainPage as ContentPage).Content = stack;
pickPictureButton.IsEnabled = true;
};
image.GestureRecognizers.Add(recognizer);

(MainPage as ContentPage).Content = image;


}
else
{
pickPictureButton.IsEnabled = true;
}
};

Tocar o elemento Image faz com que a página volte ao normal.

Links relacionados
Escolher uma foto na galeria (iOS )
Selecionar uma imagem (Android)
DependencyService (amostra)
Efeitos do Xamarin.Forms
12/04/2019 • 2 minutes to read • Edit Online

As interfaces do usuário do Xamarin.Forms são renderizadas usando controles nativos da plataforma de


destino, permitindo que os aplicativos Xamarin.Forms mantenham a aparência apropriada para cada
plataforma. Efeitos permitem que os controles nativos em cada plataforma sejam personalizados sem precisar
recorrer a uma implementação de renderizador personalizado.

Introdução aos Efeitos


Efeitos permitem que os controles nativos em cada plataforma sejam personalizados e são geralmente usados
para pequenas alterações de estilo. Este artigo fornece uma introdução aos efeitos, descreve o limite entre
efeitos e renderizadores personalizados e descreve a classe PlatformEffect .

Criar um efeito
Efeitos simplificam a personalização de um controle. Este artigo demonstra como criar um efeito que altera a
cor da tela de fundo do controle Entry quando o controle obtém foco.

Passar parâmetros para um efeito


Criar um efeito que é configurado por meio de parâmetros permite que o efeito seja reutilizado. Esses artigos
demonstram o uso de propriedades para passar parâmetros para um efeito e a alteração de um parâmetro em
tempo de execução.

Invocação de eventos de um efeito


Efeitos podem invocar eventos. Este artigo mostra como criar um evento que implementa acompanhamento
de dedos multitoque de nível baixo e sinaliza um aplicativo para pressionamentos de toque, movimentos e
liberações.
Introdução aos efeitos
12/04/2019 • 6 minutes to read • Edit Online

Efeitos permitem que os controles nativos em cada plataforma sejam personalizados e são geralmente usados
para pequenas alterações de estilo. Este artigo fornece uma introdução aos efeitos, descreve o limite entre efeitos e
renderizadores personalizados e descreve a classe PlatformEffect.
Páginas, Layouts e Controles do Xamarin.Forms apresenta uma API comum para descrever interfaces do usuário
móveis multiplataforma. Cada página, layout e controle é renderizado de maneira diferente em cada plataforma
usando uma classe Renderer , que por sua vez cria um controle nativo (correspondente à representação no
Xamarin.Forms), organiza sua disposição na tela e adiciona o comportamento especificado no código
compartilhado.
Os desenvolvedores podem implementar suas próprias classes Renderer personalizadas para personalizar a
aparência e/ou o comportamento de um controle. No entanto, implementar uma classe de renderizador
personalizado para executar uma personalização de controle simples geralmente gera uma resposta pesada. Os
efeitos simplificam esse processo, permitindo que os controles nativos em cada plataforma sejam personalizado
mais facilmente.
Os efeitos são criados em projetos específicos da plataforma criando subclasses do controle PlatformEffect e, em
seguida, os controles são consumidos anexando-os a um controle apropriado em uma biblioteca .NET Standard do
Xamarin.Forms ou um projeto de Biblioteca compartilhada.

Por que usar um efeito em vez de um renderizador personalizado?


Os efeitos simplificam a personalização de um controle, são reutilizáveis e podem ser parametrizados para
aumentar ainda mais a reutilização.
Tudo que pode ser feito com um efeito também pode ser feito com um renderizador personalizado. No entanto, os
renderizadores personalizados oferecem mais flexibilidade e personalização do que os efeitos. As diretrizes a
seguir listam as circunstâncias nas quais você pode escolher um efeito em vez de um renderizador personalizado:
É recomendado usar um efeito quando alterar as propriedades de um controle específico da plataforma atinge
o resultado desejado.
Um renderizador personalizado é necessário quando há necessidade de substituir os métodos por um controle
específico da plataforma.
Um renderizador personalizado é necessário quando há necessidade de substituir o controle específico da
plataforma que implementa um controle do Xamarin.Forms.

Criando subclasses da classe PlatformEffect


A tabela a seguir lista o namespace para a classe PlatformEffect em cada plataforma, bem como os tipos de suas
propriedades:

PLATAFORMA NAMESPACE CONTÊINER CONTROLE

iOS Xamarin.Forms.Platform.iOS UIView UIView

Android Xamarin.Forms.Platform.And ViewGroup Exibir


roid
PLATAFORMA NAMESPACE CONTÊINER CONTROLE

UWP (Plataforma Universal Xamarin.Forms.Platform.UW FrameworkElement FrameworkElement


do Windows) P

Cada classe PlatformEffect específica da plataforma expõe as propriedades a seguir:


Container – faz referência ao controle específico da plataforma que está sendo usado para implementar o
layout.
Control – faz referência ao controle específico da plataforma que está sendo usado para implementar o
controle do Xamarin.Forms.
Element – faz referência ao controle do Xamarin.Forms que está sendo renderizado.

Os efeitos não têm informações de tipo sobre o contêiner, o controle ou o elemento a que estão anexados porque
eles podem ser anexados a qualquer elemento. Portanto, quando um efeito é anexado a um elemento
incompatível, ele deve ter o desempenho reduzido discretamente ou lançar uma exceção. No entanto, as
propriedades Container , Control e Element podem ser convertidas em seu tipo de implementação. Para obter
mais informações sobre esses tipos, confira Classes base do renderizador e controles nativos.
Cada classe PlatformEffect específica da plataforma expõe os métodos a seguir, que devem ser substituídos para
implementar um efeito:
OnAttached – chamado quando um efeito é anexado a um controle do Xamarin.Forms. Uma versão de
substituição desse método, em cada classe de efeito específica da plataforma, é o lugar para realizar a
personalização do controle, bem como a manipulação de exceções caso o efeito não possa ser aplicado ao
controle do Xamarin.Forms especificado.
OnDetached – chamado quando um efeito é desanexado de um controle do Xamarin.Forms. Uma versão de
substituição deste método, em cada classe de efeito específica da plataforma, é o lugar para executar qualquer
limpeza de efeito, como cancelar o registro de um manipulador de eventos.
Além disso, o PlatformEffect expõe o método OnElementPropertyChanged , que também pode ser substituído. Esse
método é chamado quando uma propriedade do elemento foi alterada. Uma versão de substituição do método,
em cada classe de efeito específica da plataforma, é o lugar para responder a alterações de propriedade vinculáveis
sobre o controle do Xamarin.Forms. Uma verificação da propriedade alterada sempre deve ser feita, pois essa
substituição pode ser chamada várias vezes.

Links relacionados
Renderizadores personalizados
Criando um efeito
12/04/2019 • 12 minutes to read • Edit Online

Baixar o exemplo
Efeitos simplificam a personalização de um controle. Este artigo demonstra como criar um efeito que altera a cor
da tela de fundo do controle Entry quando o controle obtém foco.
O processo para criar um efeito em cada projeto específico da plataforma é o seguinte:
1. Crie uma subclasse da classe PlatformEffect .
2. Substitua o método OnAttached e escreva a lógica para personalizar o controle.
3. Substitua o método OnDetached e escreva a lógica para limpar a personalização do controle se necessário.
4. Adicione um atributo ResolutionGroupName à classe do efeito. Esse atributo define um namespace para os
efeitos que abrange toda a empresa, evitando conflitos com outros efeitos de mesmo nome. Observe que esse
atributo só pode ser aplicado uma vez por projeto.
5. Adicione um atributo ExportEffect à classe do efeito. Este atributo registra o efeito com uma ID exclusiva que
é usada pelo Xamarin.Forms, em conjunto com o nome do grupo, para localizar o efeito antes de aplicá-lo a
um controle. O atributo utiliza dois parâmetros – o nome do tipo de efeito e uma cadeia de caracteres exclusiva
que será usada para localizar o efeito antes de aplicá-lo a um controle.
O efeito, em seguida, poderá ser consumido sendo anexado ao controle apropriado.

NOTE
O fornecimento de um efeito em cada projeto de plataforma é opcional. Tentar usar um efeito quando não há um efeito
registrado retornará um valor não nulo que não faz nada.

O aplicativo de exemplo demonstra um FocusEffect que altera a cor da tela de fundo de um controle quando ele
obtém o foco. O diagrama a seguir ilustra as responsabilidades de cada projeto no aplicativo de exemplo, bem
como as relações entre elas:

Um controle Entry no HomePage é personalizado pela classe FocusEffect em cada projeto específico da
plataforma. Cada classe FocusEffect é derivada da classe PlatformEffect de cada plataforma. Isso faz com que o
controle Entry seja renderizado com uma cor da tela de fundo específica da plataforma, que muda quando o
controle obtém foco, conforme mostrado nas capturas de tela seguir:
Criando o efeito em cada plataforma
As seções a seguir abordam a implementação da classe FocusEffect específica da plataforma.

Projeto do iOS
O exemplo de código a seguir mostra a implementação de FocusEffect para o projeto do iOS:
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly:ResolutionGroupName ("MyCompany")]
[assembly:ExportEffect (typeof(FocusEffect), nameof(FocusEffect))]
namespace EffectsDemo.iOS
{
public class FocusEffect : PlatformEffect
{
UIColor backgroundColor;

protected override void OnAttached ()


{
try {
Control.BackgroundColor = backgroundColor = UIColor.FromRGB (204, 153, 255);
} catch (Exception ex) {
Console.WriteLine ("Cannot set property on attached control. Error: ", ex.Message);
}
}

protected override void OnDetached ()


{
}

protected override void OnElementPropertyChanged (PropertyChangedEventArgs args)


{
base.OnElementPropertyChanged (args);

try {
if (args.PropertyName == "IsFocused") {
if (Control.BackgroundColor == backgroundColor) {
Control.BackgroundColor = UIColor.White;
} else {
Control.BackgroundColor = backgroundColor;
}
}
} catch (Exception ex) {
Console.WriteLine ("Cannot set property on attached control. Error: ", ex.Message);
}
}
}
}

O método OnAttached define a propriedade BackgroundColor do controle como roxo claro com o método
UIColor.FromRGB e também armazena essa cor em um campo. Essa funcionalidade é encapsulada em um bloco
try / catch caso o controle a que o efeito está anexado não tenha uma propriedade de BackgroundColor .
Nenhuma implementação é fornecida pelo método OnDetached porque nenhuma limpeza é necessária.
A substituição OnElementPropertyChanged responde às alterações de propriedade associáveis no controle do
Xamarin.Forms. Quando a propriedade IsFocused é alterada, a propriedade BackgroundColor do controle será
alterada para branco se o controle estiver em foco, caso contrário, é alterada para roxo claro. Essa funcionalidade é
encapsulada em um bloco try / catch caso o controle a que o efeito está anexado não tenha uma propriedade de
BackgroundColor .

Projeto do Android
O exemplo de código a seguir mostra a implementação de FocusEffect para o projeto do Android:
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

[assembly:ResolutionGroupName ("MyCompany")]
[assembly:ExportEffect(typeof(FocusEffect), nameof(FocusEffect))]
namespace EffectsDemo.Droid
{
public class FocusEffect : PlatformEffect
{
Android.Graphics.Color backgroundColor;

protected override void OnAttached ()


{
try {
backgroundColor = Android.Graphics.Color.LightGreen;
Control.SetBackgroundColor (backgroundColor);

} catch (Exception ex) {


Console.WriteLine ("Cannot set property on attached control. Error: ", ex.Message);
}
}

protected override void OnDetached ()


{
}

protected override void OnElementPropertyChanged (System.ComponentModel.PropertyChangedEventArgs args)


{
base.OnElementPropertyChanged (args);
try {
if (args.PropertyName == "IsFocused") {
if (((Android.Graphics.Drawables.ColorDrawable)Control.Background).Color ==
backgroundColor) {
Control.SetBackgroundColor (Android.Graphics.Color.Black);
} else {
Control.SetBackgroundColor (backgroundColor);
}
}
} catch (Exception ex) {
Console.WriteLine ("Cannot set property on attached control. Error: ", ex.Message);
}
}
}
}

O método OnAttached chama o método SetBackgroundColor para definir a cor da tela de fundo do controle como
verde claro e também armazena essa cor em um campo. Essa funcionalidade é encapsulada em um bloco try /
catch caso o controle a que o efeito está anexado não tenha uma propriedade de SetBackgroundColor . Nenhuma
implementação é fornecida pelo método OnDetached porque nenhuma limpeza é necessária.
A substituição OnElementPropertyChanged responde às alterações de propriedade associáveis no controle do
Xamarin.Forms. Quando a propriedade IsFocused é alterada, a cor da tela de fundo do controle será alterada
para branco se o controle estiver em foco, caso contrário, é alterada para verde claro. Essa funcionalidade é
encapsulada em um bloco try / catch caso o controle a que o efeito está anexado não tenha uma propriedade de
BackgroundColor .

Projetos da Plataforma Universal do Windows


O exemplo de código a seguir mostra a implementação de FocusEffect para projetos da UWP (Plataforma
Universal do Windows):
using Xamarin.Forms;
using Xamarin.Forms.Platform.UWP;

[assembly: ResolutionGroupName("MyCompany")]
[assembly: ExportEffect(typeof(FocusEffect), nameof(FocusEffect))]
namespace EffectsDemo.UWP
{
public class FocusEffect : PlatformEffect
{
protected override void OnAttached()
{
try
{
(Control as Windows.UI.Xaml.Controls.Control).Background = new SolidColorBrush(Colors.Cyan);
(Control as FormsTextBox).BackgroundFocusBrush = new SolidColorBrush(Colors.White);
}
catch (Exception ex)
{
Debug.WriteLine("Cannot set property on attached control. Error: ", ex.Message);
}
}

protected override void OnDetached()


{
}
}
}

O método OnAttached define a propriedade Background do controle como ciano e define a propriedade
BackgroundFocusBrush como branco. Essa funcionalidade é encapsulada em um bloco try / catch caso o controle
a que o efeito está anexado não tenha essas propriedades. Nenhuma implementação é fornecida pelo método
OnDetached porque nenhuma limpeza é necessária.

Consumindo o efeito
O processo para consumir um efeito de uma biblioteca .NET Standard do Xamarin.Forms ou de um projeto de
Biblioteca compartilhada é o seguinte:
1. Declare um controle que será personalizado pelo efeito.
2. Anexe o efeito ao controle adicionando-o à coleção Effects do controle.

NOTE
Uma instância de efeito pode ser anexada somente a um único controle. Portanto, um efeito deve ser resolvido duas vezes
para usá-lo em dois controles.

Consumindo o efeito em XAML


O exemplo de código XAML abaixo mostra um controle Entry ao qual o FocusEffect está anexado:

<Entry Text="Effect attached to an Entry" ...>


<Entry.Effects>
<local:FocusEffect />
</Entry.Effects>
...
</Entry>

A classe FocusEffect na biblioteca do .NET Standard dá suporte ao consumo do efeito em XAML e é mostrado
no exemplo de código a seguir:

public class FocusEffect : RoutingEffect


{
public FocusEffect () : base ($"MyCompany.{nameof(FocusEffect)}")
{
}
}

A classe FocusEffect cria subclasses da classe RoutingEffect , que representa um efeito independente de
plataforma que encapsula um efeito interno, que é geralmente é específico da plataforma. A classe FocusEffect
chama o construtor da classe base, passando um parâmetro composto por uma concatenação do nome do grupo
de resolução (especificado usando o atributo ResolutionGroupName na classe do efeito) e pela ID exclusiva que foi
especificada usando o atributo ExportEffect na classe do efeito. Portanto, quando o Entry é inicializado em
tempo de execução, uma nova instância do MyCompany.FocusEffect é adicionada à coleção Effects do controle.
Efeitos também podem ser anexados a controles usando um comportamento ou usando propriedades anexadas.
Para obter mais informações sobre como anexar um efeito a um controle usando um comportamento, confira
EffectBehavior reutilizável. Para obter mais informações sobre como anexar um efeito a um controle usando
propriedades anexadas, confira Passar parâmetros para um efeito.

Consumindo o efeito em C#
O Entry equivalente em C# é mostrado no exemplo de código a seguir:

var entry = new Entry {


Text = "Effect attached to an Entry",
...
};

O FocusEffect é anexado à instância de Entry adicionando o efeito à coleção Effects do controle, conforme
demonstrado no exemplo de código a seguir:

public HomePageCS ()
{
...
entry.Effects.Add (Effect.Resolve ($"MyCompany.{nameof(FocusEffect)}"));
...
}

O Effect.Resolve retorna um Effect para o nome especificado, que é uma concatenação do nome do grupo de
resolução (especificado usando o atributo ResolutionGroupName na classe do efeito) e pela ID exclusiva que foi
especificada usando o atributo ExportEffect na classe do efeito. Se uma plataforma não fornecer o efeito, o
método Effect.Resolve retornará um valor não null .

Resumo
Este artigo demonstrou como criar um efeito que altera a cor da tela de fundo do controle Entry quando o
controle obtém foco.

Links relacionados
Renderizadores personalizados
Effect
PlatformEffect
Efeito de cor da tela de fundo (amostra)
Efeito de foco (amostra)
Passando parâmetros para um efeito
12/04/2019 • 2 minutes to read • Edit Online

Parâmetros de efeito podem ser definidos por propriedades, habilitando o efeito para ser reutilizado. Parâmetros
podem ser passados para o efeito, especificando valores para cada propriedade ao instanciar o efeito.

Passando parâmetros de efeito como propriedades de tempo de


execução de linguagem comum
Propriedades do Common Language Runtime (CLR ) podem ser usadas para definir os parâmetros do efeito que
não respondem a alterações de propriedade de tempo de execução. Este artigo demonstra como usar
propriedades CLR para passar parâmetros para um efeito.

Passando parâmetros de efeito como propriedades anexadas


Propriedades anexadas podem ser usadas para definir os parâmetros do efeito que respondem a alterações de
propriedade de tempo de execução. Este artigo demonstra como usar anexados propriedades para passar
parâmetros para um efeito e alterar um parâmetro em tempo de execução.
Passando parâmetros de efeito como propriedades
de Common Language Runtime
12/04/2019 • 9 minutes to read • Edit Online

Baixar o exemplo
Propriedades de CLR (Common Language Runtime) podem ser usadas para definir parâmetros de efeito que não
respondem a alterações de propriedade de tempo de execução. Este artigo demonstra como usar propriedades de
CLR para passar parâmetros para um efeito.
O processo para criar parâmetros de efeito que não respondem a alterações de propriedade de tempo de execução
é o seguinte:
1. Criar uma public que cria subclasses da classe RoutingEffect . A classe RoutingEffect representa um efeito
independente de plataforma que encapsula um efeito interno, que é geralmente é específico da plataforma.
2. Crie um construtor que chama o construtor da classe base, passando uma concatenação do nome do grupo de
resolução e a ID exclusiva que foi especificada em cada classe de efeito específica da plataforma.
3. Adicione propriedades à classe para cada parâmetro a ser passado para o efeito.
Em seguida, os parâmetros podem ser passados para o efeito especificando valores para cada propriedade ao
instanciar o efeito.
O aplicativo de exemplo demonstra um ShadowEffect que adiciona uma sombra ao texto exibido por um controle
Label . O diagrama a seguir ilustra as responsabilidades de cada projeto no aplicativo de exemplo, bem como as
relações entre elas:

Um controle Label no HomePage é personalizado pelo LabelShadowEffect em cada projeto específico da


plataforma. Os parâmetros são passados para cada LabelShadowEffect por meio das propriedades na classe
ShadowEffect . Cada classe LabelShadowEffect é derivada da classe PlatformEffect de cada plataforma. Isso faz
com que uma sombra seja adicionada ao texto exibido pelo controle Label , conforme mostrado nas capturas de
tela seguir:

Criando parâmetros de efeito


Uma classe public que cria subclasses da classe RoutingEffect deve ser criada para representar os parâmetros
em vigor, conforme demonstrado no exemplo de código a seguir:

public class ShadowEffect : RoutingEffect


{
public float Radius { get; set; }

public Color Color { get; set; }

public float DistanceX { get; set; }

public float DistanceY { get; set; }

public ShadowEffect () : base ("MyCompany.LabelShadowEffect")


{
}
}

O ShadowEffect contém quatro propriedades que representam os parâmetros a serem passados para cada
LabelShadowEffect específico da plataforma. O construtor de classe chama o construtor da classe base, passando
um parâmetro composto por uma concatenação do nome do grupo de resolução e pela ID exclusiva que foi
especificada em cada classe de efeito específica da plataforma. Portanto, uma nova instância de
MyCompany.LabelShadowEffect será adicionada à coleção Effects do controle quando um ShadowEffect for
instanciado.

Consumindo o efeito
O exemplo de código XAML abaixo mostra um controle Label ao qual o ShadowEffect está anexado:

<Label Text="Label Shadow Effect" ...>


<Label.Effects>
<local:ShadowEffect Radius="5" DistanceX="5" DistanceY="5">
<local:ShadowEffect.Color>
<OnPlatform x:TypeArguments="Color">
<On Platform="iOS" Value="Black" />
<On Platform="Android" Value="White" />
<On Platform="UWP" Value="Red" />
</OnPlatform>
</local:ShadowEffect.Color>
</local:ShadowEffect>
</Label.Effects>
</Label>

O Label equivalente em C# é mostrado no exemplo de código a seguir:


var label = new Label {
Text = "Label Shadow Effect",
...
};

Color color = Color.Default;


switch (Device.RuntimePlatform)
{
case Device.iOS:
color = Color.Black;
break;
case Device.Android:
color = Color.White;
break;
case Device.UWP:
color = Color.Red;
break;
}

label.Effects.Add (new ShadowEffect {


Radius = 5,
Color = color,
DistanceX = 5,
DistanceY = 5
});

Nos dois exemplos de código, uma instância da classe ShadowEffect é criada, com valores especificados para cada
propriedade, antes de ser adicionada à coleção Effects do controle. Observe que a propriedade
ShadowEffect.Color usa valores de cor específicos da plataforma. Para obter mais informações, confira Classe do
dispositivo.

Criando o efeito em cada plataforma


As seções a seguir abordam a implementação da classe LabelShadowEffect específica da plataforma.
Projeto do iOS
O exemplo de código a seguir mostra a implementação de LabelShadowEffect para o projeto do iOS:
[assembly:ResolutionGroupName ("MyCompany")]
[assembly:ExportEffect (typeof(LabelShadowEffect), "LabelShadowEffect")]
namespace EffectsDemo.iOS
{
public class LabelShadowEffect : PlatformEffect
{
protected override void OnAttached ()
{
try {
var effect = (ShadowEffect)Element.Effects.FirstOrDefault (e => e is ShadowEffect);
if (effect != null) {
Control.Layer.CornerRadius = effect.Radius;
Control.Layer.ShadowColor = effect.Color.ToCGColor ();
Control.Layer.ShadowOffset = new CGSize (effect.DistanceX, effect.DistanceY);
Control.Layer.ShadowOpacity = 1.0f;
}
} catch (Exception ex) {
Console.WriteLine ("Cannot set property on attached control. Error: ", ex.Message);
}
}

protected override void OnDetached ()


{
}
}
}

O método OnAttached recupera a instância de ShadowEffect e define propriedades de Control.Layer como os


valores de propriedade especificados para criar a sombra. Essa funcionalidade é encapsulada em um bloco try /
catch caso o controle a que o efeito está anexado não tenha as propriedades de Control.Layer . Nenhuma
implementação é fornecida pelo método OnDetached porque nenhuma limpeza é necessária.
Projeto do Android
O exemplo de código a seguir mostra a implementação de LabelShadowEffect para o projeto do Android:

[assembly:ResolutionGroupName ("MyCompany")]
[assembly:ExportEffect (typeof(LabelShadowEffect), "LabelShadowEffect")]
namespace EffectsDemo.Droid
{
public class LabelShadowEffect : PlatformEffect
{
protected override void OnAttached ()
{
try {
var control = Control as Android.Widget.TextView;
var effect = (ShadowEffect)Element.Effects.FirstOrDefault (e => e is ShadowEffect);
if (effect != null) {
float radius = effect.Radius;
float distanceX = effect.DistanceX;
float distanceY = effect.DistanceY;
Android.Graphics.Color color = effect.Color.ToAndroid ();
control.SetShadowLayer (radius, distanceX, distanceY, color);
}
} catch (Exception ex) {
Console.WriteLine ("Cannot set property on attached control. Error: ", ex.Message);
}
}

protected override void OnDetached ()


{
}
}
}
O método OnAttached recupera a instância de ShadowEffect e chama o método TextView.SetShadowLayer para
criar uma sombra usando os valores de propriedade especificados. Essa funcionalidade é encapsulada em um
bloco try / catch caso o controle a que o efeito está anexado não tenha as propriedades de Control.Layer .
Nenhuma implementação é fornecida pelo método OnDetached porque nenhuma limpeza é necessária.
Projeto da Plataforma Universal do Windows
O exemplo de código a seguir mostra a implementação de LabelShadowEffect para o projeto da UWP (Plataforma
Universal do Windows):

[assembly: ResolutionGroupName ("Xamarin")]


[assembly: ExportEffect (typeof(LabelShadowEffect), "LabelShadowEffect")]
namespace EffectsDemo.UWP
{
public class LabelShadowEffect : PlatformEffect
{
bool shadowAdded = false;

protected override void OnAttached ()


{
try {
if (!shadowAdded) {
var effect = (ShadowEffect)Element.Effects.FirstOrDefault (e => e is ShadowEffect);
if (effect != null) {
var textBlock = Control as Windows.UI.Xaml.Controls.TextBlock;
var shadowLabel = new Label ();
shadowLabel.Text = textBlock.Text;
shadowLabel.FontAttributes = FontAttributes.Bold;
shadowLabel.HorizontalOptions = LayoutOptions.Center;
shadowLabel.VerticalOptions = LayoutOptions.CenterAndExpand;
shadowLabel.TextColor = effect.Color;
shadowLabel.TranslationX = effect.DistanceX;
shadowLabel.TranslationY = effect.DistanceY;

((Grid)Element.Parent).Children.Insert (0, shadowLabel);


shadowAdded = true;
}
}
} catch (Exception ex) {
Debug.WriteLine ("Cannot set property on attached control. Error: ", ex.Message);
}
}

protected override void OnDetached ()


{
}
}
}

A Plataforma Universal do Windows não fornece um efeito de sombra, de forma que a implementação de
LabelShadowEffect nas duas plataformas simula o efeito adicionando um segundo deslocamento Label atrás do
Label principal. O método OnAttached recupera a instância de ShadowEffect , cria o novo Label e define algumas
propriedades de layout no Label . Depois, ele cria a sombra definindo as propriedades TextColor , TranslationX e
TranslationY para controlar a cor e a localização do Label . Em seguida, o shadowLabel é inserido deslocado atrás
do Label principal. Essa funcionalidade é encapsulada em um bloco try / catch caso o controle a que o efeito
está anexado não tenha as propriedades de Control.Layer . Nenhuma implementação é fornecida pelo método
OnDetached porque nenhuma limpeza é necessária.

Resumo
Este artigo demonstrou como usar propriedades de CLR para passar parâmetros para um efeito. Propriedades de
CLR podem ser usadas para definir parâmetros de efeito que não respondem a alterações de propriedade de
tempo de execução.

Links relacionados
Renderizadores personalizados
Effect
PlatformEffect
RoutingEffect
Efeito de sombra (amostra)
Passando parâmetros de efeito como propriedades
anexadas
12/04/2019 • 18 minutes to read • Edit Online

Baixar o exemplo
Propriedades anexadas podem ser usadas para definir parâmetros de efeito que respondem a alterações de
propriedade de tempo de execução. Este artigo demonstra o uso de propriedades anexadas para passar
parâmetros para um efeito e a alteração de um parâmetro em tempo de execução.
O processo para criar parâmetros de efeito que respondem a alterações de propriedade de tempo de execução é o
seguinte:
1. Crie uma classe static que contém uma propriedade anexada para cada parâmetro a ser passado para o
efeito.
2. Adicione outra propriedade anexada à classe que será usada para controlar a adição ou remoção do efeito para
o controle a que a classe será anexada. Certifique-se de que a propriedade anexada registre um delegado
propertyChanged que será executado quando o valor da propriedade for alterado.
3. Crie getters e setters static para cada propriedade anexada.
4. Implemente a lógica no delegado propertyChanged para adicionar e remover o efeito.
5. Implemente uma classe aninhada dentro da classe static , com o mesmo nome do efeito, que cria uma
subclasse da classe RoutingEffect . Para o construtor, chame o construtor da classe base passando uma
concatenação do nome do grupo de resolução e a ID exclusiva que foi especificada em cada classe de efeito
específica da plataforma.
Em seguida, é possível passar parâmetros para o efeito adicionando as propriedades anexadas e valores de
propriedade ao controle apropriado. Além disso, os parâmetros podem ser alterados no tempo de execução
especificando um novo valor da propriedade anexada.

NOTE
Uma propriedade anexada é um tipo especial de propriedade associável, definida em uma classe, mas anexada a outros
objetos e reconhecível no XAML como atributos que contêm uma classe e um nome de propriedade separados por um
ponto. Para obter mais informações, confira Propriedades anexadas.

O aplicativo de exemplo demonstra um ShadowEffect que adiciona uma sombra ao texto exibido por um controle
Label . Além disso, a cor da sombra pode ser alterada em tempo de execução. O diagrama a seguir ilustra as
responsabilidades de cada projeto no aplicativo de exemplo, bem como as relações entre elas:
Um controle Label no HomePage é personalizado pelo LabelShadowEffect em cada projeto específico da
plataforma. Os parâmetros são passados para cada LabelShadowEffect por meio das propriedades anexadas na
classe ShadowEffect . Cada classe LabelShadowEffect é derivada da classe PlatformEffect de cada plataforma. Isso
faz com que uma sombra seja adicionada ao texto exibido pelo controle Label , conforme mostrado nas capturas
de tela seguir:

Criando parâmetros de efeito


Uma classe static deve ser criada para representar os parâmetros em vigor, conforme demonstrado no exemplo
de código a seguir:
public static class ShadowEffect
{
public static readonly BindableProperty HasShadowProperty =
BindableProperty.CreateAttached ("HasShadow", typeof(bool), typeof(ShadowEffect), false, propertyChanged:
OnHasShadowChanged);
public static readonly BindableProperty ColorProperty =
BindableProperty.CreateAttached ("Color", typeof(Color), typeof(ShadowEffect), Color.Default);
public static readonly BindableProperty RadiusProperty =
BindableProperty.CreateAttached ("Radius", typeof(double), typeof(ShadowEffect), 1.0);
public static readonly BindableProperty DistanceXProperty =
BindableProperty.CreateAttached ("DistanceX", typeof(double), typeof(ShadowEffect), 0.0);
public static readonly BindableProperty DistanceYProperty =
BindableProperty.CreateAttached ("DistanceY", typeof(double), typeof(ShadowEffect), 0.0);

public static bool GetHasShadow (BindableObject view)


{
return (bool)view.GetValue (HasShadowProperty);
}

public static void SetHasShadow (BindableObject view, bool value)


{
view.SetValue (HasShadowProperty, value);
}
...

static void OnHasShadowChanged (BindableObject bindable, object oldValue, object newValue)


{
var view = bindable as View;
if (view == null) {
return;
}

bool hasShadow = (bool)newValue;


if (hasShadow) {
view.Effects.Add (new LabelShadowEffect ());
} else {
var toRemove = view.Effects.FirstOrDefault (e => e is LabelShadowEffect);
if (toRemove != null) {
view.Effects.Remove (toRemove);
}
}
}

class LabelShadowEffect : RoutingEffect


{
public LabelShadowEffect () : base ("MyCompany.LabelShadowEffect")
{
}
}
}

O ShadowEffect contém cinco propriedades anexadas, com getters e setters static para cada propriedade
anexada. Quatro dessas propriedades representam parâmetros a serem passados para cada LabelShadowEffect
específico da plataforma. A classe ShadowEffect também define uma propriedade anexada HasShadow que é usada
para controlar a adição ou remoção do efeito para o controle a que a classe ShadowEffect é anexada. Essa
propriedade anexada registra o método OnHasShadowChanged que será executado quando o valor da propriedade
for alterado. Esse método adiciona ou remove o efeito com base no valor da propriedade anexada HasShadow .
A classe LabelShadowEffect aninhada, que cria uma subclasse da classe RoutingEffect , dá suporte à adição e à
remoção de efeitos. A classe RoutingEffect representa um efeito independente de plataforma que encapsula um
efeito interno, que é geralmente é específico da plataforma. Isso simplifica o processo de remoção do efeito,
porque não há nenhum acesso de tempo de compilação às informações de tipo para um efeito específico da
plataforma. O construtor LabelShadowEffect chama o construtor da classe base, passando um parâmetro
composto por uma concatenação do nome do grupo de resolução e pela ID exclusiva que foi especificada em cada
classe de efeito específica da plataforma. Isso habilita a adição e a remoção do efeito no método
OnHasShadowChanged , da seguinte maneira:

Adição de efeito – uma nova instância do LabelShadowEffect é adicionada à coleção Effects do controle.
Isso substitui o uso do método Effect.Resolve para adicionar o efeito.
Remoção de efeito – a primeira instância do LabelShadowEffect na coleção Effects do controle é recuperada
e removida.

Consumindo o efeito
Cada LabelShadowEffect específico da plataforma pode ser consumido adicionando as propriedades anexadas a
um controle Label , conforme demonstrado no exemplo de código XAML a seguir:

<Label Text="Label Shadow Effect" ...


local:ShadowEffect.HasShadow="true" local:ShadowEffect.Radius="5"
local:ShadowEffect.DistanceX="5" local:ShadowEffect.DistanceY="5">
<local:ShadowEffect.Color>
<OnPlatform x:TypeArguments="Color">
<On Platform="iOS" Value="Black" />
<On Platform="Android" Value="White" />
<On Platform="UWP" Value="Red" />
</OnPlatform>
</local:ShadowEffect.Color>
</Label>

O Label equivalente em C# é mostrado no exemplo de código a seguir:

var label = new Label {


Text = "Label Shadow Effect",
...
};

Color color = Color.Default;


switch (Device.RuntimePlatform)
{
case Device.iOS:
color = Color.Black;
break;
case Device.Android:
color = Color.White;
break;
case Device.UWP:
color = Color.Red;
break;
}

ShadowEffect.SetHasShadow (label, true);


ShadowEffect.SetRadius (label, 5);
ShadowEffect.SetDistanceX (label, 5);
ShadowEffect.SetDistanceY (label, 5);
ShadowEffect.SetColor (label, color));

Definir a propriedade anexada ShadowEffect.HasShadowcomo true executa o método


ShadowEffect.OnHasShadowChanged que adiciona ou remove o LabelShadowEffect ao controle Label . Nos dois
exemplos de código, a propriedade anexada ShadowEffect.Color fornece valores de cor específicos da plataforma.
Para obter mais informações, confira Classe do dispositivo.
Além disso, um Button permite que a cor da sombra seja alterada em tempo de execução. Quando o usuário clica
no Button , a código a seguir altera a cor da sombra definindo a propriedade anexada ShadowEffect.Color :
ShadowEffect.SetColor (label, Color.Teal);

Consumindo o efeito com um estilo


Os efeitos que podem ser consumidos adicionando propriedades anexadas a um controle também podem ser
consumidos por um estilo. O exemplo de código XAML abaixo mostra um estilo explícito para o efeito de sombra,
que pode ser aplicado a controles Label :

<Style x:Key="ShadowEffectStyle" TargetType="Label">


<Style.Setters>
<Setter Property="local:ShadowEffect.HasShadow" Value="True" />
<Setter Property="local:ShadowEffect.Radius" Value="5" />
<Setter Property="local:ShadowEffect.DistanceX" Value="5" />
<Setter Property="local:ShadowEffect.DistanceY" Value="5" />
</Style.Setters>
</Style>

O Style pode ser aplicado a um Label definindo sua propriedade Style para a instância de Style usando a
extensão de marcação StaticResource , conforme demonstrado no exemplo de código a seguir:

<Label Text="Label Shadow Effect" ... Style="{StaticResource ShadowEffectStyle}" />

Para mais informações sobre estilos, confira Estilos.

Criando o efeito em cada plataforma


As seções a seguir abordam a implementação da classe LabelShadowEffect específica da plataforma.
Projeto do iOS
O exemplo de código a seguir mostra a implementação de LabelShadowEffect para o projeto do iOS:
[assembly:ResolutionGroupName ("MyCompany")]
[assembly:ExportEffect (typeof(LabelShadowEffect), "LabelShadowEffect")]
namespace EffectsDemo.iOS
{
public class LabelShadowEffect : PlatformEffect
{
protected override void OnAttached ()
{
try {
UpdateRadius ();
UpdateColor ();
UpdateOffset ();
Control.Layer.ShadowOpacity = 1.0f;
} catch (Exception ex) {
Console.WriteLine ("Cannot set property on attached control. Error: ", ex.Message);
}
}

protected override void OnDetached ()


{
}
...

void UpdateRadius ()
{
Control.Layer.CornerRadius = (nfloat)ShadowEffect.GetRadius (Element);
}

void UpdateColor ()
{
Control.Layer.ShadowColor = ShadowEffect.GetColor (Element).ToCGColor ();
}

void UpdateOffset ()
{
Control.Layer.ShadowOffset = new CGSize (
(double)ShadowEffect.GetDistanceX (Element),
(double)ShadowEffect.GetDistanceY (Element));
}
}

O método OnAttachedchama métodos que recuperam os valores de propriedade anexada usando os getters
ShadowEffect e que definem as propriedades de Control.Layer com os valores da propriedade para criar a
sombra. Essa funcionalidade é encapsulada em um bloco try / catch caso o controle a que o efeito está anexado
não tenha as propriedades de Control.Layer . Nenhuma implementação é fornecida pelo método OnDetached
porque nenhuma limpeza é necessária.
Respondendo a alterações de propriedade
Se qualquer um dos valores da propriedade anexada ShadowEffect for alterado em tempo de execução, o efeito
precisará responder exibindo as alterações. Uma versão de substituição do método OnElementPropertyChanged , na
classe de efeito específica da plataforma, é o lugar para responder a alterações de propriedade vinculáveis,
conforme demonstrado no código de exemplo a seguir:
public class LabelShadowEffect : PlatformEffect
{
...
protected override void OnElementPropertyChanged (PropertyChangedEventArgs args)
{
if (args.PropertyName == ShadowEffect.RadiusProperty.PropertyName) {
UpdateRadius ();
} else if (args.PropertyName == ShadowEffect.ColorProperty.PropertyName) {
UpdateColor ();
} else if (args.PropertyName == ShadowEffect.DistanceXProperty.PropertyName ||
args.PropertyName == ShadowEffect.DistanceYProperty.PropertyName) {
UpdateOffset ();
}
}
...
}

O método OnElementPropertyChanged atualiza o raio, a cor ou o deslocamento da sombra, desde que o valor da
propriedade anexada ShadowEffect tenha sido alterado. Uma verificação da propriedade alterada sempre deve ser
feita, pois essa substituição pode ser chamada várias vezes.
Projeto do Android
O exemplo de código a seguir mostra a implementação de LabelShadowEffect para o projeto do Android:
[assembly:ResolutionGroupName ("MyCompany")]
[assembly:ExportEffect (typeof(LabelShadowEffect), "LabelShadowEffect")]
namespace EffectsDemo.Droid
{
public class LabelShadowEffect : PlatformEffect
{
Android.Widget.TextView control;
Android.Graphics.Color color;
float radius, distanceX, distanceY;

protected override void OnAttached ()


{
try {
control = Control as Android.Widget.TextView;
UpdateRadius ();
UpdateColor ();
UpdateOffset ();
UpdateControl ();
} catch (Exception ex) {
Console.WriteLine ("Cannot set property on attached control. Error: ", ex.Message);
}
}

protected override void OnDetached ()


{
}
...

void UpdateControl ()
{
if (control != null) {
control.SetShadowLayer (radius, distanceX, distanceY, color);
}
}

void UpdateRadius ()
{
radius = (float)ShadowEffect.GetRadius (Element);
}

void UpdateColor ()
{
color = ShadowEffect.GetColor (Element).ToAndroid ();
}

void UpdateOffset ()
{
distanceX = (float)ShadowEffect.GetDistanceX (Element);
distanceY = (float)ShadowEffect.GetDistanceY (Element);
}
}

O método OnAttached chama métodos que recuperam os valores de propriedade anexada usando os getters
ShadowEffect e chama um método que chama o método TextView.SetShadowLayer para criar uma sombra usando
os valores da propriedade. Essa funcionalidade é encapsulada em um bloco try / catch caso o controle a que o
efeito está anexado não tenha as propriedades de Control.Layer . Nenhuma implementação é fornecida pelo
método OnDetached porque nenhuma limpeza é necessária.
Respondendo a alterações de propriedade
Se qualquer um dos valores da propriedade anexada ShadowEffect for alterado em tempo de execução, o efeito
precisará responder exibindo as alterações. Uma versão de substituição do método OnElementPropertyChanged , na
classe de efeito específica da plataforma, é o lugar para responder a alterações de propriedade vinculáveis,
conforme demonstrado no código de exemplo a seguir:
public class LabelShadowEffect : PlatformEffect
{
...
protected override void OnElementPropertyChanged (PropertyChangedEventArgs args)
{
if (args.PropertyName == ShadowEffect.RadiusProperty.PropertyName) {
UpdateRadius ();
UpdateControl ();
} else if (args.PropertyName == ShadowEffect.ColorProperty.PropertyName) {
UpdateColor ();
UpdateControl ();
} else if (args.PropertyName == ShadowEffect.DistanceXProperty.PropertyName ||
args.PropertyName == ShadowEffect.DistanceYProperty.PropertyName) {
UpdateOffset ();
UpdateControl ();
}
}
...
}

O método OnElementPropertyChanged atualiza o raio, a cor ou o deslocamento da sombra, desde que o valor da
propriedade anexada ShadowEffect tenha sido alterado. Uma verificação da propriedade alterada sempre deve ser
feita, pois essa substituição pode ser chamada várias vezes.
Projeto da Plataforma Universal do Windows
O exemplo de código a seguir mostra a implementação de LabelShadowEffect para o projeto da UWP (Plataforma
Universal do Windows):
[assembly: ResolutionGroupName ("MyCompany")]
[assembly: ExportEffect (typeof(LabelShadowEffect), "LabelShadowEffect")]
namespace EffectsDemo.UWP
{
public class LabelShadowEffect : PlatformEffect
{
Label shadowLabel;
bool shadowAdded = false;

protected override void OnAttached ()


{
try {
if (!shadowAdded) {
var textBlock = Control as Windows.UI.Xaml.Controls.TextBlock;

shadowLabel = new Label ();


shadowLabel.Text = textBlock.Text;
shadowLabel.FontAttributes = FontAttributes.Bold;
shadowLabel.HorizontalOptions = LayoutOptions.Center;
shadowLabel.VerticalOptions = LayoutOptions.CenterAndExpand;

UpdateColor ();
UpdateOffset ();

((Grid)Element.Parent).Children.Insert (0, shadowLabel);


shadowAdded = true;
}
} catch (Exception ex) {
Debug.WriteLine ("Cannot set property on attached control. Error: ", ex.Message);
}
}

protected override void OnDetached ()


{
}
...

void UpdateColor ()
{
shadowLabel.TextColor = ShadowEffect.GetColor (Element);
}

void UpdateOffset ()
{
shadowLabel.TranslationX = ShadowEffect.GetDistanceX (Element);
shadowLabel.TranslationY = ShadowEffect.GetDistanceY (Element);
}
}
}

A Plataforma Universal do Windows não fornece um efeito de sombra, de forma que a implementação de
LabelShadowEffect nas duas plataformas simula o efeito adicionando um segundo deslocamento Label atrás do
Label principal. O método OnAttached cria o novo Label e define algumas propriedades de layout no Label .
Em seguida, ele chama métodos que recuperam os valores da propriedade anexada usando os getters
ShadowEffect e cria a sombra definindo as propriedades TextColor , TranslationX e TranslationY para controlar
a cor e a localização do Label . Em seguida, o shadowLabel é inserido deslocado atrás do Label principal. Essa
funcionalidade é encapsulada em um bloco try / catch caso o controle a que o efeito está anexado não tenha as
propriedades de Control.Layer . Nenhuma implementação é fornecida pelo método OnDetached porque nenhuma
limpeza é necessária.
Respondendo a alterações de propriedade
Se qualquer um dos valores da propriedade anexada ShadowEffect for alterado em tempo de execução, o efeito
precisará responder exibindo as alterações. Uma versão de substituição do método OnElementPropertyChanged , na
classe de efeito específica da plataforma, é o lugar para responder a alterações de propriedade vinculáveis,
conforme demonstrado no código de exemplo a seguir:

public class LabelShadowEffect : PlatformEffect


{
...
protected override void OnElementPropertyChanged (PropertyChangedEventArgs args)
{
if (args.PropertyName == ShadowEffect.ColorProperty.PropertyName) {
UpdateColor ();
} else if (args.PropertyName == ShadowEffect.DistanceXProperty.PropertyName ||
args.PropertyName == ShadowEffect.DistanceYProperty.PropertyName) {
UpdateOffset ();
}
}
...
}

O método OnElementPropertyChanged atualiza a cor ou o deslocamento da sombra, desde que o valor da


propriedade anexada ShadowEffect tenha sido alterado. Uma verificação da propriedade alterada sempre deve ser
feita, pois essa substituição pode ser chamada várias vezes.

Resumo
Este artigo demonstrou o uso de propriedades anexadas para passar parâmetros para um efeito e a alteração de
um parâmetro em tempo de execução. Propriedades anexadas podem ser usadas para definir parâmetros de efeito
que respondem a alterações de propriedade de tempo de execução.

Links relacionados
Renderizadores personalizados
Effect
PlatformEffect
RoutingEffect
Efeito de sombra (amostra)
Invocando eventos por meio de efeitos
12/04/2019 • 37 minutes to read • Edit Online

Baixar o exemplo
Um efeito pode definir e invocar um evento, sinalizando as alterações na exibição nativa subjacente. Este artigo
mostra como implementar o acompanhamento de dedos multitoque de nível baixo e como gerar eventos que
sinalizam a atividade de toque.
O efeito descrito neste artigo fornece acesso aos eventos de toque de nível baixo. Esses eventos de nível baixo não
estão disponíveis por meio das classes GestureRecognizer existentes, mas elas são vitais para alguns tipos de
aplicativos. Por exemplo, um aplicativo de pintura a dedo precisa acompanhar dedos individuais à medida que eles
se movem na tela. Um teclado musical precisa detectar toques e liberações em teclas individuais, bem como o
deslize de um dedo de uma tecla a outra em um glissando.
Um efeito é ideal para o acompanhamento de dedos multitoque porque ele pode ser anexado a qualquer
elemento do Xamarin.Forms.

Eventos de toque da plataforma


O iOS, o Android e a Plataforma Universal do Windows incluem uma API de nível baixo que permite que os
aplicativos detectem a atividade de toque. Essas plataformas todas distinguem entre três tipos básicos de eventos
de toque:
Pressionado, quando um dedo toca a tela
Movido, quando um dedo que toca a tela se move
Liberado, quando o dedo é liberado da tela
Em um ambiente multitoque, vários dedos podem tocar a tela ao mesmo tempo. As várias plataformas incluem
um número de ID (identificação) que os aplicativos podem usar para distinguir entre vários dedos.
No iOS, a classe UIView define três métodos substituíveis, TouchesBegan , TouchesMoved e TouchesEnded ,
correspondentes a esses três eventos básicos. O artigo Acompanhamento de dedos multitoque descreve como
usar esses métodos. No entanto, um programa do iOS não precisa substituir uma classe que deriva de UIView
para usar esses métodos. O UIGestureRecognizer do iOS também define esses mesmos três métodos, sendo que
você pode anexar uma instância de uma classe que deriva de UIGestureRecognizer a qualquer objeto UIView .
No Android, a classe View define um método substituível chamado OnTouchEvent para processar todas as
atividades de toque. O tipo da atividade de toque é definido pelos membros de enumeração Down , PointerDown ,
Move , Up e PointerUp , conforme descrito no artigo Acompanhamento de dedos multitoque. O View do Android
também define um evento chamado Touch que permite que um manipulador de eventos seja anexado a qualquer
objeto View .
No UWP (Plataforma Universal do Windows), a classe UIElement define eventos chamados PointerPressed ,
PointerMoved e PointerReleased . Eles são descritos no artigo Manipular a entrada de ponteiro no MSDN e na
documentação da API para a classe UIElement .
A API do Pointer na Plataforma Universal do Windows se destina a unificar o mouse, o toque e a entrada à
caneta. Por esse motivo, o evento PointerMoved é invocado quando o mouse se move entre um elemento, mesmo
quando um botão do mouse não é pressionado. O objeto PointerRoutedEventArgs que acompanha esses eventos
tem uma propriedade chamada Pointer que tem uma propriedade chamada IsInContact , indicando se um
botão do mouse é pressionado ou um dedo está em contato com a tela.
Além disso, o UWP define mais dois eventos chamados PointerEntered e PointerExited . Eles indicam quando
um mouse ou o dedo e move de um elemento para outro. Por exemplo, considere dois elementos adjacentes,
chamados A e B. Ambos os elementos têm manipuladores instalados para os eventos de ponteiro. Quando um
dedo pressiona A, o evento PointerPressed é invocado. Conforme o dedo se move, A invoca eventos
PointerMoved . Se o dedo se move de A para B, A invoca um evento PointerExited e B invoca um evento
PointerEntered . Se o dedo é então liberado, B invoca um evento PointerReleased .

As plataformas iOS e Android são diferentes do UWP: A exibição que primeiro obtém a chamada a TouchesBegan
ou OnTouchEvent quando um dedo toca a exibição continua obtendo todas as atividades de toque, mesmo se o
dedo se mover para diferentes exibições. O UWP pode se comportar de forma semelhante se o aplicativo capturar
o ponteiro: No manipulador de eventos PointerEntered , o elemento chama CapturePointer e, em seguida, obtém
todas as atividades de toque desse dedo.
A abordagem do UWP prova ser muito útil para alguns tipos de aplicativos, por exemplo, um teclado musical.
Cada tecla pode manipular os eventos de toque dessa tecla e detectar quando um dedo deslizou de uma tecla para
outra usando os eventos PointerEntered e PointerExited .
Por esse motivo, o efeito do acompanhamento de toque descrito neste artigo implementa a abordagem do UWP.

A API de efeito do acompanhamento de toque


A amostra Demonstrações do efeito de acompanhamento de toque contém as classes (e uma enumeração)
que implementam o acompanhamento de toque de nível baixo. Esses tipos pertencem ao namespace
TouchTracking e começam com a palavra Touch . O projeto TouchTrackingEffectDemos da biblioteca do .NET
Standard inclui a enumeração TouchActionType para o tipo de eventos de toque:

public enum TouchActionType


{
Entered,
Pressed,
Moved,
Released,
Exited,
Cancelled
}

Todas as plataformas também incluem um evento que indica que o evento de toque foi cancelado.
A classe na biblioteca do .NET Standard deriva de RoutingEffect e define um evento chamado
TouchEffect
TouchAction e um método chamado OnTouchAction que invoca o evento TouchAction :

public class TouchEffect : RoutingEffect


{
public event TouchActionEventHandler TouchAction;

public TouchEffect() : base("XamarinDocs.TouchEffect")


{
}

public bool Capture { set; get; }

public void OnTouchAction(Element element, TouchActionEventArgs args)


{
TouchAction?.Invoke(element, args);
}
}
Observe também a propriedade Capture . Para capturar eventos de toque, um aplicativo precisa definir essa
propriedade como true anterior a um evento Pressed . Caso contrário, os eventos de toque se comportam como
aqueles mostrados na Plataforma Universal do Windows.
A classe TouchActionEventArgs na biblioteca do .NET Standard contém todas as informações que acompanham
cada evento:

public class TouchActionEventArgs : EventArgs


{
public TouchActionEventArgs(long id, TouchActionType type, Point location, bool isInContact)
{
Id = id;
Type = type;
Location = location;
IsInContact = isInContact;
}

public long Id { private set; get; }

public TouchActionType Type { private set; get; }

public Point Location { private set; get; }

public bool IsInContact { private set; get; }


}

Um aplicativo pode usar a propriedade Id para acompanhar dedos individuais. Observe a propriedade
IsInContact . Essa propriedade é sempre true para eventos Pressed e false para eventos Released . Ela
também é sempre true para eventos Moved no iOS e no Android. A propriedade IsInContact pode ser false
para eventos Moved na Plataforma Universal do Windows quando o programa está em execução na área de
trabalho e o ponteiro do mouse se move sem um botão pressionado.
Você pode usar a classe TouchEffect em seus próprios aplicativos incluindo o arquivo no projeto de biblioteca do
.NET Standard da solução e adicionando uma instância à coleção Effects de qualquer elemento do
Xamarin.Forms. Anexe um manipulador ao evento TouchAction para obter os eventos de toque.
Para usar TouchEffect em seu próprio aplicativo, você também precisará das implementações de plataforma
incluídas na solução TouchTrackingEffectDemos.

As implementações do efeito de acompanhamento de toque


As implementações do iOS, do Android e do UWP do TouchEffect são descritas abaixo começando com a
implementação mais simples (UWP ) e terminando com a implementação do iOS, porque ela é estruturalmente
mais complexa do que as outras.
A implementação do UWP
A implementação do UWP do TouchEffect é a mais simples. Como de costume, a classe deriva de
PlatformEffect e inclui dois atributos de assembly:
[assembly: ResolutionGroupName("XamarinDocs")]
[assembly: ExportEffect(typeof(TouchTracking.UWP.TouchEffect), "TouchEffect")]

namespace TouchTracking.UWP
{
public class TouchEffect : PlatformEffect
{
...
}
}

A substituição OnAttached salva algumas informações como campos e anexa manipuladores a todos os eventos
de ponteiro:

public class TouchEffect : PlatformEffect


{
FrameworkElement frameworkElement;
TouchTracking.TouchEffect effect;
Action<Element, TouchActionEventArgs> onTouchAction;

protected override void OnAttached()


{
// Get the Windows FrameworkElement corresponding to the Element that the effect is attached to
frameworkElement = Control == null ? Container : Control;

// Get access to the TouchEffect class in the .NET Standard library


effect = (TouchTracking.TouchEffect)Element.Effects.
FirstOrDefault(e => e is TouchTracking.TouchEffect);

if (effect != null && frameworkElement != null)


{
// Save the method to call on touch events
onTouchAction = effect.OnTouchAction;

// Set event handlers on FrameworkElement


frameworkElement.PointerEntered += OnPointerEntered;
frameworkElement.PointerPressed += OnPointerPressed;
frameworkElement.PointerMoved += OnPointerMoved;
frameworkElement.PointerReleased += OnPointerReleased;
frameworkElement.PointerExited += OnPointerExited;
frameworkElement.PointerCanceled += OnPointerCancelled;
}
}
...
}

O manipulador OnPointerPressed invoca o evento de efeito chamando o campo onTouchAction no método


CommonHandler :
public class TouchEffect : PlatformEffect
{
...
void OnPointerPressed(object sender, PointerRoutedEventArgs args)
{
CommonHandler(sender, TouchActionType.Pressed, args);

// Check setting of Capture property


if (effect.Capture)
{
(sender as FrameworkElement).CapturePointer(args.Pointer);
}
}
...
void CommonHandler(object sender, TouchActionType touchActionType, PointerRoutedEventArgs args)
{
PointerPoint pointerPoint = args.GetCurrentPoint(sender as UIElement);
Windows.Foundation.Point windowsPoint = pointerPoint.Position;

onTouchAction(Element, new TouchActionEventArgs(args.Pointer.PointerId,


touchActionType,
new Point(windowsPoint.X, windowsPoint.Y),
args.Pointer.IsInContact));
}
}

OnPointerPressed também verifica o valor da propriedade Capture na classe de efeito na biblioteca do .NET
Standard e chama CapturePointer se ele é true .

Os outros manipuladores de eventos do UWP são ainda mais simples:

public class TouchEffect : PlatformEffect


{
...
void OnPointerEntered(object sender, PointerRoutedEventArgs args)
{
CommonHandler(sender, TouchActionType.Entered, args);
}
...
}

A implementação do Android
As implementações do Android e do iOS são necessariamente mais complexas, porque precisam implementar os
eventos Exited e Entered quando um dedo se move de um elemento para outro. Ambas as implementações são
estruturadas de forma semelhante.
A classe TouchEffect do Android instala um manipulador para o evento Touch :

view = Control == null ? Container : Control;


...
view.Touch += OnTouch;

A classe também define dois dicionários estáticos:


public class TouchEffect : PlatformEffect
{
...
static Dictionary<Android.Views.View, TouchEffect> viewDictionary =
new Dictionary<Android.Views.View, TouchEffect>();

static Dictionary<int, TouchEffect> idToEffectDictionary =


new Dictionary<int, TouchEffect>();
...

O viewDictionary obtém uma nova entrada sempre que a substituição OnAttached é chamada:

viewDictionary.Add(view, this);

A entrada é removida do dicionário em OnDetached . Todas as instâncias de TouchEffect são associadas a uma
exibição específica à qual o efeito é anexado. O dicionário estático permite que qualquer instância TouchEffect
enumere todas as outras exibições e suas instâncias TouchEffect correspondentes. Isso é necessário para permitir
a transferência dos eventos de uma exibição para outra.
O Android atribui um código de ID a eventos de toque, que permite que um aplicativo acompanhe dedos
individuais. O idToEffectDictionary associa esse código de ID a uma instância TouchEffect . Um item é
adicionado a esse dicionário quando o manipulador Touch é chamado para um pressionamento de dedo:

void OnTouch(object sender, Android.Views.View.TouchEventArgs args)


{
...
switch (args.Event.ActionMasked)
{
case MotionEventActions.Down:
case MotionEventActions.PointerDown:
FireEvent(this, id, TouchActionType.Pressed, screenPointerCoords, true);

idToEffectDictionary.Add(id, this);

capture = libTouchEffect.Capture;
break;

O item é removido do idToEffectDictionary quando o dedo é liberado da tela. O método FireEvent apenas
acumula todas as informações necessárias para chamar o método OnTouchAction :

void FireEvent(TouchEffect touchEffect, int id, TouchActionType actionType, Point pointerLocation, bool
isInContact)
{
// Get the method to call for firing events
Action<Element, TouchActionEventArgs> onTouchAction = touchEffect.libTouchEffect.OnTouchAction;

// Get the location of the pointer within the view


touchEffect.view.GetLocationOnScreen(twoIntArray);
double x = pointerLocation.X - twoIntArray[0];
double y = pointerLocation.Y - twoIntArray[1];
Point point = new Point(fromPixels(x), fromPixels(y));

// Call the method


onTouchAction(touchEffect.formsElement,
new TouchActionEventArgs(id, actionType, point, isInContact));
}

Todos os outros tipos de toque são processados de duas maneiras diferentes: Se a propriedade Capture for true ,
o evento de toque é uma tradução bastante simples para as informações de TouchEffect . Isso fica mais
complicado quando Capture é false porque os eventos de toque talvez precisem ser movidos de uma exibição
para outra. Essa é a responsabilidade do método CheckForBoundaryHop , que é chamado durante eventos de
movimentação. Esse método faz uso de ambos os dicionários estáticos. Ele enumera pelo viewDictionary para
determinar a exibição que o dedo está tocando no momento e, em seguida, ele usa idToEffectDictionary para
armazenar a instância TouchEffect atual (e, portanto, a exibição atual) associado a uma ID específica:

void CheckForBoundaryHop(int id, Point pointerLocation)


{
TouchEffect touchEffectHit = null;

foreach (Android.Views.View view in viewDictionary.Keys)


{
// Get the view rectangle
try
{
view.GetLocationOnScreen(twoIntArray);
}
catch // System.ObjectDisposedException: Cannot access a disposed object.
{
continue;
}
Rectangle viewRect = new Rectangle(twoIntArray[0], twoIntArray[1], view.Width, view.Height);

if (viewRect.Contains(pointerLocation))
{
touchEffectHit = viewDictionary[view];
}
}

if (touchEffectHit != idToEffectDictionary[id])
{
if (idToEffectDictionary[id] != null)
{
FireEvent(idToEffectDictionary[id], id, TouchActionType.Exited, pointerLocation, true);
}
if (touchEffectHit != null)
{
FireEvent(touchEffectHit, id, TouchActionType.Entered, pointerLocation, true);
}
idToEffectDictionary[id] = touchEffectHit;
}
}

Se há uma alteração no idToEffectDictionary , o método potencialmente chama FireEvent para Exited e


Entered para a transferência de uma exibição para outra. No entanto, o dedo pode ter sido movido para uma área
ocupada por uma exibição sem um TouchEffect anexado ou dessa área para uma exibição com o efeito anexado.
Observe que o try e o catch são bloqueados quando a exibição é acessada. Em uma página na qual o usuário
navega e, em seguida, navega novamente para a home page, o método OnDetached não é chamado e os itens
permanecem no viewDictionary , mas o Android os considera descartados.
A implementação do iOS
A implementação do iOS é semelhante à implementação do Android, exceto que a classe TouchEffect do iOS
precisa criar uma instância de um derivado do UIGestureRecognizer . Essa é uma classe no projeto do iOS
chamada TouchRecognizer . Essa classe mantém dois dicionários estáticos que armazenam instâncias
TouchRecognizer :
static Dictionary<UIView, TouchRecognizer> viewDictionary =
new Dictionary<UIView, TouchRecognizer>();

static Dictionary<long, TouchRecognizer> idToTouchDictionary =


new Dictionary<long, TouchRecognizer>();

Grande parte da estrutura desta classe TouchRecognizer é semelhante à classe TouchEffect do Android.

IMPORTANT
Muitas das exibições na UIKitnão têm toque habilitado por padrão. O toque pode ser habilitado adicionando
view.UserInteractionEnabled = true; para substituir OnAttached na classe TouchEffect no projeto do iOS. Isso
deve ocorrer após a obtenção do UIView , que corresponde ao elemento ao qual o efeito está anexado.

Colocando o efeito de toque para funcionar


O programa TouchTrackingEffectDemos contém cinco páginas que testam o efeito de acompanhamento de
toque para tarefas comuns.
A página Arrastando BoxView permite que você adicione elementos BoxView a um AbsoluteLayout e, em
seguida, arraste-os na tela. O arquivo XAML cria uma instância de duas exibições Button para adicionar
elementos BoxView ao AbsoluteLayout e desmarcar o AbsoluteLayout .
O método no arquivo code-behind que adiciona uma nova BoxView ao AbsoluteLayout também adiciona um
objeto TouchEffect à BoxView e anexa um manipulador de eventos ao efeito:

void AddBoxViewToLayout()
{
BoxView boxView = new BoxView
{
WidthRequest = 100,
HeightRequest = 100,
Color = new Color(random.NextDouble(),
random.NextDouble(),
random.NextDouble())
};

TouchEffect touchEffect = new TouchEffect();


touchEffect.TouchAction += OnTouchEffectAction;
boxView.Effects.Add(touchEffect);
absoluteLayout.Children.Add(boxView);
}

O manipulador TouchAction processa todos os eventos de toque para todos os elementos BoxView , mas é
necessário ter algum cuidado: Ele não pode permitir dois dedos em uma única BoxView porque o programa
implementa apenas a operação de arrastar e os dois dedos interferirão um com o outro. Por esse motivo, a página
define uma classe inserida para cada dedo acompanhado no momento:
class DragInfo
{
public DragInfo(long id, Point pressPoint)
{
Id = id;
PressPoint = pressPoint;
}

public long Id { private set; get; }

public Point PressPoint { private set; get; }


}

Dictionary<BoxView, DragInfo> dragDictionary = new Dictionary<BoxView, DragInfo>();

O dragDictionary contém uma entrada para cada BoxView que está sendo arrastado no momento.
A ação de toque Pressed adiciona um item a esse dicionário e a ação Released remove-o. A lógica Pressed
precisa verificar se já há um item no dicionário para esse BoxView . Nesse caso, a BoxView já está sendo arrastada
e o novo evento é um segundo dedo sobre essa mesma BoxView . Para as ações Moved e Released , o
manipulador de eventos precisa verificar se o dicionário tem uma entrada para essa BoxView e se a propriedade
Id do toque para essa BoxView arrastada corresponde à entrada do dicionário:

void OnTouchEffectAction(object sender, TouchActionEventArgs args)


{
BoxView boxView = sender as BoxView;

switch (args.Type)
{
case TouchActionType.Pressed:
// Don't allow a second touch on an already touched BoxView
if (!dragDictionary.ContainsKey(boxView))
{
dragDictionary.Add(boxView, new DragInfo(args.Id, args.Location));

// Set Capture property to true


TouchEffect touchEffect = (TouchEffect)boxView.Effects.FirstOrDefault(e => e is TouchEffect);
touchEffect.Capture = true;
}
break;

case TouchActionType.Moved:
if (dragDictionary.ContainsKey(boxView) && dragDictionary[boxView].Id == args.Id)
{
Rectangle rect = AbsoluteLayout.GetLayoutBounds(boxView);
Point initialLocation = dragDictionary[boxView].PressPoint;
rect.X += args.Location.X - initialLocation.X;
rect.Y += args.Location.Y - initialLocation.Y;
AbsoluteLayout.SetLayoutBounds(boxView, rect);
}
break;

case TouchActionType.Released:
if (dragDictionary.ContainsKey(boxView) && dragDictionary[boxView].Id == args.Id)
{
dragDictionary.Remove(boxView);
}
break;
}
}

A lógica Pressed define a propriedade Capture do objeto TouchEffect como true . Isso tem o efeito de fornecer
todos os eventos seguintes desse dedo ao mesmo manipulador de eventos.
A lógica Moved move a BoxView alterando a propriedade anexada LayoutBounds . A propriedade Location dos
argumentos do evento sempre é relativa à BoxView que está sendo arrastada e, se a BoxView estiver sendo
arrastada a uma taxa constante, as propriedades Location dos eventos consecutivos serão aproximadamente as
mesmas. Por exemplo, se um dedo pressiona a BoxView em seu centro, a ação Pressed armazena uma
propriedade PressPoint de (50, 50), que permanece a mesma para eventos seguintes. Se a BoxView é arrastada
diagonalmente a uma taxa constante, as propriedades Location seguintes durante a ação Moved podem ser
valores de (55, 55); nesse caso, a lógica Moved adiciona 5 à posição horizontal e vertical da BoxView . Isso move a
BoxView para que seu centro fique novamente diretamente sob o dedo.

Você pode mover vários elementos BoxView simultaneamente usando dedos diferentes.

Criando subclasses da exibição


Geralmente, é mais fácil para um elemento do Xamarin.Forms manipular seus próprios eventos de toque. A
página Arrastando a BoxView arrastável funciona da mesma maneira que a página Arrastando BoxView,
mas os elementos que o usuário arrasta são instâncias de uma classe DraggableBoxView que deriva de BoxView :
class DraggableBoxView : BoxView
{
bool isBeingDragged;
long touchId;
Point pressPoint;

public DraggableBoxView()
{
TouchEffect touchEffect = new TouchEffect
{
Capture = true
};
touchEffect.TouchAction += OnTouchEffectAction;
Effects.Add(touchEffect);
}

void OnTouchEffectAction(object sender, TouchActionEventArgs args)


{
switch (args.Type)
{
case TouchActionType.Pressed:
if (!isBeingDragged)
{
isBeingDragged = true;
touchId = args.Id;
pressPoint = args.Location;
}
break;

case TouchActionType.Moved:
if (isBeingDragged && touchId == args.Id)
{
TranslationX += args.Location.X - pressPoint.X;
TranslationY += args.Location.Y - pressPoint.Y;
}
break;

case TouchActionType.Released:
if (isBeingDragged && touchId == args.Id)
{
isBeingDragged = false;
}
break;
}
}
}

O construtor cria e anexa o TouchEffect e define a propriedade Capture quando é criada uma instância desse
objeto pela primeira vez. Nenhum dicionário é necessário porque a própria classe armazena os valores
isBeingDragged , pressPoint e touchId associados a cada dedo. A manipulação de Moved altera as propriedades
TranslationX e TranslationY e, portanto, a lógica funcionará mesmo se o pai da DraggableBoxView não for um
AbsoluteLayout .

Integração com o SkiaSharp


As duas próximas demonstrações exigem elementos gráficos e usam o SkiaSharp para essa finalidade. Talvez você
deseje saber mais sobre como Usar o SkiaSharp no Xamarin.Forms antes de estudar esses exemplos. Os dois
primeiros artigos ("Noções básicas de desenho do SkiaSharp" e "Linhas e caminhos do SkiaSharp") abrangem
tudo o que você precisará aqui.
A página Desenho de elipse permite que você desenhe uma elipse passando o dedo na tela. Dependendo de
como você mover o dedo, você poderá desenhar a elipse do canto superior esquerdo para o canto inferior direito
ou de qualquer outro canto para o canto oposto. A elipse é desenhada com uma cor e uma opacidade aleatórias.
Se, em seguida, você tocar uma das elipses, poderá arrastá-la para outra localização. Isso exige uma técnica
conhecida como "teste de clique," que envolve a pesquisa do objeto gráfico em um ponto específico. As elipses do
SkiaSharp não são elementos do Xamarin.Forms e, portanto, não podem executar seu próprio processamento de
TouchEffect . O TouchEffect precisa ser aplicada a todo objeto da SKCanvasView .

O arquivo EllipseDrawPage.xaml cria uma instância da SKCanvasView em uma Grid de célula única. O objeto
TouchEffect é anexado a esse Grid :

<Grid x:Name="canvasViewGrid"
Grid.Row="1"
BackgroundColor="White">

<skia:SKCanvasView x:Name="canvasView"
PaintSurface="OnCanvasViewPaintSurface" />
<Grid.Effects>
<tt:TouchEffect Capture="True"
TouchAction="OnTouchEffectAction" />
</Grid.Effects>
</Grid>

No Android e na Plataforma Universal do Windows, o TouchEffect pode ser anexado diretamente à


SKCanvasView , mas no iOS isso não funciona. Observe que a propriedade Capture está definida como true .
Cada elipse renderizada pelo SkiaSharp é representada por um objeto do tipo EllipseDrawingFigure :
class EllipseDrawingFigure
{
SKPoint pt1, pt2;

public EllipseDrawingFigure()
{
}

public SKColor Color { set; get; }

public SKPoint StartPoint


{
set
{
pt1 = value;
MakeRectangle();
}
}

public SKPoint EndPoint


{
set
{
pt2 = value;
MakeRectangle();
}
}

void MakeRectangle()
{
Rectangle = new SKRect(pt1.X, pt1.Y, pt2.X, pt2.Y).Standardized;
}

public SKRect Rectangle { set; get; }

// For dragging operations


public Point LastFingerLocation { set; get; }

// For the dragging hit-test


public bool IsInEllipse(SKPoint pt)
{
SKRect rect = Rectangle;

return (Math.Pow(pt.X - rect.MidX, 2) / Math.Pow(rect.Width / 2, 2) +


Math.Pow(pt.Y - rect.MidY, 2) / Math.Pow(rect.Height / 2, 2)) < 1;
}
}

As propriedades StartPoint e EndPoint são usadas quando o programa está processando a entrada por toque; a
propriedade Rectangle é usada para desenhar a elipse. A propriedade LastFingerLocation entra em jogo quando
a elipse está sendo arrastada e o método IsInEllipse ajuda no teste de clique. O método retorna true se o
ponto está dentro da elipse.
O arquivo code-behind mantém três coleções:

Dictionary<long, EllipseDrawingFigure> inProgressFigures = new Dictionary<long, EllipseDrawingFigure>();


List<EllipseDrawingFigure> completedFigures = new List<EllipseDrawingFigure>();
Dictionary<long, EllipseDrawingFigure> draggingFigures = new Dictionary<long, EllipseDrawingFigure>();

O dicionário draggingFigurecontém um subconjunto da coleção completedFigures . O manipulador de eventos


PaintSurface do SkiaSharp apenas renderiza os objetos nestas coleções completedFigures e inProgressFigures :
SKPaint paint = new SKPaint
{
Style = SKPaintStyle.Fill
};
...
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKCanvas canvas = args.Surface.Canvas;
canvas.Clear();

foreach (EllipseDrawingFigure figure in completedFigures)


{
paint.Color = figure.Color;
canvas.DrawOval(figure.Rectangle, paint);
}
foreach (EllipseDrawingFigure figure in inProgressFigures.Values)
{
paint.Color = figure.Color;
canvas.DrawOval(figure.Rectangle, paint);
}
}

A parte mais complicada do processamento de toque é a manipulação de Pressed . É nesse momento que o teste
de clique é executado, mas se o código detectar uma elipse sob o dedo do usuário, essa elipse só poderá ser
arrastada se não estiver sendo arrastada por outro dedo. Se não houver nenhuma elipse sob o dedo do usuário, o
código iniciará o processo de desenho de uma nova elipse:
case TouchActionType.Pressed:
bool isDragOperation = false;

// Loop through the completed figures


foreach (EllipseDrawingFigure fig in completedFigures.Reverse<EllipseDrawingFigure>())
{
// Check if the finger is touching one of the ellipses
if (fig.IsInEllipse(ConvertToPixel(args.Location)))
{
// Tentatively assume this is a dragging operation
isDragOperation = true;

// Loop through all the figures currently being dragged


foreach (EllipseDrawingFigure draggedFigure in draggingFigures.Values)
{
// If there's a match, we'll need to dig deeper
if (fig == draggedFigure)
{
isDragOperation = false;
break;
}
}

if (isDragOperation)
{
fig.LastFingerLocation = args.Location;
draggingFigures.Add(args.Id, fig);
break;
}
}
}

if (isDragOperation)
{
// Move the dragged ellipse to the end of completedFigures so it's drawn on top
EllipseDrawingFigure fig = draggingFigures[args.Id];
completedFigures.Remove(fig);
completedFigures.Add(fig);
}
else // start making a new ellipse
{
// Random bytes for random color
byte[] buffer = new byte[4];
random.NextBytes(buffer);

EllipseDrawingFigure figure = new EllipseDrawingFigure


{
Color = new SKColor(buffer[0], buffer[1], buffer[2], buffer[3]),
StartPoint = ConvertToPixel(args.Location),
EndPoint = ConvertToPixel(args.Location)
};
inProgressFigures.Add(args.Id, figure);
}
canvasView.InvalidateSurface();
break;

Outro exemplo do SkiaSharp é a página Pintura a dedo. Você pode selecionar uma cor e uma largura do traço
em duas exibições Picker e, em seguida, desenhar com um ou mais dedos:
Este exemplo também exige uma classe separada para representar cada linha pintada na tela:

class FingerPaintPolyline
{
public FingerPaintPolyline()
{
Path = new SKPath();
}

public SKPath Path { set; get; }

public Color StrokeColor { set; get; }

public float StrokeWidth { set; get; }


}

Um objeto SKPath é usado para renderizar cada linha. O arquivo FingerPaint.xaml.cs mantém duas coleções
desses objetos, uma para essas polilinhas desenhadas no momento e outra para as polilinhas concluídas:

Dictionary<long, FingerPaintPolyline> inProgressPolylines = new Dictionary<long, FingerPaintPolyline>();


List<FingerPaintPolyline> completedPolylines = new List<FingerPaintPolyline>();

O processamento de Pressed cria uma nova FingerPaintPolyline , chama MoveTo no objeto de caminho para
armazenar o ponto inicial e adiciona esse objeto ao dicionário inProgressPolylines . O processamento de Moved
chama LineTo no objeto de caminho com a nova posição do dedo e o processamento de Released transfere a
polilinha concluída de inProgressPolylines para completedPolylines . Mais uma vez, o código de desenho real do
SkiaSharp é relativamente simples:
SKPaint paint = new SKPaint
{
Style = SKPaintStyle.Stroke,
StrokeCap = SKStrokeCap.Round,
StrokeJoin = SKStrokeJoin.Round
};
...
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKCanvas canvas = args.Surface.Canvas;
canvas.Clear();

foreach (FingerPaintPolyline polyline in completedPolylines)


{
paint.Color = polyline.StrokeColor.ToSKColor();
paint.StrokeWidth = polyline.StrokeWidth;
canvas.DrawPath(polyline.Path, paint);
}

foreach (FingerPaintPolyline polyline in inProgressPolylines.Values)


{
paint.Color = polyline.StrokeColor.ToSKColor();
paint.StrokeWidth = polyline.StrokeWidth;
canvas.DrawPath(polyline.Path, paint);
}
}

Acompanhando o toque exibição para exibição


Todos os exemplos anteriores definiram a propriedade Capture do TouchEffect como true , quando o
TouchEffect foi criado ou quando o evento Pressed ocorreu. Isso garante que o mesmo elemento receba todos
os eventos associados ao dedo que pressionou a exibição primeiro. A amostra final não define Capture como
true . Isso causa um comportamento diferente quando um dedo em contato com a tela se move de um elemento
para outro. O elemento movido pelo dedo recebe um evento com uma propriedade Type definida como
TouchActionType.Exited e o segundo elemento recebe um evento com uma configuração Type igual a
TouchActionType.Entered .

Esse tipo de processamento de toque é muito útil para um teclado musical. Uma tecla deve conseguir detectar
quando ela é pressionada, mas também quando um dedo deslizar de uma tecla para outra.
A página Teclado silencioso define classes WhiteKey e BlackKey pequenas que derivam de Key , que, por sua
vez, deriva de BoxView .
A classe Key está pronta para ser usada em um programa real de música. Ela define as propriedades públicas
chamadas IsPressed e KeyNumber , que se destinam a ser definidas como o código de teclas estabelecido pelo
padrão MIDI. A classe Key também define um evento chamado StatusChanged , que é invocado quando a
propriedade IsPressed é alterada.
Vários dedos são permitidos em cada tecla. Por esse motivo, a classe Key mantém uma List dos números de ID
de toque dos dedos que estão tocando essa tecla:

List<long> ids = new List<long>();

O manipulador de eventos TouchAction adiciona uma ID à lista ids para um tipo de evento Pressed e um tipo
Entered , mas somente quando a propriedade IsInContact é true para o evento Entered . A ID é removida da
List para um evento Released ou Exited :
void OnTouchEffectAction(object sender, TouchActionEventArgs args)
{
switch (args.Type)
{
case TouchActionType.Pressed:
AddToList(args.Id);
break;

case TouchActionType.Entered:
if (args.IsInContact)
{
AddToList(args.Id);
}
break;

case TouchActionType.Moved:
break;

case TouchActionType.Released:
case TouchActionType.Exited:
RemoveFromList(args.Id);
break;
}
}

Os métodos AddToList e RemoveFromList verificam se a List foi alterada entre vazia e não vazia e, nesse caso,
invoca o evento StatusChanged .
Os vários elementos WhiteKey e BlackKey são organizados no arquivo XAML da página, que tem uma melhor
aparência quando o telefone é segurado em um modo paisagem:

Se você passar o dedo entre as teclas, pelas pequenas alterações nas cores, você verá que os eventos de toque são
transferidos de uma tecla para outra.

Resumo
Este artigo demonstrou como invocar eventos em um efeito e como gravar e usar um efeito que implementa o
processamento multitoque de nível baixo.

Links relacionados
Acompanhamento de dedo multitoque no iOS
Acompanhamento de dedo multitoque no Android
Efeito de acompanhamento de toque (amostra)
Manipulação de arquivos no Xamarin.Forms
12/04/2019 • 9 minutes to read • Edit Online

Baixar o exemplo
O tratamento de arquivos com o Xamarin.Forms pode ser alcançado usando código em uma biblioteca .NET
Standard ou usando recursos inseridos.

Visão geral
Código do Xamarin.Forms são executados em várias plataformas e cada uma delas tem seu próprio sistema de
arquivos. Anteriormente, isso significava que ler e gravar arquivos era realizado mais facilmente usando as APIs
de arquivo nativo em cada plataforma. Como alternativa, os recursos inseridos são uma solução mais simples para
distribuir os arquivos de dados com um aplicativo. No entanto, com o .NET Standard 2.0, é possível compartilhar o
código de acesso de arquivo nas bibliotecas .NET Standard.
Para saber mais sobre o tratamento de arquivos de imagem, confira a página Trabalhando com imagens.

Salvamento e carregamento de arquivos


As classes System.IO podem ser usadas para acessar o sistema de arquivos em cada plataforma. A classe File
permite criar, excluir e ler arquivos e a classe Directory permite criar, excluir ou enumerar o conteúdo de
diretórios. Também é possível usar as subclasses Stream , que podem fornecer um maior grau de controle sobre
operações de arquivo (como compactação ou pesquisa de posição em um arquivo).
Um arquivo de texto pode ser escrito usando o método File.WriteAllText :

File.WriteAllText(fileName, text);

Um arquivo de texto pode ser lido usando o método File.ReadAllText :

string text = File.ReadAllText(fileName);

Além disso, o método File.Exists determina se o arquivo especificado existe:

bool doesExist = File.Exists(fileName);

O caminho do arquivo em cada plataforma pode ser determinado com base em uma biblioteca .NET Standard
usando um valor da enumeração Environment.SpecialFolder como o primeiro argumento para o método
Environment.GetFolderPath . Isso pode ser combinado com um nome de arquivo com o método Path.Combine :

string fileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),


"temp.txt");

Essas operações são demonstradas no aplicativo de exemplo, que inclui uma página que salva e carrega texto:
Carregamento de arquivos inseridos como recursos
Para inserir um arquivo em um assembly do .NET Standard, crie ou adicione um arquivo e certifique-se de que
seja Ação de build: EmbeddedResource.
Visual Studio
Visual Studio para Mac

GetManifestResourceStream é usado para acessar o arquivo inserido usando sua ID de recurso. Por padrão, a ID
de recurso é o nome do arquivo com o prefixo do namespace padrão para o projeto no qual ele está inserido –
nesse caso, o assembly é WorkingWithFiles e o nome do arquivo é PCLTextResource.txt; portanto, a ID de
recurso é WorkingWithFiles.PCLTextResource.txt .

var assembly = IntrospectionExtensions.GetTypeInfo(typeof(LoadResourceText)).Assembly;


Stream stream = assembly.GetManifestResourceStream("WorkingWithFiles.PCLTextResource.txt");
string text = "";
using (var reader = new System.IO.StreamReader (stream)) {
text = reader.ReadToEnd ();
}

A variável text pode ser usada para exibir o texto ou, caso contrário, usá-lo no código. Esta captura de tela do
aplicativo de exemplo mostra o texto renderizado em um controle Label .
Carregar e desserializar um XML é igualmente simples. O código a seguir mostra um arquivo XML sendo
carregado e desserializado de um recurso, associado a um ListView para exibição. O arquivo XML contém uma
matriz de objetos Monkey (a classe é definida no código de exemplo).

var assembly = IntrospectionExtensions.GetTypeInfo(typeof(LoadResourceText)).Assembly;


Stream stream = assembly.GetManifestResourceStream("WorkingWithFiles.PCLXmlResource.xml");
List<Monkey> monkeys;
using (var reader = new System.IO.StreamReader (stream)) {
var serializer = new XmlSerializer(typeof(List<Monkey>));
monkeys = (List<Monkey>)serializer.Deserialize(reader);
}
var listView = new ListView ();
listView.ItemsSource = monkeys;

Inserção em projetos compartilhados


Projetos compartilhados também podem conter arquivos como recursos inseridos; no entanto, como o conteúdo
de um Projeto compartilhado é compilado em projetos de referência, o prefixo usado para IDs de recurso de
arquivo inserido pode ser alterado. Isso significa que a ID do recurso para cada arquivo inserido pode ser diferente
para cada plataforma.
Há duas soluções para esse problema com Projetos compartilhados:
Sincronizar os projetos – edite as propriedades do projeto para cada plataforma para usar o mesmo nome
de assembly e o namespace padrão. Esse valor pode ser embutido como o prefixo para IDs de recurso inserido
no Projeto compartilhado.
Diretivas de compilador #if – use diretivas de compilador para definir o prefixo correto de ID do recurso e
use esse valor para construir dinamicamente a ID do recurso correta.
Veja abaixo o código ilustrando a segunda opção. As diretivas de compilador são usadas para selecionar o prefixo
de recurso embutido (normalmente o mesmo que o namespace padrão para o projeto de referência). A variável
resourcePrefix é usada para criar uma ID de recurso válida, concatenando-a com o nome do arquivo de recurso
inserido.

#if __IOS__
var resourcePrefix = "WorkingWithFiles.iOS.";
#endif
#if __ANDROID__
var resourcePrefix = "WorkingWithFiles.Droid.";
#endif

Debug.WriteLine("Using this resource prefix: " + resourcePrefix);


// note that the prefix includes the trailing period '.' that is required
var assembly = IntrospectionExtensions.GetTypeInfo(typeof(SharedPage)).Assembly;
Stream stream = assembly.GetManifestResourceStream
(resourcePrefix + "SharedTextResource.txt");

Organização de recursos
Os exemplos acima supõem que o arquivo é inserido na raiz do projeto da biblioteca .NET Standard, em cujo caso
a ID de recurso é do formato Namespace.Filename.Extension, como WorkingWithFiles.PCLTextResource.txt e
WorkingWithFiles.iOS.SharedTextResource.txt .

É possível organizar os recursos inseridos em pastas. Quando um recurso inserido é colocado em uma pasta, o
nome da pasta se torna parte da ID de recurso (separado por pontos) para que o formato de ID de recurso se
torne Namespace.Folder.Filename.Extension. Colocar os arquivos usados no aplicativo de exemplo em uma
pasta MyFolder tornaria as IDs de recurso correspondentes WorkingWithFiles.MyFolder.PCLTextResource.txt e
WorkingWithFiles.iOS.MyFolder.SharedTextResource.txt .

Depuração de recursos inseridos


Como às vezes é difícil entender por que determinado recurso não está sendo carregado, o código de depuração a
seguir pode ser adicionado temporariamente a um aplicativo para ajudar a confirmar que os recursos foram
configurados corretamente. Ele transmitirá todos os recursos conhecidos inseridos no assembly fornecido para o
painel Erros para ajudar a depurar problemas de carregamento de recursos.

using System.Reflection;
// ...
// use for debugging, not in released app code!
var assembly = IntrospectionExtensions.GetTypeInfo(typeof(SharedPage)).Assembly;
foreach (var res in assembly.GetManifestResourceNames()) {
System.Diagnostics.Debug.WriteLine("found resource: " + res);
}

Resumo
Este artigo mostrou algumas operações de arquivo simples para salvar e carregar texto no dispositivo e para
carregar recursos inseridos. Com o .NET Standard 2.0, é possível compartilhar o código de acesso de arquivo nas
bibliotecas .NET Standard.

Links relacionados
FilesSample
Amostras do Xamarin.Forms
Trabalhando com o sistema de arquivos no Xamarin.iOS
Gestos do Xamarin.Forms
12/04/2019 • 2 minutes to read • Edit Online

Reconhecedores de gestos podem ser usados para detectar a interação do usuário com exibições em um aplicativo
Xamarin.Forms.
A classe GestureRecognizer do Xamarin.Forms dá suporte a gestos de toque, de pinçagem, de panorâmica e de
passar o dedo em instâncias de View .

Adicionando um reconhecedor de gestos de toque


Um gesto de toque é usado para detecção de toque e é reconhecido com a classe TapGestureRecognizer .

Adicionando um reconhecedor de gestos de pinçagem


Um gesto de pinçagem é usado para aplicar zoom interativo e é reconhecido com a classe PinchGestureRecognizer
.

Adicionando um reconhecedor de gestos de panorâmica


Um gesto de panorâmica é usado para detectar a movimentação dos dedos na tela e aplicar essa movimentação
ao conteúdo. Ele é reconhecido com a classe PanGestureRecognizer .

Adicionando um reconhecedor de gestos de passar o dedo


Um gesto de passar o dedo ocorre quando um dedo é movido pela tela na direção horizontal ou vertical e
geralmente é usado para iniciar a navegação pelo conteúdo. Gestos de passar o dedo são reconhecidos com a
classe SwipeGestureRecognizer .
Adicionando um reconhecedor de gestos de toque
12/04/2019 • 3 minutes to read • Edit Online

Baixar o exemplo
O gesto de toque é usado para detecção de toque e é implementado com a classe TapGestureRecognizer.
Para que seja possível clicar em um elemento da interface do usuário com um gesto de toque, crie uma instância
de TapGestureRecognizer , manipule o evento Tapped e adicione o novo reconhecedor de gestos à coleção
GestureRecognizers no elemento de interface do usuário. O exemplo de código a seguir mostra um
TapGestureRecognizer anexado a um elemento Image :

var tapGestureRecognizer = new TapGestureRecognizer();


tapGestureRecognizer.Tapped += (s, e) => {
// handle the tap
};
image.GestureRecognizers.Add(tapGestureRecognizer);

Por padrão, a imagem responderá a toques único. Configure a propriedade NumberOfTapsRequired para aguardar
um toque duplo (ou mais toques se necessário).

tapGestureRecognizer.NumberOfTapsRequired = 2; // double-tap

Quando NumberOfTapsRequired é configurado como mais de um, o manipulador de eventos é executado somente
quando os toques ocorrem em um período definido (esse período não é configurável). Se o segundo toque (ou os
toques posteriores) não ocorrerem dentro desse período, eles serão ignorados e a “contagem de toques” será
reiniciada.

Usando XAML
Um reconhecedor de gestos pode ser adicionado a um controle em XAML usando propriedades anexadas. A
sintaxe para adicionar um TapGestureRecognizer a uma imagem é mostrada abaixo (nesse caso, definindo um
evento de toque duplo):

<Image Source="tapped.jpg">
<Image.GestureRecognizers>
<TapGestureRecognizer
Tapped="OnTapGestureRecognizerTapped"
NumberOfTapsRequired="2" />
</Image.GestureRecognizers>
</Image>

O código para o manipulador de eventos (no exemplo) incrementa um contador e altera a imagem de colorida
para preto & branca.
void OnTapGestureRecognizerTapped(object sender, EventArgs args)
{
tapCount++;
var imageSender = (Image)sender;
// watch the monkey go from color to black&white!
if (tapCount % 2 == 0) {
imageSender.Source = "tapped.jpg";
} else {
imageSender.Source = "tapped_bw.jpg";
}
}

Usando ICommand
Aplicativos que usam o padrão MVVM (Model-View -ViewModel) normalmente usam ICommand em vez de
conectar manipuladores de eventos diretamente. O TapGestureRecognizer pode facilmente dar suporte a ICommand
definindo a associação no código:

var tapGestureRecognizer = new TapGestureRecognizer();


tapGestureRecognizer.SetBinding (TapGestureRecognizer.CommandProperty, "TapCommand");
image.GestureRecognizers.Add(tapGestureRecognizer);

ou usando XAML:

<Image Source="tapped.jpg">
<Image.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding TapCommand}"
CommandParameter="Image1" />
</Image.GestureRecognizers>
</Image>

O código completo para esse modelo de exibição pode ser encontrado na amostra. Os detalhes relevantes da
implementação de Command são mostrados abaixo:

public class TapViewModel : INotifyPropertyChanged


{
int taps = 0;
ICommand tapCommand;
public TapViewModel () {
// configure the TapCommand with a method
tapCommand = new Command (OnTapped);
}
public ICommand TapCommand {
get { return tapCommand; }
}
void OnTapped (object s) {
taps++;
Debug.WriteLine ("parameter: " + s);
}
//region INotifyPropertyChanged code omitted
}

Links relacionados
TapGesture (amostra)
GestureRecognizer
TapGestureRecognizer
Adicionando um reconhecedor de gestos de
pinçagem
12/04/2019 • 5 minutes to read • Edit Online

Baixar o exemplo
O gesto de pinçagem é usado para aplicar zoom de forma interativa e é implementado com a classe
PinchGestureRecognizer. Um cenário comum para o gesto de pinçagem é aplicar zoom de forma interativa a uma
imagem na localização da pinçagem. Isso é feito dimensionando o conteúdo do visor e é demonstrado neste
artigo.
Para que seja possível ampliar um elemento da interface do usuário com um gesto de pinçagem, crie uma
instância de PinchGestureRecognizer , manipule o evento PinchUpdated e adicione o novo reconhecedor de gestos à
coleção GestureRecognizers no elemento de interface do usuário. O exemplo de código a seguir mostra um
PinchGestureRecognizer anexado a um elemento Image :

var pinchGesture = new PinchGestureRecognizer();


pinchGesture.PinchUpdated += (s, e) => {
// Handle the pinch
};
image.GestureRecognizers.Add(pinchGesture);

Isso também pode ser feito em XAML, conforme mostrado no exemplo de código a seguir:

<Image Source="waterfront.jpg">
<Image.GestureRecognizers>
<PinchGestureRecognizer PinchUpdated="OnPinchUpdated" />
</Image.GestureRecognizers>
</Image>

O código para o manipulador de eventos OnPinchUpdated é adicionado ao arquivo code-behind:

void OnPinchUpdated (object sender, PinchGestureUpdatedEventArgs e)


{
// Handle the pinch
}

Criar um contêiner de PinchToZoom


Manipular o gesto de pinçagem para executar uma operação de aplicação de zoom requer alguns cálculos
matemáticos para transformar a interface do usuário. Esta seção contém uma classe auxiliar generalizada para
executar os cálculos, que pode ser usada para aplicar zoom interativamente a qualquer elemento da interface do
usuário. O exemplo de código a seguir mostra a classe PinchToZoomContainer :
public class PinchToZoomContainer : ContentView
{
...

public PinchToZoomContainer ()
{
var pinchGesture = new PinchGestureRecognizer ();
pinchGesture.PinchUpdated += OnPinchUpdated;
GestureRecognizers.Add (pinchGesture);
}

void OnPinchUpdated (object sender, PinchGestureUpdatedEventArgs e)


{
...
}
}

Essa classe pode ser encapsulada em torno de um elemento de interface do usuário para que o gesto de pinçagem
aplique zoom ao elemento de interface do usuário encapsulado. O exemplo de código XAML a seguir mostra o
PinchToZoomContainer encapsulando um elemento Image :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:PinchGesture;assembly=PinchGesture"
x:Class="PinchGesture.HomePage">
<ContentPage.Content>
<Grid Padding="20">
<local:PinchToZoomContainer>
<local:PinchToZoomContainer.Content>
<Image Source="waterfront.jpg" />
</local:PinchToZoomContainer.Content>
</local:PinchToZoomContainer>
</Grid>
</ContentPage.Content>
</ContentPage>

O exemplo de código a seguir mostra como o PinchToZoomContainer encapsula um elemento Image em uma
página de C#:

public class HomePageCS : ContentPage


{
public HomePageCS ()
{
Content = new Grid {
Padding = new Thickness (20),
Children = {
new PinchToZoomContainer {
Content = new Image { Source = ImageSource.FromFile ("waterfront.jpg") }
}
}
};
}
}

Quando o elemento Image receber um gesto de pinçagem, a imagem exibida será ampliada ou reduzida. A
aplicação de zoom é realizada pelo método PinchZoomContainer.OnPinchUpdated , que é mostrado no exemplo de
código a seguir:
void OnPinchUpdated (object sender, PinchGestureUpdatedEventArgs e)
{
if (e.Status == GestureStatus.Started) {
// Store the current scale factor applied to the wrapped user interface element,
// and zero the components for the center point of the translate transform.
startScale = Content.Scale;
Content.AnchorX = 0;
Content.AnchorY = 0;
}
if (e.Status == GestureStatus.Running) {
// Calculate the scale factor to be applied.
currentScale += (e.Scale - 1) * startScale;
currentScale = Math.Max (1, currentScale);

// The ScaleOrigin is in relative coordinates to the wrapped user interface element,


// so get the X pixel coordinate.
double renderedX = Content.X + xOffset;
double deltaX = renderedX / Width;
double deltaWidth = Width / (Content.Width * startScale);
double originX = (e.ScaleOrigin.X - deltaX) * deltaWidth;

// The ScaleOrigin is in relative coordinates to the wrapped user interface element,


// so get the Y pixel coordinate.
double renderedY = Content.Y + yOffset;
double deltaY = renderedY / Height;
double deltaHeight = Height / (Content.Height * startScale);
double originY = (e.ScaleOrigin.Y - deltaY) * deltaHeight;

// Calculate the transformed element pixel coordinates.


double targetX = xOffset - (originX * Content.Width) * (currentScale - startScale);
double targetY = yOffset - (originY * Content.Height) * (currentScale - startScale);

// Apply translation based on the change in origin.


Content.TranslationX = targetX.Clamp (-Content.Width * (currentScale - 1), 0);
Content.TranslationY = targetY.Clamp (-Content.Height * (currentScale - 1), 0);

// Apply scale factor.


Content.Scale = currentScale;
}
if (e.Status == GestureStatus.Completed) {
// Store the translation delta's of the wrapped user interface element.
xOffset = Content.TranslationX;
yOffset = Content.TranslationY;
}
}

Esse método atualiza o nível de aplicação de zoom do elemento da interface do usuário encapsulado, com base no
gesto de pinçagem do usuário. Isso é feito usando os valores das propriedades Scale , ScaleOrigin e Status da
instância de PinchGestureUpdatedEventArgs para calcular o fator de escala a ser aplicado na origem do gesto de
pinçagem. O elemento do usuário encapsulado, então, é ampliado na origem do gesto de pinçagem definindo suas
propriedades TranslationX , TranslationY e Scale como os valores calculados.

Links relacionados
PinchGesture (amostra)
GestureRecognizer
PinchGestureRecognizer
Adicionando um reconhecedor de gesto de
panorâmica
12/04/2019 • 6 minutes to read • Edit Online

Baixar o exemplo
O gesto de panorâmica é usado para detectar a movimentação dos dedos na tela e aplicar essa movimentação ao
conteúdo e é implementado com a classe PanGestureRecognizer . Um cenário comum para o gesto de panorâmica
é percorrer uma imagem horizontal e verticalmente, para que todo o conteúdo da imagem pode ser exibido
quando ela estiver sendo exibida em um visor menor do que as dimensões da imagem. Isso é feito movendo a
imagem dentro do visor e é demonstrado neste artigo.
Para que seja possível mover um elemento da interface do usuário com um gesto de panorâmica, crie uma
instância de PanGestureRecognizer , manipule o evento PanUpdated e adicione o novo reconhecedor de gestos à
coleção GestureRecognizers no elemento de interface do usuário. O exemplo de código a seguir mostra um
PanGestureRecognizer anexado a um elemento Image :

var panGesture = new PanGestureRecognizer();


panGesture.PanUpdated += (s, e) => {
// Handle the pan
};
image.GestureRecognizers.Add(panGesture);

Isso também pode ser feito em XAML, conforme mostrado no exemplo de código a seguir:

<Image Source="MonoMonkey.jpg">
<Image.GestureRecognizers>
<PanGestureRecognizer PanUpdated="OnPanUpdated" />
</Image.GestureRecognizers>
</Image>

O código para o manipulador de eventos OnPanUpdated é adicionado ao arquivo code-behind:

void OnPanUpdated (object sender, PanUpdatedEventArgs e)


{
// Handle the pan
}

NOTE
Para usar a panorâmica corretamente no Android, é necessário ter no mínimo o Pacote NuGet 2.1.0-pre1 do Xamarin.Forms.

Criando um contêiner de panorâmica


Esta seção contém uma classe auxiliar generalizada que executa a panorâmica de forma livre, o que normalmente é
adequado para navegar em imagens ou mapas. Manipular o gesto de panorâmica para executar esta operação
requer alguns cálculos matemáticos para transformar a interface do usuário. Esses cálculos são usados para
percorrer apenas os limites do elemento de interface do usuário encapsulado. O exemplo de código a seguir
mostra a classe PanContainer :
public class PanContainer : ContentView
{
double x, y;

public PanContainer ()
{
// Set PanGestureRecognizer.TouchPoints to control the
// number of touch points needed to pan
var panGesture = new PanGestureRecognizer ();
panGesture.PanUpdated += OnPanUpdated;
GestureRecognizers.Add (panGesture);
}

void OnPanUpdated (object sender, PanUpdatedEventArgs e)


{
...
}
}

Essa classe pode ser encapsulada em torno de um elemento de interface do usuário para que o gesto percorra o
elemento de interface do usuário encapsulado. O exemplo de código XAML a seguir mostra o PanContainer
encapsulando um elemento Image :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:PanGesture"
x:Class="PanGesture.HomePage">
<ContentPage.Content>
<AbsoluteLayout>
<local:PanContainer>
<Image Source="MonoMonkey.jpg" WidthRequest="1024" HeightRequest="768" />
</local:PanContainer>
</AbsoluteLayout>
</ContentPage.Content>
</ContentPage>

O exemplo de código a seguir mostra como o PanContainer encapsula um elemento Image em uma página de
C#:

public class HomePageCS : ContentPage


{
public HomePageCS ()
{
Content = new AbsoluteLayout {
Padding = new Thickness (20),
Children = {
new PanContainer {
Content = new Image {
Source = ImageSource.FromFile ("MonoMonkey.jpg"),
WidthRequest = 1024,
HeightRequest = 768
}
}
}
};
}
}

Nos dois exemplos, as propriedades WidthRequest e HeightRequest são definidas como os valores de largura e
altura da imagem que está sendo exibida.
Quando o elemento Image receber um gesto de panorâmica, a imagem exibida será deslocada. A panorâmica é
realizada pelo método PanContainer.OnPanUpdated , que é mostrado no exemplo de código a seguir:

void OnPanUpdated (object sender, PanUpdatedEventArgs e)


{
switch (e.StatusType) {
case GestureStatus.Running:
// Translate and ensure we don't pan beyond the wrapped user interface element bounds.
Content.TranslationX =
Math.Max (Math.Min (0, x + e.TotalX), -Math.Abs (Content.Width - App.ScreenWidth));
Content.TranslationY =
Math.Max (Math.Min (0, y + e.TotalY), -Math.Abs (Content.Height - App.ScreenHeight));
break;

case GestureStatus.Completed:
// Store the translation applied during the pan
x = Content.TranslationX;
y = Content.TranslationY;
break;
}
}

Esse método atualiza o conteúdo visível do elemento de interface do usuário encapsulado, com base no gesto de
panorâmica do usuário. Isso é feito usando os valores das propriedades TotalX e TotalY da instância de
PanUpdatedEventArgs para calcular a direção e a distância da panorâmica. As propriedades App.ScreenWidth e
App.ScreenHeight fornecem a altura e largura do visor e são definidas com os valores da largura e da altura da tela
do dispositivo pelos respectivos projetos específicos da plataforma. O elemento de usuário encapsulado, então, é
percorrido definindo suas propriedades TranslationX e TranslationY como os valores calculados.
Quando o movimento panorâmico no conteúdo de um elemento que não ocupa a tela inteira, a altura e a largura
do visor podem ser obtidas das propriedades Height e Width do elemento.

NOTE
Exibir imagens de alta resolução pode aumentar significativamente o volume de memória de um aplicativo. Portanto, elas só
devem ser criadas quando necessário e devem ser liberadas assim que o aplicativo não precisar mais delas. Para saber mais,
consulte Otimizar recursos de imagem.

Links relacionados
PanGesture (amostra)
GestureRecognizer
PanGestureRecognizer
Adicionando um reconhecedor de gesto de passar o
dedo
12/04/2019 • 9 minutes to read • Edit Online

Baixar o exemplo
Um gesto de passar o dedo ocorre quando um dedo é movido pela tela na direção horizontal ou vertical e
geralmente é usado para iniciar a navegação pelo conteúdo. Os exemplos de código neste artigo são provenientes
do exemplo Gesto de passar o dedo.
Para fazer com que um View reconheça um gesto de passar o dedo, crie uma instância de SwipeGestureRecognizer
, defina a propriedade Direction como um valor de enumeração SwipeDirection ( Left , Right , Up ou Down ),
opcionalmente, defina a propriedade Threshold , manipule o evento Swiped e adicione o novo reconhecedor de
gestos à coleção GestureRecognizers na exibição. O exemplo de código a seguir mostra um
SwipeGestureRecognizer anexado a um BoxView :

<BoxView Color="Teal" ...>


<BoxView.GestureRecognizers>
<SwipeGestureRecognizer Direction="Left" Swiped="OnSwiped"/>
</BoxView.GestureRecognizers>
</BoxView>

Este é o código C# equivalente:

var boxView = new BoxView { Color = Color.Teal, ... };


var leftSwipeGesture = new SwipeGestureRecognizer { Direction = SwipeDirection.Left };
leftSwipeGesture.Swiped += OnSwiped;

boxView.GestureRecognizers.Add(leftSwipeGesture);

A classe SwipeGestureRecognizer também inclui uma propriedade Threshold que pode, opcionalmente, ser
definida como um valor de uint que representa a distância mínima que gesto deve percorrer para ser
reconhecido, em unidades independentes do dispositivo. O valor padrão dessa propriedade é 100, o que significa
que qualquer gesto de passar o dedo com menos de 100 unidades independentes do dispositivo será ignorado.

Reconhecendo a direção do gesto de passar o dedo


Nos exemplos acima, a propriedade Direction é definida como um valor único da enumeração SwipeDirection .
No entanto, também é possível definir essa propriedade como vários valores da enumeração SwipeDirection , para
que o evento Swiped seja acionado em resposta a um gesto de passar o dedo em mais de uma direção. No
entanto, a restrição é que um SwipeGestureRecognizer único só é capaz de reconhecer gestos que ocorrem no
mesmo eixo. Portanto, gestos que ocorrem no eixo horizontal podem ser reconhecidos definindo a propriedade
Direction como Left e Right :

<SwipeGestureRecognizer Direction="Left,Right" Swiped="OnSwiped"/>

De forma semelhante, gestos que ocorrem no eixo vertical podem ser reconhecidos definindo a propriedade
Direction como Up e Down :
var swipeGesture = new SwipeGestureRecognizer { Direction = SwipeDirection.Up | SwipeDirection.Down };

Como alternativa, é possível criar um SwipeGestureRecognizer para o gesto de passar o dedo em cada direção a fim
de reconhecer o gesto em todas as direções:

<BoxView Color="Teal" ...>


<BoxView.GestureRecognizers>
<SwipeGestureRecognizer Direction="Left" Swiped="OnSwiped"/>
<SwipeGestureRecognizer Direction="Right" Swiped="OnSwiped"/>
<SwipeGestureRecognizer Direction="Up" Swiped="OnSwiped"/>
<SwipeGestureRecognizer Direction="Down" Swiped="OnSwiped"/>
</BoxView.GestureRecognizers>
</BoxView>

Este é o código C# equivalente:

var boxView = new BoxView { Color = Color.Teal, ... };


var leftSwipeGesture = new SwipeGestureRecognizer { Direction = SwipeDirection.Left };
leftSwipeGesture.Swiped += OnSwiped;
var rightSwipeGesture = new SwipeGestureRecognizer { Direction = SwipeDirection.Right };
rightSwipeGesture.Swiped += OnSwiped;
var upSwipeGesture = new SwipeGestureRecognizer { Direction = SwipeDirection.Up };
upSwipeGesture.Swiped += OnSwiped;
var downSwipeGesture = new SwipeGestureRecognizer { Direction = SwipeDirection.Down };
downSwipeGesture.Swiped += OnSwiped;

boxView.GestureRecognizers.Add(leftSwipeGesture);
boxView.GestureRecognizers.Add(rightSwipeGesture);
boxView.GestureRecognizers.Add(upSwipeGesture);
boxView.GestureRecognizers.Add(downSwipeGesture);

NOTE
Nos exemplos acima, o mesmo manipulador de eventos responde ao acionamento do evento Swiped . No entanto, cada
instância de SwipeGestureRecognizer pode usar um manipulador de eventos diferente se necessário.

Respondendo ao gesto de passar o dedo


Um manipulador de eventos para o evento Swiped é mostrado no código a seguir:
void OnSwiped(object sender, SwipedEventArgs e)
{
switch (e.Direction)
{
case SwipeDirection.Left:
// Handle the swipe
break;
case SwipeDirection.Right:
// Handle the swipe
break;
case SwipeDirection.Up:
// Handle the swipe
break;
case SwipeDirection.Down:
// Handle the swipe
break;
}
}

O SwipedEventArgs pode ser examinado para determinar a direção do gesto de passar o dedo, com a lógica
personalizada respondendo ao gesto conforme necessário. A direção do gesto de passar o dedo pode ser obtida da
propriedade Direction dos argumentos do evento, que será definida como um dos valores da enumeração
SwipeDirection . Além disso, os argumentos do evento também têm uma propriedade Parameter que será
definida com o valor da propriedade CommandParameter , se definida.

Usando comandos
A classe SwipeGestureRecognizer também inclui propriedades Command e CommandParameter . Essas propriedades
geralmente são usadas em aplicativos que usam o padrão MVVM (Model-View -ViewModel). A propriedade
Command define o ICommand a ser invocado quando um gesto de passar o dedo for reconhecido, com a
propriedade CommandParameter definindo um objeto a ser passado para o ICommand. . O exemplo de código a
seguir mostra como associar a propriedade Command a um ICommand definido no modelo de exibição cuja instância
é definida como a página BindingContext :

var boxView = new BoxView { Color = Color.Teal, ... };


var leftSwipeGesture = new SwipeGestureRecognizer { Direction = SwipeDirection.Left, CommandParameter = "Left"
};
leftSwipeGesture.SetBinding(SwipeGestureRecognizer.CommandProperty, "SwipeCommand");
boxView.GestureRecognizers.Add(leftSwipeGesture);

O código XAML equivalente é:

<BoxView Color="Teal" ...>


<BoxView.GestureRecognizers>
<SwipeGestureRecognizer Direction="Left" Command="{Binding SwipeCommand}" CommandParameter="Left" />
</BoxView.GestureRecognizers>
</BoxView>

SwipeCommand é uma propriedade do tipo ICommand definida na instância do modelo de exibição que é definida
como o BindingContext da página. Quando um gesto de passar o dedo é reconhecido, o método Execute do
objeto SwipeCommand é executado. O argumento para o método Execute assume o valor da propriedade
CommandParameter . Para obter mais informações sobre comandos, confira A Interface de Comando.

Criando um contêiner para o gesto de passar o dedo


A classe SwipeContainer , que é mostrada no exemplo de código a seguir, é uma classe de reconhecimento
generalizado do gesto de passar o dedo, que é encapsulada em torno de um View para reconhecer o gesto:

public class SwipeContainer : ContentView


{
public event EventHandler<SwipedEventArgs> Swipe;

public SwipeContainer()
{
GestureRecognizers.Add(GetSwipeGestureRecognizer(SwipeDirection.Left));
GestureRecognizers.Add(GetSwipeGestureRecognizer(SwipeDirection.Right));
GestureRecognizers.Add(GetSwipeGestureRecognizer(SwipeDirection.Up));
GestureRecognizers.Add(GetSwipeGestureRecognizer(SwipeDirection.Down));
}

SwipeGestureRecognizer GetSwipeGestureRecognizer(SwipeDirection direction)


{
var swipe = new SwipeGestureRecognizer { Direction = direction };
swipe.Swiped += (sender, e) => Swipe?.Invoke(this, e);
return swipe;
}
}

A classe SwipeContainer cria objetos SwipeGestureRecognizer para os quatro sentidos do gesto de passar o dedo e
anexa manipuladores de eventos Swipe . Esses manipuladores de eventos invocam o evento Swipe definido pelo
SwipeContainer .

O exemplo de código XAML a seguir mostra a classe SwipeContainer encapsulando um BoxView :

<ContentPage ...>
<StackLayout>
<local:SwipeContainer Swipe="OnSwiped" ...>
<BoxView Color="Teal" ... />
</local:SwipeContainer>
</StackLayout>
</ContentPage>

O exemplo de código a seguir mostra como o SwipeContainer encapsula um BoxView em uma página de C#:

public class SwipeContainerPageCS : ContentPage


{
public SwipeContainerPageCS()
{
var boxView = new BoxView { Color = Color.Teal, ... };
var swipeContainer = new SwipeContainer { Content = boxView, ... };
swipeContainer.Swipe += (sender, e) =>
{
// Handle the swipe
};

Content = new StackLayout


{
Children = { swipeContainer }
};
}
}

Quando o BoxView recebe um gesto de passar o dedo, o evento Swiped no SwipeGestureRecognizer é acionado.
Isso é manipulado pela classe SwipeContainer , que aciona seu próprio evento Swipe . Esse evento Swipe é
manipulado na página. O SwipedEventArgs pode, então, ser examinado para determinar a direção do gesto de
passar o dedo, com a lógica personalizada respondendo ao gesto conforme necessário.
Links relacionados
Gesto de passar o dedo (amostra)
GestureRecognizer
SwipeGestureRecognizer
Localização do Xamarin.Forms
12/04/2019 • 2 minutes to read • Edit Online

A estrutura de localização interna do .NET pode ser usada para criar aplicativos multilíngues multiplataforma
com o Xamarin.Forms.

Localização de cadeia de caracteres e imagem


O mecanismo interno para localização de usos de aplicativos .NET arquivos RESX e as classes nos namespaces
System.Resources e System.Globalization . Arquivos RESX que contêm cadeias de caracteres traduzidas são
inseridos no assembly do Xamarin.Forms, junto com uma classe gerada pelo compilador que fornece acesso
fortemente tipado para as traduções. O texto traduzido pode ser então recuperado no código.

Localização da direita para esquerda


A direção do fluxo é a direção na qual os elementos de interface do usuário na página são detectados pelos olhos.
A localização da direita para esquerda adiciona suporte para a direção do fluxo da direita para esquerda para
aplicativos Xamarin.Forms.
Localização
12/04/2019 • 44 minutes to read • Edit Online

Baixar o exemplo
Aplicativos do Xamarin.Forms podem ser localizados usando arquivos de recursos do .NET.

Visão geral
O mecanismo interno para localização de usos de aplicativos .NET arquivos RESX e as classes nos namespaces
System.Resources e System.Globalization . Arquivos RESX que contêm cadeias de caracteres traduzidas são
inseridos no assembly do Xamarin.Forms, junto com uma classe gerada pelo compilador que fornece acesso
fortemente tipado para as traduções. O texto traduzido pode ser então recuperado no código.
Código de exemplo
Há dois exemplos associados a este documento:
UsingResxLocalization é uma demonstração muito simples dos conceitos explicados. Todos os trechos de
código mostrados abaixo são provenientes deste exemplo.
TodoLocalized é um aplicativo de trabalho básico que usa essas técnicas de localização.
Não é recomendado o uso de Projetos compartilhados
O exemplo TodoLocalized inclui uma Demonstração de Projeto compartilhado. No entanto, devido a limitações do
sistema de build, os arquivos de recurso não geram um arquivo .designer.cs, o que impossibilita o acesso a
cadeias de caracteres traduzidas fortemente tipadas no código.
O restante deste documento aborda projetos que usam o modelo de biblioteca .NET Standard do Xamarin.Forms.

Globalizando o código do Xamarin.Forms


Globalizar um aplicativo é o processo de deixá-lo "pronto para o mundo". Isso significa escrever um código que
seja capaz de exibir idiomas diferentes.
Uma dos principais aspectos de globalizar um aplicativo é compilar a interface do usuário de forma que não haja
nenhum texto embutido em código. Em vez disso, tudo o que é exibido para o usuário deve ser recuperado de um
conjunto de cadeias de caracteres que foram traduzidas para o idioma escolhido.
Neste documento, examinaremos como usar arquivos RESX para armazenar essas cadeias de caracteres e
recuperá-las para exibição, dependendo da preferência do usuário.
Os exemplos têm como alvo os idiomas inglês, francês, espanhol, alemão, chinês, japonês, russo e português
brasileiro. É possível traduzir os aplicativos para tantos idiomas quantos forem necessários.

NOTE
Na Plataforma Universal do Windows, é necessário usado arquivos RESW para localização de notificações por push, em vez de
arquivos RESX. Para obter mais informações, confira Localização da UWP.

Adicionando recursos
A primeira etapa da globalização de um aplicativo de biblioteca .NET Standard do Xamarin.Forms é adicionar os
arquivos de recursos RESX que serão usados para armazenar todo o texto usado no aplicativo. Precisamos
adicionar um arquivo RESX que contém o texto padrão e, em seguida, adicionar arquivos RESX adicionais para
cada idioma a que desejamos dar suporte.
Recurso de idioma base
O arquivo de recursos base (RESX) contém as cadeias de caracteres de idioma padrão (os exemplos pressupõem o
que inglês seja o idioma padrão). Adicione o arquivo ao projeto de código comum do Xamarin.Forms clicando com
o botão direito do mouse no projeto e escolhendo Adicionar > Novo Arquivo....
Escolha um nome significativo, como AppResources, e pressione OK.

Dois arquivos serão adicionados ao projeto:


Arquivo AppResources.resx em que as cadeias de caracteres traduzíveis são armazenadas no formato XML.
Arquivo AppResources.designer.cs, que declara uma classe parcial que contém referências a todos os
elementos criados no arquivo XML RESX.
A árvore de solução mostrará que os arquivos são relacionados. O arquivo RESX deve ser editado para adicionar
novas cadeias de caracteres traduzíveis; o arquivo .designer.cs não deve ser editado.

Vi si b i l i d a d e d a c a d e i a d e c a r a c t e r e s

Por padrão, quando são geradas referências fortemente tipadas a cadeias de caracteres, elas são o internal para
o assembly. Isso ocorre porque a ferramenta de build padrão para arquivos RESX gera o arquivo .designer.cs com
propriedades internal .
Selecione o arquivo AppResources.resx e mostre o painel Propriedades para ver onde a ferramenta de build
está configurada. A captura de tela abaixo mostra a Ferramenta Personalizada: ResXFileCodeGenerator.
Visual Studio
Visual Studio para Mac

Para tornar as propriedades public da cadeia de caracteres fortemente tipadas, você deve alterar manualmente a
configuração da Ferramenta Personalizada: PublicResXFileCodeGenerator, como mostrado na captura de
tela abaixo:
Visual Studio
Visual Studio para Mac

Essa alteração é opcional e só é necessária se você deseja fazer referência a cadeias de caracteres localizadas em
assemblies diferentes (por exemplo, se você colocar os arquivos RESX em um assembly diferente de seu código).
O exemplo deste tópico deixa as cadeias de caracteres internal porque elas são definidas no mesmo assembly de
biblioteca .NET Standard do Xamarin.Forms em que são usadas.
Você só precisa definir a ferramenta personalizada no arquivo RESX base, conforme mostrado acima. Não é
necessário definir nenhuma ferramenta de build nos arquivos RESX específicos a um idioma discutidos nas seções
a seguir.
Ed i t a n d o o a r q u i v o R E SX

Infelizmente, não há um editor de RESX interno no Visual Studio para Mac. Adicionar novas cadeias de caracteres
traduzíveis requer a adição de um novo elemento data XML para cada cadeia de caracteres. Cada elemento data
pode conter os seguintes elementos:
O atributo name (obrigatório) é a chave para essa cadeia de caracteres traduzível. Ele deve ser um nome de
propriedade C# válido, de modo que não são permitidos espaços nem caracteres especiais.
Elemento value (obrigatório), que é a cadeia de caracteres que de fato é exibida no aplicativo.
O elemento comment (opcional) pode conter instruções para o tradutor explicando como a cadeia de caracteres
é usada.
O atributo xml:space (opcional), para controlar como o espaçamento na cadeia de caracteres é preservado.

Alguns exemplos de elementos data são mostrados aqui:

<data name="NotesLabel" xml:space="preserve">


<value>Notes:</value>
<comment>label for input field</comment>
</data>
<data name="NotesPlaceholder" xml:space="preserve">
<value>eg. buy milk</value>
<comment>example input for notes field</comment>
</data>
<data name="AddButton" xml:space="preserve">
<value>Add new item</value>
</data>

Conforme o aplicativo é escrito, cada parte do texto exibido para o usuário deve ser adicionada ao arquivo de
recursos RESX base em um novo elemento data . É recomendável que você inclua tantos comment s quanto
possível para garantir uma tradução de alta qualidade.
NOTE
O Visual Studio (incluindo a edição Community gratuita) contém um editor do RESX básico. Se você tem acesso a um
computador com Windows, essa pode ser uma maneira conveniente de adicionar e editar cadeias de caracteres em arquivos
RESX.

Recursos específicos a um idioma


Normalmente, a tradução de fato das cadeias de caracteres de texto padrão não acontecerá até que grandes partes
do aplicativo tenham sido escritas (neste caso, o arquivo RESX padrão conterá várias cadeias de caracteres). Ainda
é uma boa ideia adicionar os recursos específicos a um idioma no início do ciclo de desenvolvimento, sendo
possível também preencher com texto traduzido de maneira automática para ajudar a testar o código de
localização.
Um arquivo RESX adicional é adicionado para cada idioma a que desejamos dar suporte. Arquivos de recurso
específico a um idioma devem seguir uma convenção de nomenclatura específica: usar o mesmo nome de arquivo
que o arquivo de recurso (por exemplo, AppResources) seguido por um ponto (.) e, em seguida, o código de
idioma. Veja alguns exemplos simples:
AppResources.fr.resx – traduções para o idioma francês.
AppResources.es.resx – traduções para o idioma espanhol.
AppResources.de.resx – traduções para o idioma alemão.
AppResources.ja.resx – traduções para o idioma japonês.
AppResources.zh-Hans.resx – traduções para o idioma chinês (simplificado).
AppResources.zh-Hant.resx – traduções para o idioma chinês (tradicional).
AppResources.pt.resx – traduções para o idioma português.
AppResources.pt-BR.resx – traduções para o idioma português brasileiro.
O padrão geral é usar códigos de idioma com duas letras, mas há alguns exemplos (como chinês) em que um
formato diferente é usado, bem como outros exemplos (por exemplo, português brasileiro) em que um
identificador de localidade de quatro caracteres é necessário.
Estes arquivos de recursos específicos a um idioma não exigem uma classe parcial .designer.cs para que possam
ser adicionados como arquivos XML regulares, com Compilar Ação: EmbeddedResource definido. Esta captura
de tela mostra uma solução que contém os arquivos de recursos específicos a um idioma:

Conforme o aplicativo é desenvolvido e o texto é adicionado ao arquivo RESX base, você deve enviá-lo para os
tradutores, que traduzirão cada elemento data e retornarão um arquivo de recurso específico a um idioma
(usando a convenção de nomenclatura mostrada) para ser incluído no aplicativo. Alguns exemplos 'traduzidos de
maneira automática' são mostrados abaixo:
AppResources.es.resx (espanhol)
<data name="AddButton" xml:space="preserve">
<value>Escribir un artículo</value>
<comment>this string appears on a button to add a new item to the list</comment>
</data>

AppResources.ja.resx ( japonês)

<data name="AddButton" xml:space="preserve">


<value>新しい項目を追加</value>
<comment>this string appears on a button to add a new item to the list</comment>
</data>

AppResources.pt-BR.resx (português brasileiro)

<data name="AddButton" xml:space="preserve">


<value>adicionar novo item</value>
<comment>this string appears on a button to add a new item to the list</comment>
</data>

Somente o elemento value precisa ser atualizado pelo tradutor – o comment não se destina a ser traduzido.
Lembre-se: ao editar arquivos XML, faça o escape de caracteres reservados como < , > , & com &lt; , &gt; e
&amp; se eles aparecerem no value ou comment .

Usando recursos no código


Cadeias de caracteres em arquivos de recursos RESX estarão disponíveis para uso no código da interface do
usuário usando a classe AppResources . O name atribuído a cada cadeia de caracteres no arquivo RESX se torna
uma propriedade na classe, o que pode ser referenciado no código do Xamarin.Forms da seguinte forma:

var myLabel = new Label ();


var myEntry = new Entry ();
var myButton = new Button ();
// populate UI with translated text values from resources
myLabel.Text = AppResources.NotesLabel;
myEntry.Placeholder = AppResources.NotesPlaceholder;
myButton.Text = AppResources.AddButton;

A interface do usuário no iOS, no Android e na UWP (Plataforma Universal do Windows) é renderizada da forma
esperada, mas agora é possível traduzir o aplicativo para vários idiomas, porque o texto está sendo carregado de
um recurso em vez de ser embutido em código. Veja uma captura de tela que mostra a interface do usuário em
cada plataforma antes da tradução:

Solução de problemas
Testando um idioma específico
Pode ser complicado passar o simulador ou um dispositivo para idiomas diferentes, especialmente durante o
desenvolvimento, quando você deseja testar rapidamente diferentes culturas.
É possível forçar o carregamento de um idioma específico definindo o Culture , conforme mostrado neste snippet
de código:

// force a specific culture, useful for quick testing


AppResources.Culture = new CultureInfo("fr-FR");

Essa abordagem – configurar a cultura diretamente na classe AppResources – também pode ser usada para
implementar um seletor de idioma dentro de seu aplicativo (em vez de usar a localidade do dispositivo).
Carregando recursos inseridos
O snippet de código a seguir é útil ao tentar depurar problemas com os recursos inseridos (como arquivos RESX).
Adicione este código ao seu aplicativo (no início do ciclo de vida do aplicativo) e ele listará todos os recursos
inseridos no assembly, mostrando o identificador de recurso completo:

using System.Reflection;
// ...
// NOTE: use for debugging, not in released app code!
var assembly = typeof(EmbeddedImages).GetTypeInfo().Assembly; // "EmbeddedImages" should be a class in your
app
foreach (var res in assembly.GetManifestResourceNames())
{
System.Diagnostics.Debug.WriteLine("found resource: " + res);
}

No arquivo AppResources.Designer.cs(próximo da linha 33), o nome completo do gerenciador de recursos é


especificado (por exemplo, "UsingResxLocalization.Resx.AppResources" ), semelhante ao código a seguir:

System.Resources.ResourceManager temp =
new System.Resources.ResourceManager(
"UsingResxLocalization.Resx.AppResources",
typeof(AppResources).GetTypeInfo().Assembly);

Verifique na Saída do Aplicativo os resultados do código de depuração mostrado acima para confirmar se os
recursos corretos estão listados (por exemplo, "UsingResxLocalization.Resx.AppResources" ).
Se não estiverem, a classe AppResources não poderá carregar seus recursos. Verifique o seguinte para resolver
problemas em que os recursos não podem ser encontrados:
O namespace padrão do projeto corresponde ao namespace raiz no arquivo AppResources.Designer.cs.
Se o arquivo AppResources.resx estiver localizado em um subdiretório, o nome do subdiretório deverá fazer
parte do namespace e do identificador do recurso.
O arquivo AppResources.resx tem Compilar Ação: EmbeddedResource.
A configuração Opções do Projeto > Código-fonte > Políticas de Nomenclatura do .NET > Usar nomes
de recursos com estilo do Visual Studio está marcada. Você pode desmarcar essa opção se preferir, mas os
namespaces usados ao fazer referência a seus recursos RESX precisarão ser atualizados em todo o aplicativo.
Não funciona no modo de depuração (somente Android)
Se as cadeias de caracteres traduzidas estiverem funcionando em seus builds de VERSÃO do Android, mas não
durante a depuração, clique com o botão direito do mouse em Projeto do Android e selecione Opções > Build
> Build do Android e certifique-se de que Implantação de Assembly Rápida NÃO esteja marcado. Essa opção
causa problemas ao carregar recursos e não deverá ser usada se você estiver testando aplicativos localizados.
Exibindo o idioma correto
Até agora, examinamos como escrever código para que as traduções possam ser fornecidas, mas não como
realmente fazê-las aparecer. O código do Xamarin.Forms pode tirar proveito de recursos do .NET para carregar as
traduções no idioma correto, mas é necessário consultar o sistema operacional de cada plataforma para
determinar qual idioma foi selecionado pelo usuário.
Como são necessários alguns códigos específicos da plataforma para obter a preferência de idioma do usuário, use
um serviço de dependência para expor essas informações no aplicativo do Xamarin.Forms e implementá-las para
cada plataforma.
Primeiro, defina uma interface para expor a cultura preferencial do usuário, semelhante ao código a seguir:

public interface ILocalize


{
CultureInfo GetCurrentCultureInfo ();
void SetLocale (CultureInfo ci);
}

Depois, use o DependencyService na classe App do Xamarin.Forms para chamar a interface e definir nossa cultura
de recursos RESX com o valor correto. Observe que não precisamos definir manualmente esse valor para a
Plataforma Universal do Windows, pois a estrutura de recursos reconhece automaticamente o idioma selecionado
nessas plataformas.

if (Device.RuntimePlatform == Device.iOS || Device.RuntimePlatform == Device.Android)


{
var ci = DependencyService.Get<ILocalize>().GetCurrentCultureInfo();
Resx.AppResources.Culture = ci; // set the RESX for resource localization
DependencyService.Get<ILocalize>().SetLocale(ci); // set the Thread for locale-aware methods
}

O recurso Culture precisa ser definido quando o aplicativo é carregado pela primeira vez para que as cadeias de
caracteres no idioma correto sejam usadas. Você pode, opcionalmente, atualizar esse valor de acordo com eventos
específicos da plataforma que podem ser acionados no iOS ou no Android se o usuário atualizar suas preferências
de idioma enquanto o aplicativo está em execução.
As implementações para a interface ILocalize são mostradas na seção Código específico da plataforma abaixo.
Essas implementações tiram proveito dessa classe auxiliar PlatformCulture :
public class PlatformCulture
{
public PlatformCulture (string platformCultureString)
{
if (String.IsNullOrEmpty(platformCultureString))
{
throw new ArgumentException("Expected culture identifier", "platformCultureString"); // in C# 6
use nameof(platformCultureString)
}
PlatformString = platformCultureString.Replace("_", "-"); // .NET expects dash, not underscore
var dashIndex = PlatformString.IndexOf("-", StringComparison.Ordinal);
if (dashIndex > 0)
{
var parts = PlatformString.Split('-');
LanguageCode = parts[0];
LocaleCode = parts[1];
}
else
{
LanguageCode = PlatformString;
LocaleCode = "";
}
}
public string PlatformString { get; private set; }
public string LanguageCode { get; private set; }
public string LocaleCode { get; private set; }
public override string ToString()
{
return PlatformString;
}
}

Código específico da plataforma


O código para detectar o idioma a ser exibido deve ser específico da plataforma, pois o iOS, o Android e a UWP
expõem essas informações de maneiras ligeiramente diferentes. O código do serviço de dependência ILocalize é
fornecido abaixo para cada plataforma, junto com requisitos adicionais específicos da plataforma para garantir que
o texto localizado seja renderizado corretamente.
O código específico da plataforma também deve lidar com casos em que o sistema operacional permite que o
usuário configure um identificador de localidade que não tem suporte da classe CultureInfo do .NET. Nesses
casos, é necessário escrever um código personalizado para detectar localidades sem suporte e substituir o melhor
localidade compatível com o .NET.
Projeto de Aplicativo iOS
Os usuários do iOS selecionam seu idioma preferencial separadamente da cultura de formatação de data e hora.
Para carregar os recursos corretos para localizar um aplicativo Xamarin.Forms, precisamos apenas consultar a
matriz NSLocale.PreferredLanguages para o primeiro elemento.
A seguinte implementação do serviço de dependência ILocalize deve ser colocada no projeto do aplicativo iOS.
Como o iOS usa sublinhados em vez de traços (que são a representação padrão do .NET), o código substitui o
sublinhado antes de instanciar a classe CultureInfo :

[assembly:Dependency(typeof(UsingResxLocalization.iOS.Localize))]

namespace UsingResxLocalization.iOS
{
public class Localize : UsingResxLocalization.ILocalize
{
public void SetLocale (CultureInfo ci)
{
Thread.CurrentThread.CurrentCulture = ci;
Thread.CurrentThread.CurrentUICulture = ci;
Thread.CurrentThread.CurrentUICulture = ci;
}

public CultureInfo GetCurrentCultureInfo ()


{
var netLanguage = "en";
if (NSLocale.PreferredLanguages.Length > 0)
{
var pref = NSLocale.PreferredLanguages [0];
netLanguage = iOSToDotnetLanguage(pref);
}
// this gets called a lot - try/catch can be expensive so consider caching or something
System.Globalization.CultureInfo ci = null;
try
{
ci = new System.Globalization.CultureInfo(netLanguage);
}
catch (CultureNotFoundException e1)
{
// iOS locale not valid .NET culture (eg. "en-ES" : English in Spain)
// fallback to first characters, in this case "en"
try
{
var fallback = ToDotnetFallbackLanguage(new PlatformCulture(netLanguage));
ci = new System.Globalization.CultureInfo(fallback);
}
catch (CultureNotFoundException e2)
{
// iOS language not valid .NET culture, falling back to English
ci = new System.Globalization.CultureInfo("en");
}
}
return ci;
}

string iOSToDotnetLanguage(string iOSLanguage)


{
// .NET cultures don't support underscores
string netLanguage = iOSLanguage.Replace("_", "-");

//certain languages need to be converted to CultureInfo equivalent


switch (iOSLanguage)
{
case "ms-MY": // "Malaysian (Malaysia)" not supported .NET culture
case "ms-SG": // "Malaysian (Singapore)" not supported .NET culture
netLanguage = "ms"; // closest supported
break;
case "gsw-CH": // "Schwiizertüütsch (Swiss German)" not supported .NET culture
netLanguage = "de-CH"; // closest supported
break;
// add more application-specific cases here (if required)
// ONLY use cultures that have been tested and known to work
}
return netLanguage;
}

string ToDotnetFallbackLanguage (PlatformCulture platCulture)


{
var netLanguage = platCulture.LanguageCode; // use the first part of the identifier (two chars,
usually);
switch (platCulture.LanguageCode)
{
case "pt":
netLanguage = "pt-PT"; // fallback to Portuguese (Portugal)
break;
case "gsw":
netLanguage = "de-CH"; // equivalent to German (Switzerland) for this app
break;
// add more application-specific cases here (if required)
// ONLY use cultures that have been tested and known to work
// ONLY use cultures that have been tested and known to work
}
return netLanguage;
}
}
}

NOTE
Os blocos try/catch no método GetCurrentCultureInfo imitam o comportamento de fallback usado normalmente com
especificadores de localidade – se a correspondência exata não for encontrada, procure uma correspondência aproximada
com base apenas no idioma (primeiro bloco de caracteres na localidade).
No caso do Xamarin.Forms, algumas localidades são válidas no iOS, mas não correspondem a um CultureInfo válido no
.NET e o código acima tenta lidar com isso.
Por exemplo, a tela Configurações > Idioma Geral & Região do iOS permite que você defina o Idioma de seu telefone
como Inglês e a Região como Espanha, o que resulta na cadeia de caracteres de localidade "en-ES" . Quando a criação de
CultureInfo falha, o código volta a usar apenas as primeiras duas letras para selecionar o idioma de exibição.

Os desenvolvedores devem modificar os métodos iOSToDotnetLanguage e ToDotnetFallbackLanguage para lidar com


casos específicos necessários em seus idiomas com suporte.

Há alguns elementos da interface do usuário definidos pelo sistema que são traduzidos automaticamente pelo
iOS, como o botão Concluído no controle Picker . Para forçar o iOS a traduzir esses elementos, precisamos
indicar a quais idiomas damos suporte no arquivo Info.plist. Você pode adicionar esses valores usando Info.plist
> Origem, conforme mostrado aqui:

Como alternativa, abra o arquivo Info.plist em um editor de XML e edite os valores diretamente:

<key>CFBundleLocalizations</key>
<array>
<string>de</string>
<string>es</string>
<string>fr</string>
<string>ja</string>
<string>pt</string> <!-- Brazil -->
<string>pt-PT</string> <!-- Portugal -->
<string>ru</string>
<string>zh-Hans</string>
<string>zh-Hant</string>
</array>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
Após você ter implementado o serviço de dependência e atualizado Info.plist, o aplicativo do iOS poderá exibir o
texto localizado.

NOTE
Observe que a Apple trata o idioma português um pouco diferente da forma esperada. Nos documentos a Apple: "use pt
como a ID do idioma português usado no Brasil e pt-PT como a ID do idioma português usado em Portugal". Isso significa
que, quando o idioma português é escolhido em uma localidade não padrão, o idioma de fallback é o português brasileiro no
iOS, a menos que seja escrito um código para alterar esse comportamento (como o ToDotnetFallbackLanguage acima).

Para obter mais informações sobre a localização no iOS, confira Localização no iOS.
Projeto de Aplicativo Android
O Android expõe a localidade selecionada por meio de Java.Util.Locale.Default e também usa o sublinhado
como caractere separador, em vez do traço (que é substituído pelo código a seguir). Adicione essa implementação
do serviço de dependência ao projeto de aplicativo do Android:

[assembly:Dependency(typeof(UsingResxLocalization.Android.Localize))]

namespace UsingResxLocalization.Android
{
public class Localize : UsingResxLocalization.ILocalize
{
public void SetLocale(CultureInfo ci)
{
Thread.CurrentThread.CurrentCulture = ci;
Thread.CurrentThread.CurrentUICulture = ci;
}
public CultureInfo GetCurrentCultureInfo()
{
var netLanguage = "en";
var androidLocale = Java.Util.Locale.Default;
netLanguage = AndroidToDotnetLanguage(androidLocale.ToString().Replace("_", "-"));
// this gets called a lot - try/catch can be expensive so consider caching or something
System.Globalization.CultureInfo ci = null;
try
{
ci = new System.Globalization.CultureInfo(netLanguage);
}
catch (CultureNotFoundException e1)
{
// iOS locale not valid .NET culture (eg. "en-ES" : English in Spain)
// fallback to first characters, in this case "en"
try
{
var fallback = ToDotnetFallbackLanguage(new PlatformCulture(netLanguage));
ci = new System.Globalization.CultureInfo(fallback);
}
catch (CultureNotFoundException e2)
{
// iOS language not valid .NET culture, falling back to English
ci = new System.Globalization.CultureInfo("en");
}
}
return ci;
}
string AndroidToDotnetLanguage(string androidLanguage)
{
var netLanguage = androidLanguage;
//certain languages need to be converted to CultureInfo equivalent
switch (androidLanguage)
{
case "ms-BN": // "Malaysian (Brunei)" not supported .NET culture
case "ms-MY": // "Malaysian (Malaysia)" not supported .NET culture
case "ms-MY": // "Malaysian (Malaysia)" not supported .NET culture
case "ms-SG": // "Malaysian (Singapore)" not supported .NET culture
netLanguage = "ms"; // closest supported
break;
case "in-ID": // "Indonesian (Indonesia)" has different code in .NET
netLanguage = "id-ID"; // correct code for .NET
break;
case "gsw-CH": // "Schwiizertüütsch (Swiss German)" not supported .NET culture
netLanguage = "de-CH"; // closest supported
break;
// add more application-specific cases here (if required)
// ONLY use cultures that have been tested and known to work
}
return netLanguage;
}
string ToDotnetFallbackLanguage(PlatformCulture platCulture)
{
var netLanguage = platCulture.LanguageCode; // use the first part of the identifier (two chars,
usually);
switch (platCulture.LanguageCode)
{
case "gsw":
netLanguage = "de-CH"; // equivalent to German (Switzerland) for this app
break;
// add more application-specific cases here (if required)
// ONLY use cultures that have been tested and known to work
}
return netLanguage;
}
}
}

NOTE
Os blocos try/catch no método GetCurrentCultureInfo imitam o comportamento de fallback usado normalmente com
especificadores de localidade – se a correspondência exata não for encontrada, procure uma correspondência aproximada
com base apenas no idioma (primeiro bloco de caracteres na localidade).
No caso do Xamarin.Forms, algumas localidades são válidas no Android, mas não correspondem a um CultureInfo válido
no .NET e o código acima tenta lidar com isso.
Os desenvolvedores devem modificar os métodos iOSToDotnetLanguage e ToDotnetFallbackLanguage para lidar com
casos específicos necessários em seus idiomas com suporte.

Após esse código ter sido adicionado ao projeto de aplicativo do Android, ele será capaz de exibir
automaticamente as cadeias de caracteres traduzidas.

NOTE
AVISO: Se as cadeias de caracteres traduzidas estiverem funcionando em seus builds de VERSÃO do Android, mas não
durante a depuração, clique com o botão direito do mouse em Projeto do Android e selecione Opções > Build > Build
do Android e certifique-se de que Implantação de Assembly Rápida NÃO esteja marcado. Essa opção causa problemas
ao carregar recursos e não deverá ser usada se você estiver testando aplicativos localizados.

Para obter mais informações sobre a localização no Android, confira Localização no Android.
Plataforma Universal do Windows
Projetos da UWP (Plataforma Universal do Windows) não requerem o serviço de dependência. Em vez disso, a
plataforma define automaticamente a cultura do recurso corretamente.
A sse m b l y I n fo .c s

Expanda o nó Propriedades no projeto da biblioteca .NET Standard e clique duas vezes no arquivo
AssemblyInfo.cs. Adicione a seguinte linha ao arquivo para definir o idioma do assembly de recursos neutro
como inglês:

[assembly: NeutralResourcesLanguage("en")]

Isso informa ao gerenciador de recursos a cultura padrão do aplicativo, garantindo assim que as cadeias de
caracteres definidas no arquivo RESX de idioma neutro (AppResources.resx) sejam exibidas quando o aplicativo
estiver em execução em uma das localidades de idioma inglês.
Exemplo
Depois de atualizar projetos específicos da plataforma conforme mostrado acima e recompilar o aplicativo com
arquivos RESX traduzidos, traduções atualizadas serão disponibilizadas em cada aplicativo. Está é uma captura de
tela do código de exemplo traduzido para chinês simplificado:

Para obter mais informações sobre a localização na UWP, confira Localização na UWP.

Localizando XAML
Ao compilar uma interface do usuário do Xamarin.Forms em XAML, a marcação teria uma aparência semelhante a
esta, com cadeias de caracteres inseridas diretamente no XML:

<Label Text="Notes:" />


<Entry Placeholder="eg. buy milk" />
<Button Text="Add to list" />

Idealmente, poderíamos traduzir os controles da interface do usuário diretamente no XAML, o que pode ser feito
criando uma extensão de marcação. O código de uma extensão de marcação que expõe os recursos RESX para
XAML é mostrado abaixo. Essa classe deve ser adicionada ao código comum do Xamarin.Forms (juntamente com
as páginas XAML ):
using System;
using System.Globalization;
using System.Reflection;
using System.Resources;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace UsingResxLocalization
{
// You exclude the 'Extension' suffix when using in XAML
[ContentProperty("Text")]
public class TranslateExtension : IMarkupExtension
{
readonly CultureInfo ci = null;
const string ResourceId = "UsingResxLocalization.Resx.AppResources";

static readonly Lazy<ResourceManager> ResMgr = new Lazy<ResourceManager>(


() => new ResourceManager(ResourceId,
IntrospectionExtensions.GetTypeInfo(typeof(TranslateExtension)).Assembly));

public string Text { get; set; }

public TranslateExtension()
{
if (Device.RuntimePlatform == Device.iOS || Device.RuntimePlatform == Device.Android)
{
ci = DependencyService.Get<ILocalize>().GetCurrentCultureInfo();
}
}

public object ProvideValue(IServiceProvider serviceProvider)


{
if (Text == null)
return string.Empty;

var translation = ResMgr.Value.GetString(Text, ci);


if (translation == null)
{
#if DEBUG
throw new ArgumentException(
string.Format("Key '{0}' was not found in resources '{1}' for culture '{2}'.", Text,
ResourceId, ci.Name),
"Text");
#else
translation = Text; // HACK: returns the key, which GETS DISPLAYED TO THE USER
#endif
}
return translation;
}
}
}

Os marcadores a seguir explicam os elementos importantes do código acima:


A classe é denominada TranslateExtension , mas, por convenção, podemos nos referir a ela como Translate em
nossa marcação.
A classe implementa IMarkupExtension , que é necessário para que o Xamarin.Forms funcione.
"UsingResxLocalization.Resx.AppResources" é o identificador de recurso de nossos recursos RESX. Ele é
composto por nosso namespace padrão, pela pasta em que se encontram os arquivos de recurso e pelo nome
do arquivo RESX padrão.
A classe ResourceManager é criada usando
IntrospectionExtensions.GetTypeInfo(typeof(TranslateExtension)).Assembly) para determinar o assembly atual
do qual carregar os recursos e é armazenada em cache no campo ResMgr estático. Ela é criada como um tipo
Lazy , de forma que sua criação é adiada até que ela seja usada pela primeira vez no método ProvideValue .
ci usa o serviço de dependência para obter o idioma escolhido pelo usuário do sistema operacional nativo.
GetString é o método que recupera a cadeia de caracteres traduzida real dos arquivos de recursos. Na
Plataforma Universal do Windows, ci será nulo porque a interface ILocalize não está implementada nessas
plataformas. Isso é equivalente a chamar o método GetString apenas com o primeiro parâmetro. Em vez disso,
a estrutura de recursos automaticamente reconhecerá a localidade e recuperará a cadeia de caracteres
traduzida do arquivo RESX apropriado.
O tratamento de erro foi incluído para ajudar a depurar recursos ausentes lançando uma exceção (somente no
modo DEBUG ).

O snippet de XAML a seguir mostra como usar a extensão de marcação. Há duas etapas para fazê-la funcionar:
1. Declarar o namespace xmlns:i18n personalizado no nó raiz. namespace e assembly devem corresponder
exatamente às configurações do projeto – neste exemplo, são idênticos, mas podem ser diferentes em seu
projeto.
2. Use a sintaxe {Binding} em atributos que normalmente conteriam texto para chamar a extensão de marcação
Translate . A chave de recurso é o único parâmetro necessário.

<?xml version="1.0" encoding="UTF-8"?>


<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="UsingResxLocalization.FirstPageXaml"
xmlns:i18n="clr-namespace:UsingResxLocalization;assembly=UsingResxLocalization">
<StackLayout Padding="0, 20, 0, 0">
<Label Text="{i18n:Translate NotesLabel}" />
<Entry Placeholder="{i18n:Translate NotesPlaceholder}" />
<Button Text="{i18n:Translate AddButton}" />
</StackLayout>
</ContentPage>

A sintaxe mais detalhada a seguir também é válida para a extensão de marcação:

<Button Text="{i18n:TranslateExtension Text=AddButton}" />

Localizando elementos específicos da plataforma


Embora possamos manipular a tradução da interface do usuário no código do Xamarin.Forms, há alguns
elementos que precisam ser feitos em cada projeto específico da plataforma. Esta seção abordará como localizar:
Nome do aplicativo
Imagens
O projeto de exemplo inclui uma imagem localizada chamada flag.png, que é referenciada em C# da seguinte
maneira:
var flag = new Image();
switch (Device.RuntimePlatform)
{
case Device.iOS:
case Device.Android:
flag.Source = ImageSource.FromFile("flag.png");
break;
case Device.UWP:
flag.Source = ImageSource.FromFile("Assets/Images/flag.png");
break;
}

A imagem do sinalizador também é referenciada no XAML desta forma:

<Image>
<Image.Source>
<OnPlatform x:TypeArguments="ImageSource">
<On Platform="iOS, Android" Value="flag.png" />
<On Platform="UWP" Value="Assets/Images/flag.png" />
</OnPlatform>
</Image.Source>
</Image>

Todas as plataformas resolverão automaticamente referências de imagem como essa para versões localizadas das
imagens, desde que as estruturas de projeto explicadas abaixo sejam implementadas.
Projeto de Aplicativo iOS
O iOS usa um padrão de nomenclatura chamado Localization Projects ou diretórios .lproj para conter os recursos
de imagem e cadeia de caracteres. Esses diretórios podem conter versões localizadas de imagens usadas no
aplicativo e também o arquivo InfoPlist.strings, que pode ser usado para localizar o nome do aplicativo. Para
obter mais informações sobre a localização no iOS, confira Localização no iOS.
Imagens
Esta captura de tela mostra o aplicativo de exemplo do iOS com os diretórios .lproj específicos a um idioma. O
diretório do idioma espanhol, chamado es.lproj, contém as versões localizadas da imagem padrão, bem como
flag.png:

Cada diretório de idioma contém uma cópia de flag.png, localizada para esse idioma. Se nenhuma imagem for
fornecida, o sistema operacional, por padrão, usará a imagem no diretório de idioma padrão. Para ter suporte
completo do Retina, você precisa fornecer cópias de @2x e @3x de cada imagem.
Nome do Aplicativo
O conteúdo de InfoPlist.strings é apenas um par de chave-valor para configurar o nome do aplicativo:
"CFBundleDisplayName" = "ResxEspañol";

Quando o aplicativo é executado, o nome do aplicativo e a imagem são localizados:

Projeto de Aplicativo Android


O Android segue um esquema diferente para armazenar imagens localizadas usando diferentes diretórios
desenháveis e de cadeias de caracteres com um sufixo de código de idioma. Quando um código de localidade
de quatro letras é necessário (por exemplo, zh-TW ou pt-BR ), observe que o Android exige um r adicional após o
traço/antes do código de localidade (por exemplo, zh-rTW ou pt-rBR ). Para obter mais informações sobre a
localização no Android, confira Localização no Android.
Imagens
Esta captura de tela mostra o exemplo do Android com um alguns recursos desenháveis e cadeias de caracteres
localizados:

Observe que o Android não usa os códigos zh-Hans e zh-Hant para chinês simplificado e chinês tradicional. Em
vez disso, ele dá suporte apenas aos códigos específicos do país zh-CN e zh-TW.
Para dar suporte a imagens com resolução diferente para telas de alta densidade, crie pastas adicionais com os
sufixos -*dpi , como drawables-es-mdpi, drawables-es-xdpi, drawables-es-xxdpi etc. Confira Fornecendo
recursos alternativos do Android para obter mais informações.
Nome do Aplicativo
O conteúdo de strings.xml é apenas um par de chave-valor para configurar o nome do aplicativo:

<?xml version="1.0" encoding="utf-8"?>


<resources>
<string name="app_name">ResxEspañol</string>
</resources>
Atualize MainActivity.cs no projeto de aplicativo do Android para que Label referencie as cadeias de caracteres
XML.

[Activity (Label = "@string/app_name", MainLauncher = true,


ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]

Agora, o aplicativo localiza o nome do aplicativo e a imagem. Veja uma captura de tela do resultado (em espanhol):

Projetos de aplicativo da Plataforma Universal do Windows


A Plataforma Universal do Windows tem uma infraestrutura de recurso que simplifica a localização de imagens e
o nome do aplicativo. Para obter mais informações sobre a localização na UWP, confira Localização na UWP.
Imagens
É possível localizar imagens colocando-as em uma pasta específica do recurso, como demonstrado na seguinte
captura de tela:

Em tempo de execução, a infraestrutura de recursos do Windows selecionará a imagem apropriada com base na
localidade do usuário.

Resumo
Aplicativos do Xamarin.Forms podem ser localizados usando arquivos RESX e classes de globalização do .NET.
Exceto por uma pequena quantidade de código específico da plataforma para detectar qual é o idioma preferido
pelo usuário, a maior parte do esforço de localização está centralizado no código comum.
Normalmente, as imagens são manipuladas de forma específica à plataforma para tirar proveito do suporte de
resolução múltipla fornecido no iOS e no Android.

Links relacionados
Exemplo de localização de RESX
Aplicativo de exemplo TodoLocalized
Localização multiplataforma
Localização no iOS
Localização no Android
Localização na UWP
Usando a classe CultureInfo (MSDN )
Localizando e usando recursos para uma cultura específica (MSDN )
Localização da direita para a esquerda
12/04/2019 • 9 minutes to read • Edit Online

Baixar o exemplo
A localização da direita para a esquerda adiciona suporte para a direção do fluxo da direita para a esquerda aos
aplicativos Xamarin.Forms.

NOTE
A localização da direita para a esquerda exige o uso do iOS 9 ou superior e da API 17 ou superior no Android.

A direção do fluxo é a direção na qual os elementos de interface do usuário na página são detectados pelos olhos.
Alguns idiomas, como árabe e hebraico, exigem que os elementos de interface do usuário sejam dispostos em
uma direção de fluxo da direita para a esquerda. Isso pode ser feito com a definição da propriedade
VisualElement.FlowDirection . Essa propriedade obtém ou define a direção na qual os elementos de interface do
usuário fluem nos elementos pai que controlam seu layout e deve ser definida com um dos valores de
enumeração FlowDirection :
LeftToRight
RightToLeft
MatchParent

Em geral, a definição da propriedade FlowDirection como RightToLeft em um elemento define o alinhamento


para a direita, o sentido de leitura como direita para esquerda e o layout do controle para fluir da direita para a
esquerda:

TIP
Você só deve definir a propriedade FlowDirection no layout inicial. A alteração desse valor em tempo de execução causa
um processo caro de layout que afetará o desempenho.

O valor padrão da propriedade FlowDirection de um elemento sem um pai é LeftToRight , enquanto o


FlowDirection padrão de um elemento com um pai é MatchParent . Portanto, um elemento herda o valor da
propriedade FlowDirection de seu pai na árvore visual e qualquer elemento pode substituir o valor obtido de seu
pai.

TIP
Ao localizar um aplicativo para idiomas da direita para a esquerda, defina a propriedade FlowDirection em uma página ou
um layout raiz. Isso faz com que todos os elementos contidos na página ou layout raiz respondam de forma apropriada à
direção do fluxo.

Respeitando a direção do fluxo do dispositivo


O respeito à direção do fluxo do dispositivo com base na região e no idioma selecionados é uma opção explícita
do desenvolvedor e não ocorre automaticamente. Isso pode ser feito com a definição da propriedade
FlowDirection em uma página ou no layout raiz com o valor static Device.FlowDirection :

<ContentPage ... FlowDirection="{x:Static Device.FlowDirection}"> />

this.FlowDirection = Device.FlowDirection;

Em seguida, todos os elementos filho da página ou o layout raiz, por padrão, herdarão o valor
Device.FlowDirection .

Instalação da plataforma
A instalação da plataforma específica é necessária para habilitar localidades com leitura da direita para a esquerda.
iOS
A localidade com leitura da direita para a esquerda necessária deve ser adicionada como um idioma compatível
aos itens de matriz da chave CFBundleLocalizations em Info.plist. O seguinte exemplo mostra o árabe
adicionado à matriz da chave CFBundleLocalizations :

<key>CFBundleLocalizations</key>
<array>
<string>en</string>
<string>ar</string>
</array>

Para obter mais informações, confira Noções básicas de localização no iOS.


A localização da direita para a esquerda pode então ser testada, alterando o idioma e a região no
dispositivo/simulador para uma localidade com leitura da direita para a esquerda que foi especificada em
Info.plist.
WARNING
Observe que ao alterar o idioma e a região para uma localidade com leitura da direita para a esquerda no iOS, as exibições
DatePicker gerarão uma exceção se você não incluir os recursos necessários para a localidade. Por exemplo, ao testar um
aplicativo em árabe que tenha um DatePicker , verifique se a opção oriente médio está selecionada na seção
Internacionalização no painel Build do iOS.

Android
O arquivo AndroidManifest.xml do aplicativo deve ser atualizado para que o nó <uses-sdk> defina o atributo
android:minSdkVersion como 17 e o nó <application> defina o atributo android:supportsRtl como true :

<?xml version="1.0" encoding="utf-8"?>


<manifest ... >
<uses-sdk android:minSdkVersion="17" ... />
<application ... android:supportsRtl="true">
</application>
</manifest>

A localização da direita para a esquerda pode então ser testada, alterando o dispositivo/emulador para usar o
idioma da direita para a esquerda ou habilitando a opção Forçar direção do layout da direita para esquerda
em Configurações > Opções do Desenvolvedor.
UWP (Plataforma Universal do Windows)
Os recursos de idioma necessários devem ser especificados no nó <Resources> do arquivo
Package.appxmanifest. O seguinte exemplo mostra o árabe adicionado ao nó <Resources> :

<Resources>
<Resource Language="x-generate"/>
<Resource Language="en" />
<Resource Language="ar" />
</Resources>

Além disso, o UWP exige que a cultura padrão do aplicativo seja explicitamente definida na biblioteca do .NET
Standard. Isso pode ser feito com a definição do atributo NeutralResourcesLanguage em AssemblyInfo.cs , ou em
outra classe, como a cultura padrão:

using System.Resources;

[assembly: NeutralResourcesLanguage("en")]

A localização da direita para a esquerda pode então ser testada, alterando o idioma e a região no dispositivo para
a localidade da direita para a esquerda apropriada.

Limitações
Atualmente, a localização da direita para a esquerda do Xamarin.Forms tem várias limitações:
A localização do botão NavigationPage , a localização do item da barra de ferramentas e a animação de
transição são controlados pela localidade do dispositivo, em vez de pela propriedade FlowDirection .
A direção de passar o dedo de CarouselPage não é invertida.
O conteúdo visual de Image não é invertido.
A orientação de DisplayAlert e DisplayActionSheet é controlada pela localidade do dispositivo, em vez de
pela propriedade FlowDirection .
O conteúdo de WebView não respeita a propriedade FlowDirection .
Uma propriedade TextDirection precisa ser adicionada, para controlar o alinhamento do texto.
iOS
A orientação de Stepper é controlada pela localidade do dispositivo, em vez de pela propriedade
FlowDirection .
O alinhamento do texto de EntryCell é controlado pela localidade do dispositivo, em vez de pela propriedade
FlowDirection .
Os gestos e o alinhamento de ContextActions não são revertidos.
Android
A orientação de SearchBar é controlada pela localidade do dispositivo, em vez de pela propriedade
FlowDirection .
O posicionamento de ContextActions é controlado pela localidade do dispositivo, em vez de pela propriedade
FlowDirection .

UWP
O alinhamento do texto de Editor é controlado pela localidade do dispositivo, em vez de pela propriedade
FlowDirection .
A propriedade de FlowDirection não é herdada pelos filhos de MasterDetailPage .
O alinhamento do texto de ContextActions é controlado pela localidade do dispositivo, em vez de pela
propriedade FlowDirection .

Suporte a idiomas da direita para a esquerda com o Xamarin.University


Suporte da direita para a esquerda do Xamarin.Forms 3.0, por Xamarin University

Links relacionados
Aplicativo de exemplo TodoLocalizedRTL
Bancos de dados locais do Xamarin.Forms
12/04/2019 • 4 minutes to read • Edit Online

Baixar o exemplo
O Xamarin.Forms dá suporte a aplicativos controlados por banco de dados usando o mecanismo de banco de
dados SQLite, que torna possível carregar e salvar objetos em código compartilhado. Este artigo descreve como
os aplicativos Xamarin.Forms podem ler e gravar dados em um banco de dados SQLite local usando o
SQLite.Net.

Visão geral
Os aplicativos Xamarin.Forms podem usar o pacote NuGet SQLite.NET PCL para incorporar operações de banco
de dados no código compartilhado referenciando as classes SQLite que acompanham o NuGet. As operações de
banco de dados podem ser definidas no projeto de biblioteca do .NET Standard da solução Xamarin.Forms.
O aplicativo de exemplo que acompanha é um aplicativo simples de lista de tarefas. As capturas de tela a seguir
mostram como o exemplo é exibido em cada plataforma:

Usando o SQLite
Para adicionar o suporte do SQLite em uma biblioteca do .NET Standard Xamarin.Forms, use a função de
pesquisa do NuGet para localizar sqlite-net-pcl e instalar o pacote mais recente:
Há inúmeros pacotes NuGet com nomes semelhantes. O pacote correto tem estes atributos:
Criado por: Frank A. Krueger
Id: sqlite-net-pcl
Link do NuGet: sqlite-net-pcl

NOTE
Apesar do nome do pacote, use o pacote NuGet sqlite-net-pcl, mesmo em projetos do .NET Standard.

Depois que a referência tiver sido adicionada, adicione uma propriedade à classe App que retorna um caminho
de arquivo local para armazenar o banco de dados:

static TodoItemDatabase database;

public static TodoItemDatabase Database


{
get
{
if (database == null)
{
database = new TodoItemDatabase(
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"TodoSQLite.db3"));
}
return database;
}
}

O construtor TodoItemDatabase , que usa o caminho para o arquivo de banco de dados como um argumento, é
mostrado abaixo:

public TodoItemDatabase(string dbPath)


{
database = new SQLiteAsyncConnection(dbPath);
database.CreateTableAsync<TodoItem>().Wait();
}

A vantagem de expor o banco de dados como um singleton é que uma conexão de banco de dados individual
criada é mantida aberta enquanto o aplicativo é executado, evitando, portanto, o trabalho de abrir e fechar o
arquivo de banco de dados cada vez que uma operação de banco de dados é realizada.
O restante da classe TodoItemDatabase contém consultas SQLite em execução multiplataforma. O código de
consulta de exemplo é mostrado abaixo (mais detalhes sobre a sintaxe podem ser encontrados em Usando
SQLite.NET com o Xamarin.iOS.
public Task<List<TodoItem>> GetItemsAsync()
{
return database.Table<TodoItem>().ToListAsync();
}

public Task<List<TodoItem>> GetItemsNotDoneAsync()


{
return database.QueryAsync<TodoItem>("SELECT * FROM [TodoItem] WHERE [Done] = 0");
}

public Task<TodoItem> GetItemAsync(int id)


{
return database.Table<TodoItem>().Where(i => i.ID == id).FirstOrDefaultAsync();
}

public Task<int> SaveItemAsync(TodoItem item)


{
if (item.ID != 0)
{
return database.UpdateAsync(item);
}
else {
return database.InsertAsync(item);
}
}

public Task<int> DeleteItemAsync(TodoItem item)


{
return database.DeleteAsync(item);
}

NOTE
A vantagem de usar a API do SQLite.Net assíncrona é que as operações de banco de dados são movidas para ameaças em
segundo plano. Além disso, não há nenhuma necessidade de escrever código de tratamento de simultaneidade adicional,
porque a API faz isso.

Resumo
O Xamarin.Forms dá suporte a aplicativos controlados por banco de dados usando o mecanismo de banco de
dados SQLite, que torna possível carregar e salvar objetos em código compartilhado.
O foco deste artigo foi o acesso a um banco de dados SQLite que usa o Xamarin.Forms. Para saber mais sobre
trabalhar com o próprio SQLite, confira a documentação SQLite.NET no Android ou SQLite.NET no iOS.

Links relacionados
Exemplo de tarefas pendentes
Amostras do Xamarin.Forms
Xamarin.Forms MessagingCenter
18/04/2019 • 5 minutes to read • Edit Online

Baixar o exemplo
O Xamarin.Forms inclui um serviço de mensagens simples para enviar e receber mensagens.

Visão geral
O MessagingCenter do Xamarin.Forms habilita a exibição de modelos e outros componentes para se comunicar
sem que eles precisem saber nada uns sobre os outros, além de um contrato de mensagem simples.

Como funciona o MessagingCenter


Há duas partes para MessagingCenter :
Assinar – escute mensagens com uma determinada assinatura e execute alguma ação quando elas forem
recebidas. Vários assinantes podem escutar a mesma mensagem.
Enviar – publique uma mensagem na qual os ouvintes devem agir. Se nenhum ouvinte tiver assinado, a
mensagem será ignorada.
O MessagingCenter é uma classe estática com os métodos Subscribe e Send que são usados em toda a solução.
As mensagens têm um parâmetro message de cadeia de caracteres que é usado como uma maneira de endereçar
mensagens. Os métodos Subscribe e Send usam parâmetros genéricos para controlar como as mensagens são
entregues – duas mensagens com o mesmo texto message , mas os argumentos de tipo genérico diferentes não
serão entregues ao mesmo assinante.
A API para MessagingCenter é simples:
Subscribe<TSender> (object subscriber, string message, Action<TSender> callback, TSender source = null)
Subscribe<TSender, TArgs> (object subscriber, string message, Action<TSender, TArgs> callback, TSender
source = null)
Send<TSender> (TSender sender, string message)
Send<TSender, TArgs> (TSender sender, string message, TArgs args)
Unsubscribe<TSender, TArgs> (object subscriber, string message)
Unsubscribe<TSender> (object subscriber, string message)

Esses métodos são explicados abaixo.

Usar o MessagingCenter
As mensagens podem ser enviadas como resultado da interação do usuário (como um clique de botão), um
evento do sistema (como controles alterando um estado) ou alguns outros incidentes (como um download
assíncrono sendo concluído). Os assinantes podem estar escutando para alterar a aparência da interface do
usuário, salvar os dados ou disparar alguma outra operação.
Para obter mais informações sobre como usar a classe MessagingCenter , confira Comunicação entre componentes
fracamente acoplados.
Mensagem de cadeia de caracteres simples
A mensagem mais simples contém apenas uma cadeia de caracteres no parâmetro message . Um método
Subscribe que escuta uma mensagem de cadeia de caracteres simples é mostrado abaixo. Observe o tipo
genérico especificando que o remetente deve ser do tipo MainPage . As classes na solução podem assinar a
mensagem usando esta sintaxe:

MessagingCenter.Subscribe<MainPage> (this, "Hi", (sender) => {


// do something whenever the "Hi" message is sent
});

Na classe MainPage , o código a seguir envia a mensagem. O parâmetro this é uma instância de MainPage .

MessagingCenter.Send<MainPage> (this, "Hi");

A cadeia de caracteres não é alterada. Ela indica o tipo de mensagem e é usada para determinar quais assinantes
notificar. Esse tipo de mensagem é usado para indicar que algum evento ocorreu, como "upload concluído", em
que nenhuma informação adicional é necessária.
Passar um argumento
Para passar um argumento com a mensagem, especifique o tipo de argumento nos argumentos genéricos
Subscribe e na assinatura Ação.

MessagingCenter.Subscribe<MainPage, string> (this, "Hi", (sender, arg) => {


// do something whenever the "Hi" message is sent
// using the 'arg' parameter which is a string
});

Para enviar a mensagem com o argumento, inclua o parâmetro Tipo genérico e o valor do argumento na chamada
de método Send .

MessagingCenter.Send<MainPage, string> (this, "Hi", "John");

Este exemplo simples usa um argumento string , mas qualquer objeto C# pode ser passado.
Cancelar assinatura
Um objeto pode cancelar uma assinatura de uma mensagem para que nenhuma mensagem futura seja entregue.
A sintaxe do método Unsubscribe deve refletir a assinatura da mensagem (portanto, talvez seja necessário incluir
o parâmetro Tipo genérico para o argumento de mensagem).

MessagingCenter.Unsubscribe<MainPage> (this, "Hi");


MessagingCenter.Unsubscribe<MainPage, string> (this, "Hi");

Resumo
O MessagingCenter é uma maneira simples de reduzir o acoplamento, especialmente entre modelos de exibição.
Ele pode ser usado para enviar e receber mensagens simples ou passar um argumento entre classes. As classes
devem cancelar a assinatura de mensagens que não desejam receber.

Links relacionados
MessagingCenterSample
Amostras do Xamarin.Forms
Comunicação entre componentes flexíveis
Navegação do Xamarin.Forms
12/04/2019 • 2 minutes to read • Edit Online

O Xamarin.Forms oferece uma série de experiências de navegação de página diferentes, dependendo do tipo de
página sendo usado.

Navegação hierárquica
A classe NavigationPage oferece uma experiência de Navegação hierárquica em que o usuário é capaz de navegar
pelas páginas para frente e para trás, conforme desejado. A classe implementa navegação como uma pilha UEPS
(último a entrar, primeiro a sair) de objetos Page .

TabbedPage
O TabbedPage do Xamarin.Forms consiste em uma lista de guias e uma área de detalhes maior, com cada guia
carregando conteúdo na área de detalhes.

CarouselPage
O CarouselPage do Xamarin.Forms é uma página em que os usuários podem passar o dedo de um lado ao outro
para navegar por páginas de conteúdo, assim como uma galeria.

MasterDetailPage
O MasterDetailPage do Xamarin.Forms é uma página que gerencia duas páginas de informações relacionadas –
uma página mestra que apresenta itens e uma página de detalhes que apresenta detalhes sobre os itens na página
mestra.

Páginas modais
O Xamarin.Forms também dá suporte a páginas modais. Uma página modal incentiva os usuários a concluir uma
tarefa independente da qual não se pode sair via navegação até que essa tarefa seja concluída ou cancelada.

Exibição de pop-ups
O Xamarin.Forms fornece dois elementos de interface do usuário semelhantes a pop-up: um alerta e uma folha de
ações. Esses elementos de interface podem ser usados para fazer perguntas simples a usuários e para orientar os
usuários por meio de tarefas.
Navegação hierárquica
12/04/2019 • 20 minutes to read • Edit Online

Baixar o exemplo
A classe NavigationPage oferece uma experiência de navegação hierárquica em que o usuário pode navegar
pelas páginas para frente e para trás, conforme desejado. A classe implementa a navegação como uma pilha
UEPS (último a entrar, primeiro a sair ) de objetos de Página. Este artigo demonstra como usar a classe
NavigationPage para executar a navegação em uma pilha de páginas.
Para ir de uma página para outra, um aplicativo enviará por push uma nova página para a pilha de navegação, na
qual ela se tornará a página ativa, conforme mostrado no diagrama a seguir:

Para retornar à página anterior, o aplicativo removerá a página atual da pilha de navegação e, em seguida, a nova
página de nível superior se tornará a página ativa, conforme mostrado no diagrama a seguir:

Os métodos de navegação são expostos pela propriedade Navigation em qualquer tipo derivado de Page . Esses
métodos possibilitam enviar páginas por push para a pilha de navegação, remover páginas da pilha de navegação
e executar a manipulação da pilha.

Executando a navegação
Na barra de navegação hierárquica, a classe NavigationPage é usada para navegar por meio de uma pilha de
objetos ContentPage . As capturas de tela a seguir mostram os principais componentes de NavigationPage em
cada plataforma:

O layout de um NavigationPage depende da plataforma:


No iOS, há uma barra de navegação na parte superior da página que exibe um título e que tem um botão
Voltar que leva à página anterior.
No Android, há uma barra de navegação na parte superior da página que exibe um título, um ícone e um
botão Voltar que leva à página anterior. O ícone é definido no atributo [Activity] que decora a classe
MainActivity no projeto específico da plataforma Android.
Na Plataforma Universal do Windows, há uma barra de navegação na parte superior da página que exibe um
título.
Em todas as plataformas, o valor da propriedade Page.Title será exibido como o título da página.

NOTE
É recomendável que um NavigationPage seja preenchido somente com instâncias de ContentPage .

Criando a Página Raiz


A primeira página adicionada a uma pilha de navegação é conhecida como a página raiz do aplicativo e o exemplo
de código a seguir mostra como isso é realizado:

public App ()
{
MainPage = new NavigationPage (new Page1Xaml ());
}

Isso faz com que a instância ContentPage de Page1Xaml seja enviada por push para a pilha de navegação, em que
se torna a página ativa e a página raiz do aplicativo. Isso é mostrado nas capturas de tela a seguir:

NOTE
A propriedade RootPage de uma instância de NavigationPage fornece acesso à primeira página na pilha de navegação.

Enviando páginas por push para a pilha de navegação


Para navegar até Page2Xaml , é necessário invocar o método PushAsync na propriedade Navigation da página
atual, conforme demonstrado no exemplo de código a seguir:

async void OnNextPageButtonClicked (object sender, EventArgs e)


{
await Navigation.PushAsync (new Page2Xaml ());
}
Isso faz com que a instância Page2Xaml seja enviada por push para a pilha de navegação, em que ele se torna a
página ativa. Isso é mostrado nas capturas de tela a seguir:

Quando o método PushAsync é invocado, os seguintes eventos ocorrem:


A página que chama PushAsync tem sua substituição OnDisappearing invocada.
A página para a qual o usuário está navegando tem sua substituição OnAppearing invocada.
A tarefa PushAsync é concluída.
No entanto, a ordem exata em que esses eventos ocorrem depende da plataforma. Para obter mais informações,
confira o Capítulo 24 do livro de Charles Petzold sobre Xamarin.Forms.

NOTE
Chamadas para as substituições OnDisappearing e OnAppearing não podem ser tratadas como indicações garantidas de
navegação de página. Por exemplo, no iOS, a substituição OnDisappearing é chamada na página ativa quando o aplicativo
é encerrado.

Removendo páginas da pilha de navegação


A página ativa pode ser removida como o item mais recente da pilha de navegação pressionando o botão Voltar
no dispositivo, independentemente de este ser um botão físico no dispositivo ou um botão na tela.
Para retornar programaticamente à página original, a instância Page2Xaml deve invocar o método PopAsync ,
conforme demonstrado no exemplo de código a seguir:

async void OnPreviousPageButtonClicked (object sender, EventArgs e)


{
await Navigation.PopAsync ();
}

Isso faz com que a instância Page2Xaml seja removida da pilha de navegação, com a nova página de nível superior
tornando-se a página ativa. Quando o método PopAsync é invocado, os seguintes eventos ocorrem:
A página que chama PopAsync tem sua substituição OnDisappearing invocada.
A página para a qual o usuário está voltando tem sua substituição OnAppearing invocada.
A tarefa PopAsync é retornada.
No entanto, a ordem exata em que esses eventos ocorrem depende da plataforma. Para obter mais informações,
confira o Capítulo 24 do livro de Charles Petzold sobre Xamarin.Forms.
Assim como os métodos PushAsync e PopAsync , a propriedade Navigation de cada página também fornece um
método PopToRootAsync , que é mostrado no exemplo de código a seguir:

async void OnRootPageButtonClicked (object sender, EventArgs e)


{
await Navigation.PopToRootAsync ();
}

Esse método retira todas a páginas, exceto pela Page raiz, da pilha de navegação, tornando assim a página raiz do
aplicativo a página ativa.
Animando transições de página
A propriedade Navigation de cada página também fornece métodos de envio por push e remoção substituídos
que incluem um parâmetro boolean que controla se deve ser exibida uma animação de página durante a
navegação, conforme mostrado no código de exemplo a seguir:

async void OnNextPageButtonClicked (object sender, EventArgs e)


{
// Page appearance not animated
await Navigation.PushAsync (new Page2Xaml (), false);
}

async void OnPreviousPageButtonClicked (object sender, EventArgs e)


{
// Page appearance not animated
await Navigation.PopAsync (false);
}

async void OnRootPageButtonClicked (object sender, EventArgs e)


{
// Page appearance not animated
await Navigation.PopToRootAsync (false);
}

Definir o parâmetro boolean como false desabilita a animação de transição de página, enquanto definir o
parâmetro como true habilita a animação de transição de página, desde que ela tenha suporte da plataforma
subjacente. No entanto, os métodos de envio por push e remoção que não têm esse parâmetro habilitam a
animação por padrão.

Transmitindo dados ao navegar


Às vezes, é necessário que uma página transmita dados para outra página durante a navegação. Duas técnicas
para fazer isso são transmitir dados por meio de um construtor de página e definir o BindingContext como os
dados. Descreveremos cada técnica separadamente.
Transmitindo dados por meio de um construtor de página
A técnica mais simples para transmitir dados para outra página durante a navegação é por meio de um parâmetro
de construtor de página, que é mostrado no exemplo de código a seguir:

public App ()
{
MainPage = new NavigationPage (new MainPage (DateTime.Now.ToString ("u")));
}
Esse código cria uma instância de MainPage , transmitindo a data e a hora atuais no formato ISO8601, que é
encapsulada em uma instância de NavigationPage .

A instância de MainPage recebe os dados por meio de um parâmetro de construtor, conforme mostrado no
exemplo de código a seguir:

public MainPage (string date)


{
InitializeComponent ();
dateLabel.Text = date;
}

Os dados são exibidos na página definindo a propriedade Label.Text , conforme mostrado nas capturas de tela
seguir:

Transmitindo dados por meio de um BindingContext


Outra abordagem para transmitir dados para outra página durante a navegação é definir o BindingContext da
nova página como os dados, conforme mostrado no exemplo de código a seguir:

async void OnNavigateButtonClicked (object sender, EventArgs e)


{
var contact = new Contact {
Name = "Jane Doe",
Age = 30,
Occupation = "Developer",
Country = "USA"
};

var secondPage = new SecondPage ();


secondPage.BindingContext = contact;
await Navigation.PushAsync (secondPage);
}

Esse código define o BindingContext da instância de SecondPage como a instância de Contact e, em seguida,
navega para o SecondPage .
O SecondPage , em seguida, usa a associação de dados para exibir os dados da instância de Contact , conforme
mostrado no exemplo de código XAML a seguir:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="PassingData.SecondPage"
Title="Second Page">
<ContentPage.Content>
<StackLayout HorizontalOptions="Center" VerticalOptions="Center">
<StackLayout Orientation="Horizontal">
<Label Text="Name:" HorizontalOptions="FillAndExpand" />
<Label Text="{Binding Name}" FontSize="Medium" FontAttributes="Bold" />
</StackLayout>
...
<Button x:Name="navigateButton" Text="Previous Page" Clicked="OnNavigateButtonClicked" />
</StackLayout>
</ContentPage.Content>
</ContentPage>

O exemplo de código a seguir mostra como a associação de dados pode ser feita em C#:

public class SecondPageCS : ContentPage


{
public SecondPageCS ()
{
var nameLabel = new Label {
FontSize = Device.GetNamedSize (NamedSize.Medium, typeof(Label)),
FontAttributes = FontAttributes.Bold
};
nameLabel.SetBinding (Label.TextProperty, "Name");
...
var navigateButton = new Button { Text = "Previous Page" };
navigateButton.Clicked += OnNavigateButtonClicked;

Content = new StackLayout {


HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center,
Children = {
new StackLayout {
Orientation = StackOrientation.Horizontal,
Children = {
new Label{ Text = "Name:", FontSize = Device.GetNamedSize (NamedSize.Medium, typeof(Label)),
HorizontalOptions = LayoutOptions.FillAndExpand },
nameLabel
}
},
...
navigateButton
}
};
}

async void OnNavigateButtonClicked (object sender, EventArgs e)


{
await Navigation.PopAsync ();
}
}

Em seguida, os dados são exibidos na página por uma série de controles de Label , conforme mostrado nas
capturas de tela seguir:
Para obter mais informações sobre vinculação de dados, veja Noções básicas de vinculação de dados.

Manipulando a pilha de navegação


A propriedade Navigation expõe uma propriedade NavigationStack da qual as páginas na pilha de navegação
podem ser obtidas. Enquanto o Xamarin.Forms mantém o acesso à pilha de navegação, a propriedade
Navigation fornece os métodos InsertPageBefore e RemovePage para manipular a pilha inserindo ou removendo
páginas.
O método InsertPageBefore insere uma página especificada na pilha de navegação antes de uma página
existente, conforme mostrado no diagrama a seguir:

O método RemovePage remove a página especificada da pilha de navegação, conforme mostrado no diagrama a
seguir:

Esses métodos permitem criar uma experiência de navegação personalizada, como substituir uma página de
logon por uma nova página após um logon bem-sucedido. O código de exemplo a seguir demonstra esse cenário:

async void OnLoginButtonClicked (object sender, EventArgs e)


{
...
var isValid = AreCredentialsCorrect (user);
if (isValid) {
App.IsUserLoggedIn = true;
Navigation.InsertPageBefore (new MainPage (), this);
await Navigation.PopAsync ();
} else {
// Login failed
}
}

Desde que as credenciais do usuário estejam corretas, a instância MainPage será inserida na pilha de navegação
antes da página atual. Em seguida, o método PopAsync remove a página atual da pilha de navegação, com a
instância de MainPage se tornando a página ativa.

Exibindo modos de exibição na barra de navegação


Qualquer View da Xamarin.Forms pode ser exibido na barra de navegação de uma NavigationPage . Isso é feito
definindo a propriedade anexada NavigationPage.TitleView como um View . Essa propriedade anexada pode ser
definida em qualquer Page e, quando a Page é enviada por push a uma NavigationPage , a NavigationPage
respeitará o valor da propriedade.
O exemplo a seguir, extraído do Exemplo de Modo de Exibição de Título, mostra como definir a propriedade
anexada NavigationPage.TitleView do XAML:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="NavigationPageTitleView.TitleViewPage">
<NavigationPage.TitleView>
<Slider HeightRequest="44" WidthRequest="300" />
</NavigationPage.TitleView>
...
</ContentPage>

Este é o código C# equivalente:

public class TitleViewPage : ContentPage


{
public TitleViewPage()
{
var titleView = new Slider { HeightRequest = 44, WidthRequest = 300 };
NavigationPage.SetTitleView(this, titleView);
...
}
}

Isso faz com que um Slider seja exibido na barra de navegação na NavigationPage :

IMPORTANT
Muitos modos de exibição não aparecerão na barra de navegação a menos que o tamanho do modo de exibição seja
especificado com as propriedades WidthRequest e HeightRequest . Como alternativa, o modo de exibição pode ser
encapsulado em um StackLayout com as propriedades HorizontalOptions e VerticalOptions definidas como os
valores apropriados.

Observe que, como a classe Layout é derivada da classe View , a propriedade anexada TitleView pode ser
definida para exibir uma classe de layout que contém vários modos de exibição. No iOS e na UWP (Plataforma
Universal do Windows), não é possível alterar a altura da barra de navegação e, portanto, será feito um recorte se
o modo de exibição na barra de navegação for maior que o tamanho padrão da barra de navegação. No entanto,
no Android, a altura da barra de navegação pode ser alterada definindo a propriedade vinculável
NavigationPage.BarHeight como um double que representa a nova altura. Para obter mais informações, confira
Definindo a altura da barra de navegação em uma NavigationPage.
Como alternativa, é possível sugerir uma barra de navegação estendida colocando parte do conteúdo na barra de
navegação e parte em um modo de exibição na parte superior do conteúdo da página, cuja cor deve corresponder
à da barra de navegação. Além disso, no iOS, a linha separadora e sombra na parte inferior da barra de
navegação podem ser removidas definindo a propriedade associável NavigationPage.HideNavigationBarSeparator
como true . Para obter mais informações, confira Ocultando o separador da barra de navegação em uma
NavigationPage.

NOTE
As propriedades BackButtonTitle , Title , TitleIcon e TitleView podem definir valores que ocupam espaço na
barra de navegação. Embora o tamanho da barra de navegação varie de acordo com o tamanho da tela e a plataforma,
definir todas essas propriedades causará conflitos devido à limitação do espaço disponível. Em vez de tentar usar uma
combinação dessas propriedades, você provavelmente concluirá que é mais fácil obter o design desejado da barra de
navegação definindo apenas a propriedade TitleView .

Limitações
É necessário estar ciente de uma série de limitações ao exibir um View na barra de navegação de uma
NavigationPage :

No iOS, modos de exibição colocados na barra de navegação de um NavigationPage poderão aparecer em


uma posição diferente se títulos grandes estiverem habilitados. Para obter mais informações sobre a
habilitação de títulos grandes, confira Exibindo títulos grandes.
No Android, só é possível colocar modos de exibição na barra de navegação de um NavigationPage em
aplicativos que usam a compatibilidade de aplicativos.
Não é recomendável colocar modos de exibição grandes e complexos, como ListView e TableView , na barra
de navegação de uma NavigationPage .

Links relacionados
Navegação da página
Hierárquica (amostra)
PassingData (amostra)
LoginFlow (amostra)
TitleView (amostra)
Exemplo de como criar um fluxo de tela de entrada no Xamarin.Forms (vídeo do Xamarin University)
Como criar um fluxo de tela de entrada no Xamarin.Forms (vídeo do Xamarin University)
NavigationPage
Página com guias do Xamarin.Forms
12/04/2019 • 10 minutes to read • Edit Online

Baixar o exemplo
A TabbedPage do Xamarin.Forms consiste em uma lista de guias e uma área do detalhe maior, com cada guia
carregando conteúdo na área do detalhe. Este artigo demonstra como usar uma TabbedPage para navegar por
uma coleção de páginas.

Visão geral
As seguintes capturas de tela mostram uma TabbedPage em cada plataforma:

As seguintes capturas de tela se concentram no formato da guia em cada plataforma:

O layout de uma TabbedPage , e suas guias, depende da plataforma:


No iOS, a lista de guias é exibida na parte inferior da tela e a área do detalhe fica acima dela. Cada guia
também tem uma imagem de ícone que deve ser um PNG 30x30 com transparência para resolução
normal, 60x60 para alta resolução e 90x90 para resolução no iPhone 6 Plus. Se houver mais de cinco guias,
uma guia Mais será exibida, que poderá ser usada para acessar as guias adicionais. Para obter mais
informações sobre como carregar imagens em um aplicativo Xamarin.Forms, confira Trabalhando com
imagens. Para obter mais informações sobre os requisitos de ícone, confira Criando aplicativos com guias.

NOTE
Observe que o TabbedRenderer para iOS tem um método GetIcon substituível que pode ser usado para carregar
ícones de guia de uma origem especificada. Essa substituição possibilita o uso de imagens SVG como ícones em uma
TabbedPage . Além disso, versões selecionadas e não selecionadas de um ícone podem ser fornecidas.

No Android, a lista de guias é exibida na parte superior da tela por padrão e a área do detalhe fica abaixo
dela. No entanto, a lista de guias pode ser movida para a parte inferior da tela com um código específico da
plataforma. Para obter mais informações, confira Definindo o posicionamento e a cor da barra de
ferramentas da TabbedPage.
NOTE
Observe que, ao usar AppCompat no Android, cada guia também exibirá um ícone. Além disso, o
TabbedPageRenderer para Android AppCompat tem um método GetIconDrawable substituível que pode ser
usado para carregar ícones de guia de um Drawable personalizado. Essa substituição possibilita o uso de imagens
SVG como ícones em uma TabbedPage e funciona com barras de guia superior e inferior. Como alternativa, o
método SetTabIcon substituível pode ser usado para carregar ícones de guia de um Drawable personalizado
para barras de guia superior.

Em fatores forma de tablets Windows, as guias não ficam sempre visíveis e os usuários precisam passar o
dedo para baixo (ou clicar com o botão direito do mouse, caso tenham um mouse anexado) para exibir as
guias em uma TabbedPage (conforme mostrado abaixo).

Criando uma TabbedPage


Duas abordagens podem ser usadas para criar uma TabbedPage :
Popular a TabbedPage com uma coleção de objetos Page filhos, como uma coleção de ContentPage instâncias.
Atribuir uma coleção à propriedade ItemsSource e atribuir um DataTemplate à propriedade ItemTemplate para
retornar páginas para objetos na coleção.
Com as duas abordagens, a TabbedPage exibirá cada página conforme o usuário selecionar cada guia.

NOTE
É recomendável popular uma TabbedPage somente com as instâncias NavigationPage e ContentPage . Isso ajudará a
garantir uma experiência do usuário consistente em todas as plataformas.

Populando uma TabbedPage com uma coleção de páginas


O seguinte exemplo de código XAML mostra uma TabbedPage construída populando-a com uma coleção de
objetos Page filho:

<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:TabbedPageWithNavigationPage;assembly=TabbedPageWithNavigationPage"
x:Class="TabbedPageWithNavigationPage.MainPage">
<local:TodayPage />
<NavigationPage Title="Schedule" Icon="schedule.png">
<x:Arguments>
<local:SchedulePage />
</x:Arguments>
</NavigationPage>
</TabbedPage>

O seguinte exemplo de código mostra a TabbedPage equivalente criada em C#:


public class MainPageCS : TabbedPage
{
public MainPageCS ()
{
var navigationPage = new NavigationPage (new SchedulePageCS ());
navigationPage.Icon = "schedule.png";
navigationPage.Title = "Schedule";

Children.Add (new TodayPageCS ());


Children.Add (navigationPage);
}
}

A TabbedPage é populada com dois objetos Page filho. O primeiro filho é uma instância ContentPage e a segunda
guia é uma NavigationPage que contém uma instância ContentPage .

NOTE
A TabbedPage não dá suporte à virtualização de interface do usuário. Portanto, o desempenho poderá ser afetado se a
TabbedPage contiver muitos elementos filho.

As seguintes capturas de tela mostram a instância TodayPage ContentPage , que é mostrada na guia Hoje:

A seleção da guia Agendamento exibe a instância SchedulePage ContentPage , que é encapsulada em uma
instância NavigationPage , e é mostrada na seguinte captura de tela:
Para obter informações sobre o layout de uma NavigationPage , confira Executando a navegação.

NOTE
Embora seja aceitável colocar uma NavigationPage em uma TabbedPage , não é recomendável colocar uma TabbedPage
em uma NavigationPage . Isso ocorre porque, no iOS, um UITabBarController sempre funciona como um wrapper para
o UINavigationController . Para obter mais informações, confira Interfaces combinadas do controlador de exibição na
Biblioteca do Desenvolvedor do iOS.

Navegação dentro de uma guia


A navegação pode ser executada na segunda guia invocando o método PushAsync na propriedade Navigation da
instância ContentPage , conforme demonstrado no seguinte exemplo de código:

async void OnUpcomingAppointmentsButtonClicked (object sender, EventArgs e)


{
await Navigation.PushAsync (new UpcomingAppointmentsPage ());
}

Isso faz com que a instância UpcomingAppointmentsPage seja enviada por push para a pilha de navegação, em que
ele se torna a página ativa. Isso é mostrado nas seguintes capturas de tela:
Para obter mais informações sobre como executar a navegação usando a classe NavigationPage , confira
Navegação hierárquica.
Populando uma TabbedPage com um modelo
O exemplo de código XAML a seguir mostra uma TabbedPage construída pela atribuição de um DataTemplate à
propriedade ItemTemplate para retornar páginas para objetos na coleção:

<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TabbedPageDemo;assembly=TabbedPageDemo"
x:Class="TabbedPageDemo.TabbedPageDemoPage">
<TabbedPage.Resources>
<ResourceDictionary>
<local:NonNullToBooleanConverter x:Key="booleanConverter" />
</ResourceDictionary>
</TabbedPage.Resources>
<TabbedPage.ItemTemplate>
<DataTemplate>
<ContentPage Title="{Binding Name}" Icon="monkeyicon.png">
<StackLayout Padding="5, 25">
<Label Text="{Binding Name}" Font="Bold,Large" HorizontalOptions="Center" />
<Image Source="{Binding PhotoUrl}" WidthRequest="200" HeightRequest="200" />
<StackLayout Padding="50, 10">
<StackLayout Orientation="Horizontal">
<Label Text="Family:" HorizontalOptions="FillAndExpand" />
<Label Text="{Binding Family}" Font="Bold,Medium" />
</StackLayout>
...
</StackLayout>
</StackLayout>
</ContentPage>
</DataTemplate>
</TabbedPage.ItemTemplate>
</TabbedPage>

A TabbedPage é populada com os dados, definindo a propriedade ItemsSource no construtor para o arquivo code-
behind:

public TabbedPageDemoPage ()
{
...
ItemsSource = MonkeyDataModel.All;
}

O seguinte exemplo de código mostra a TabbedPage equivalente criada em C#:


public class TabbedPageDemoPageCS : TabbedPage
{
public TabbedPageDemoPageCS ()
{
var booleanConverter = new NonNullToBooleanConverter ();

ItemTemplate = new DataTemplate (() => {


var nameLabel = new Label {
FontSize = Device.GetNamedSize (NamedSize.Large, typeof(Label)),
FontAttributes = FontAttributes.Bold,
HorizontalOptions = LayoutOptions.Center
};
nameLabel.SetBinding (Label.TextProperty, "Name");

var image = new Image { WidthRequest = 200, HeightRequest = 200 };


image.SetBinding (Image.SourceProperty, "PhotoUrl");

var familyLabel = new Label {


FontSize = Device.GetNamedSize (NamedSize.Medium, typeof(Label)),
FontAttributes = FontAttributes.Bold
};
familyLabel.SetBinding (Label.TextProperty, "Family");
...

var contentPage = new ContentPage {


Icon = "monkeyicon.png",
Content = new StackLayout {
Padding = new Thickness (5, 25),
Children = {
nameLabel,
image,
new StackLayout {
Padding = new Thickness (50, 10),
Children = {
new StackLayout {
Orientation = StackOrientation.Horizontal,
Children = {
new Label { Text = "Family:", HorizontalOptions = LayoutOptions.FillAndExpand },
familyLabel
}
},
...
}
}
}
}
};
contentPage.SetBinding (TitleProperty, "Name");
return contentPage;
});
ItemsSource = MonkeyDataModel.All;
}
}

Cada guia exibe uma ContentPage que usa uma série de instâncias StackLayout e Label para exibir os dados
para a guia. As seguintes capturas de tela mostram o conteúdo da guia Tamarin:
A seleção de outra guia exibe o conteúdo dessa guia.

NOTE
A TabbedPage não dá suporte à virtualização de interface do usuário. Portanto, o desempenho poderá ser afetado se a
TabbedPage contiver muitos elementos filho.

Para obter mais informações sobre a TabbedPage , confira o Capítulo 25 do livro sobre o Xamarin.Forms de
Charles Petzold.

Resumo
Este artigo demonstrou como usar uma TabbedPage para navegar por uma coleção de páginas. A TabbedPage do
Xamarin.Forms consiste em uma lista de guias e uma área do detalhe maior, com cada guia carregando conteúdo
na área do detalhe.

Links relacionados
Variedades de página
TabbedPageWithNavigationPage (amostra)
TabbedPage (amostra)
TabbedPage
Página de carrossel do Xamarin.Forms
12/04/2019 • 7 minutes to read • Edit Online

Baixar o exemplo
A CarouselPage do Xamarin.Forms é uma página em que os usuários podem passar o dedo de um lado ao outro
para navegar por páginas de conteúdo, como uma galeria. Este artigo demonstra como usar uma CarouselPage
para navegar por uma coleção de páginas.

Visão geral
As seguintes capturas de tela mostram uma CarouselPage em cada plataforma:

O layout de uma CarouselPage é idêntico em todas as plataformas. As páginas podem ser navegadas passando o
dedo da direita para a esquerda para navegar para frente na coleção e passando o dedo da esquerda para a direita
para navegar para trás. As capturas de tela a seguir mostram a primeira página em uma instância de uma
CarouselPage :

Passar o dedo da direita para a esquerda leva para a segunda página, conforme mostrado nas capturas de tela
seguir:
Passar o dedo da direita para a esquerda novamente leva para a terceira página, enquanto passar o dedo da
esquerda para a direita retorna à página anterior.

Criando uma CarouselPage


Duas abordagens podem ser usadas para criar uma CarouselPage :
Popular uma CarouselPage com uma coleção de instancias filhas de ContentPage .
Atribuir uma coleção à propriedade ItemsSource e atribuir um DataTemplate à propriedade ItemTemplate para
retornar instâncias de ContentPage para objetos na coleção.

Com as duas abordagens, a CarouselPage exibirá uma página por vez, com uma interação de passar o dedo
levando para a próxima página a ser exibida.

NOTE
Uma CarouselPage pode ser populada apenas com instâncias de ContentPage ou derivados de ContentPage .

Populando uma CarouselPage com uma coleção de páginas


O exemplo de código XAML a seguir mostra um CarouselPage que exibe três instâncias de ContentPage :
<CarouselPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="CarouselPageNavigation.MainPage">
<ContentPage>
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS, Android" Value="0,40,0,0" />
</OnPlatform>
</ContentPage.Padding>
<StackLayout>
<Label Text="Red" FontSize="Medium" HorizontalOptions="Center" />
<BoxView Color="Red" WidthRequest="200" HeightRequest="200" HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
<ContentPage>
...
</ContentPage>
<ContentPage>
...
</ContentPage>
</CarouselPage>

O exemplo de código a seguir mostra a interface do usuário equivalente em C#:


public class MainPageCS : CarouselPage
{
public MainPageCS ()
{
Thickness padding;
switch (Device.RuntimePlatform)
{
case Device.iOS:
case Device.Android:
padding = new Thickness(0, 40, 0, 0);
break;
default:
padding = new Thickness();
break;
}

var redContentPage = new ContentPage {


Padding = padding,
Content = new StackLayout {
Children = {
new Label {
Text = "Red",
FontSize = Device.GetNamedSize (NamedSize.Medium, typeof(Label)),
HorizontalOptions = LayoutOptions.Center
},
new BoxView {
Color = Color.Red,
WidthRequest = 200,
HeightRequest = 200,
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.CenterAndExpand
}
}
}
};
var greenContentPage = new ContentPage {
Padding = padding,
Content = new StackLayout {
...
}
};
var blueContentPage = new ContentPage {
Padding = padding,
Content = new StackLayout {
...
}
};

Children.Add (redContentPage);
Children.Add (greenContentPage);
Children.Add (blueContentPage);
}
}

Cada ContentPage simplesmente exibe um Label para uma cor específica e um BoxView dessa cor.

NOTE
A CarouselPage não dá suporte à virtualização de interface do usuário. Portanto, o desempenho poderá ser afetado se a
CarouselPage contiver muitos elementos filho.

Se uma for inserida na página Detail de um MasterDetailPage , a propriedade


CarouselPage
MasterDetailPage.IsGestureEnabled deverá ser definida como false para evitar conflitos de gesto entre o
CarouselPage eo MasterDetailPage .
Para obter mais informações sobre a CarouselPage , confira o Capítulo 25 do livro sobre o Xamarin.Forms de
Charles Petzold.
Populando uma CarouselPage com um modelo
O exemplo de código XAML a seguir mostra uma CarouselPage construída pela atribuição de um DataTemplate à
propriedade ItemTemplate para retornar páginas para objetos na coleção:

<CarouselPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="CarouselPageNavigation.MainPage">
<CarouselPage.ItemTemplate>
<DataTemplate>
<ContentPage>
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS, Android" Value="0,40,0,0" />
</OnPlatform>
</ContentPage.Padding>
<StackLayout>
<Label Text="{Binding Name}" FontSize="Medium" HorizontalOptions="Center" />
<BoxView Color="{Binding Color}" WidthRequest="200" HeightRequest="200"
HorizontalOptions="Center" VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
</DataTemplate>
</CarouselPage.ItemTemplate>
</CarouselPage>

A CarouselPage é populada com os dados, definindo a propriedade ItemsSource no construtor para o arquivo
code-behind:

public MainPage ()
{
...
ItemsSource = ColorsDataModel.All;
}

O seguinte exemplo de código mostra a CarouselPage equivalente criada em C#:


public class MainPageCS : CarouselPage
{
public MainPageCS ()
{
Thickness padding;
switch (Device.RuntimePlatform)
{
case Device.iOS:
case Device.Android:
padding = new Thickness(0, 40, 0, 0);
break;
default:
padding = new Thickness();
break;
}

ItemTemplate = new DataTemplate (() => {


var nameLabel = new Label {
FontSize = Device.GetNamedSize (NamedSize.Medium, typeof(Label)),
HorizontalOptions = LayoutOptions.Center
};
nameLabel.SetBinding (Label.TextProperty, "Name");

var colorBoxView = new BoxView {


WidthRequest = 200,
HeightRequest = 200,
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.CenterAndExpand
};
colorBoxView.SetBinding (BoxView.ColorProperty, "Color");

return new ContentPage {


Padding = padding,
Content = new StackLayout {
Children = {
nameLabel,
colorBoxView
}
}
};
});

ItemsSource = ColorsDataModel.All;
}
}

Cada ContentPage simplesmente exibe um Label para uma cor específica e um BoxView dessa cor.

NOTE
A CarouselPage não dá suporte à virtualização de interface do usuário. Portanto, o desempenho poderá ser afetado se a
CarouselPage contiver muitos elementos filho.

Se uma CarouselPage for inserida na página Detail de um MasterDetailPage , a propriedade


MasterDetailPage.IsGestureEnabled deverá ser definida como false para evitar conflitos de gesto entre o
CarouselPage e o MasterDetailPage .
Para obter mais informações sobre a CarouselPage , confira o Capítulo 25 do livro sobre o Xamarin.Forms de
Charles Petzold.

Resumo
Este artigo demonstrou como usar uma CarouselPage para navegar por uma coleção de páginas. A CarouselPage
é uma página em que os usuários podem passar o dedo de um lado ao outro para navegar por páginas de
conteúdo, assim como uma galeria.

Links relacionados
Variedades de página
CarouselPage (amostra)
CarouselPageTemplate (amostra)
CarouselPage
Página Mestre/Detalhes do Xamarin.Forms
12/04/2019 • 15 minutes to read • Edit Online

Baixar o exemplo
A MasterDetailPage do Xamarin.Forms é uma página que gerencia duas páginas relacionadas de informações –
uma página mestra que apresenta itens e uma página de detalhes que apresenta detalhes sobre os itens na
página mestra. Este artigo explica como usar uma MasterDetailPage e navegar entre suas páginas de
informações.

Visão geral
Uma página mestra normalmente exibe uma lista de itens, conforme mostrado nas capturas de tela seguir:

A localização da lista de itens é idêntico em cada plataforma e selecionar um dos itens navegará até a página de
detalhes correspondente. Além disso, a página mestra também apresenta uma barra de navegação que contém
um botão que pode ser usado para navegar até a página de detalhes ativa:
No iOS, a barra de navegação está presente na parte superior da página e tem um botão que navega até a
página de detalhes. Além disso, é possível navegar até a página de detalhes ativa passando o dedo na página
mestra para a esquerda.
No Android, a barra de navegação está presente na parte superior da página e exibe um título, um ícone e um
botão que navega até a página de detalhes. O ícone é definido no atributo [Activity] que decora a classe
MainActivity no projeto específico da plataforma Android. Além disso, é possível navegar até a página de
detalhes ativa passando o dedo na página mestra para a esquerda, tocando a página de detalhes na
extremidade direita da tela e tocando no botão Voltar na parte inferior da tela.
Na UWP (Plataforma Universal do Windows), a barra de navegação está presente na parte superior da página
e tem um botão que navega até a página de detalhes.
Uma página de detalhes exibe dados correspondentes ao item selecionado na página mestra e os principais
componentes da página de detalhes são mostrados nas capturas de tela a seguir:
A página de detalhes contém uma barra de navegação, cujo conteúdo dependem da plataforma:
No iOS, a barra de navegação está presente na parte superior da página, exibe um título e tem um botão que
retorna para a página mestra, contanto que a instância da página de detalhes seja encapsulada na instância
NavigationPage . Além disso, é possível retornar à página mestra passando o dedo na página de detalhes para a
direita.
No Android, uma barra de navegação está presente na parte superior da página e exibe um título, um ícone e
um botão que retorna à página mestra. O ícone é definido no atributo [Activity] que decora a classe
MainActivity no projeto específico da plataforma Android.
Na UWP, uma barra de navegação está presente na parte superior da página e exibe um título e tem botão que
retorna à página mestra.
Comportamento de navegação
O comportamento da experiência de navegação entre páginas mestras e de detalhes depende da plataforma:
No iOS, a página de detalhes desliza para a direita enquanto a página mestra desliza para a esquerda e a parte
esquerda da página de detalhes ainda está visível.
No Android, as páginas mestras e de detalhes são sobrepostas umas às outras.
Na UWP, a página mestra desliza da esquerda para parte da página de detalhes, desde que a propriedade
MasterBehavior esteja definida como Popover . Para obter mais informações, confira Controlando o
comportamento de exibição da página de detalhes.
Um comportamento semelhante será observado no modo paisagem, exceto que a página mestra no iOS e no
Android tem uma largura semelhante à da página mestra no modo retrato; portanto, mais coisas da página de
detalhes ficarão visíveis.
Para saber como controlar o comportamento de navegação, confira Controlling the Detail Page Display Behavior
(Controlando o comportamento de exibição da página de detalhes).

Criando um MasterDetailPage
Um MasterDetailPage contém as propriedades Master e Detail que são do tipo Page , usadas para obter e
definir as páginas mestras e de detalhes, respectivamente.

IMPORTANT
Um MasterDetailPage foi criado para ser uma página raiz e usá-la como uma página filho em outros tipos de página pode
resultar em comportamento inesperado e inconsistente. Além disso, é recomendável que a página mestra de um
MasterDetailPage sempre deva ser uma instância ContentPage , e que a página de detalhes só deva ser populada com as
instâncias TabbedPage , NavigationPage e ContentPage . Isso ajudará a garantir uma experiência do usuário consistente
em todas as plataformas.

O exemplo de código XAML a seguir mostra um MasterDetailPage que define as propriedades Master e Detail :
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MasterDetailPageNavigation;assembly=MasterDetailPageNavigation"
x:Class="MasterDetailPageNavigation.MainPage">
<MasterDetailPage.Master>
<local:MasterPage x:Name="masterPage" />
</MasterDetailPage.Master>
<MasterDetailPage.Detail>
<NavigationPage>
<x:Arguments>
<local:ContactsPage />
</x:Arguments>
</NavigationPage>
</MasterDetailPage.Detail>
</MasterDetailPage>

O seguinte exemplo de código mostra a MasterDetailPage equivalente criada em C#:

public class MainPageCS : MasterDetailPage


{
MasterPageCS masterPage;

public MainPageCS ()
{
masterPage = new MasterPageCS ();
Master = masterPage;
Detail = new NavigationPage (new ContactsPageCS ());
...
}
...
}

A propriedade MasterDetailPage.Master está definida como uma instância ContentPage . A propriedade


MasterDetailPage.Detail está definida como uma NavigationPage que contém uma instância ContentPage .
Criando a página mestra
O exemplo de código XAML a seguir mostra a declaração do objeto MasterPage , referenciado por meio da
propriedade MasterDetailPage.Master :
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="using:MasterDetailPageNavigation"
x:Class="MasterDetailPageNavigation.MasterPage"
Padding="0,40,0,0"
Icon="hamburger.png"
Title="Personal Organiser">
<StackLayout>
<ListView x:Name="listView" x:FieldModifier="public">
<ListView.ItemsSource>
<x:Array Type="{x:Type local:MasterPageItem}">
<local:MasterPageItem Title="Contacts" IconSource="contacts.png" TargetType="{x:Type
local:ContactsPage}" />
<local:MasterPageItem Title="TodoList" IconSource="todo.png" TargetType="{x:Type
local:TodoListPage}" />
<local:MasterPageItem Title="Reminders" IconSource="reminders.png" TargetType="{x:Type
local:ReminderPage}" />
</x:Array>
</ListView.ItemsSource>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Padding="5,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Source="{Binding IconSource}" />
<Label Grid.Column="1" Text="{Binding Title}" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>

A página consiste em uma ListView populada com os dados em XAML definindo sua propriedade ItemsSource
como uma matriz de instâncias MasterPageItem . Cada MasterPageItem define propriedades Title , IconSource e
TargetType .

Um DataTemplate é atribuído à propriedade ListView.ItemTemplate , para exibir cada MasterPageItem . O


DataTemplate contém um ViewCell que consiste em um Image e em um Label . O Image exibe o valor da
propriedade IconSource , e o Label exibe o valor da propriedade Title , para cada MasterPageItem .
A página tem seu conjunto de propriedades Title e Icon . O ícone será exibido na página de detalhes, desde que
ela tenha uma barra de título. Isso deve ser habilitado no iOS encapsulando a instância da página de detalhes em
uma instância NavigationPage .

NOTE
A página MasterDetailPage.Master deve ter a propriedade Title definida ou ocorrerá uma exceção.

O exemplo de código a seguir mostra a página equivalente criada em C#:


public class MasterPageCS : ContentPage
{
public ListView ListView { get { return listView; } }

ListView listView;

public MasterPageCS ()
{
var masterPageItems = new List<MasterPageItem> ();
masterPageItems.Add (new MasterPageItem {
Title = "Contacts",
IconSource = "contacts.png",
TargetType = typeof(ContactsPageCS)
});
masterPageItems.Add (new MasterPageItem {
Title = "TodoList",
IconSource = "todo.png",
TargetType = typeof(TodoListPageCS)
});
masterPageItems.Add (new MasterPageItem {
Title = "Reminders",
IconSource = "reminders.png",
TargetType = typeof(ReminderPageCS)
});

listView = new ListView {


ItemsSource = masterPageItems,
ItemTemplate = new DataTemplate (() => {
var grid = new Grid { Padding = new Thickness(5, 10) };
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(30) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Star });

var image = new Image();


image.SetBinding(Image.SourceProperty, "IconSource");
var label = new Label { VerticalOptions = LayoutOptions.FillAndExpand };
label.SetBinding(Label.TextProperty, "Title");

grid.Children.Add(image);
grid.Children.Add(label, 1, 0);

return new ViewCell { View = grid };


}),
SeparatorVisibility = SeparatorVisibility.None
};

Icon = "hamburger.png";
Title = "Personal Organiser";
Content = new StackLayout
{
Children = { listView }
};
}
}

As capturas de tela a seguir mostram a página mestra em cada plataforma:


Criação e exibição da página de detalhes
A instância MasterPage contém uma propriedade ListView que expõe a instância ListView para que a instância
MainPage MasterDetailPage possa registrar um manipulador de eventos para manipular o evento ItemSelected .
Isso permite que a instância MainPage defina a propriedade Detail como a página que representa o item
ListView selecionado. O exemplo de código a seguir mostra o manipulador de eventos:

public partial class MainPage : MasterDetailPage


{
public MainPage ()
{
...
masterPage.listView.ItemSelected += OnItemSelected;
}

void OnItemSelected (object sender, SelectedItemChangedEventArgs e)


{
var item = e.SelectedItem as MasterPageItem;
if (item != null) {
Detail = new NavigationPage ((Page)Activator.CreateInstance (item.TargetType));
masterPage.listView.SelectedItem = null;
IsPresented = false;
}
}
}

O método OnItemSelected executa as seguintes ações:


Ele recupera o SelectedItem da instância ListView e, contanto que não seja null , define a página de detalhes
como uma nova instância do tipo de página armazenado na propriedade TargetType do MasterPageItem . O
tipo de página é encapsulado em uma instância NavigationPage para garantir que o ícone referenciado por
meio da propriedade Icon no MasterPage seja mostrado na página de detalhes no iOS.
O item selecionado no ListView é definido como null para garantir que nenhum dos itens ListView serão
selecionados na próxima vez em que o MasterPage for apresentado.
A página de detalhes é apresentada ao usuário definindo a propriedade MasterDetailPage.IsPresented como
false . Esta propriedade controla se a página mestra ou de detalhes é apresentada. Ela deve ser definida como
true para exibir a página mestra e como false para exibir a página de detalhes.

As capturas de tela a seguir mostram a página de detalhes ContactPage , mostrada depois que ela for selecionada
na página mestra:

Controle do comportamento de exibição da página de detalhes


A maneira como o MasterDetailPage gerencia as páginas mestras e de detalhes depende se o aplicativo está em
execução em um telefone ou tablet, da orientação do dispositivo e do valor da propriedade MasterBehavior . Essa
propriedade determina como a página de detalhes será exibida. Os valores possíveis são:
Default – as páginas são exibidas usando o padrão da plataforma.
Popover – a página de detalhes cobre ou cobre parcialmente a página mestra.
Split – a página mestra é exibida à esquerda e a página de detalhes está à direita.
SplitOnLandscape – Uma tela dividida é usada quando o dispositivo está na orientação paisagem.
SplitOnPortrait – Uma tela dividida é usada quando o dispositivo está na orientação retrato.
O exemplo de código XAML a seguir demonstra como definir a propriedade MasterBehavior em um
MasterDetailPage :
<?xml version="1.0" encoding="UTF-8"?>
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MasterDetailPageNavigation.MainPage"
MasterBehavior="Popover">
...
</MasterDetailPage>

O seguinte exemplo de código mostra a MasterDetailPage equivalente criada em C#:

public class MainPageCS : MasterDetailPage


{
MasterPageCS masterPage;

public MainPageCS ()
{
MasterBehavior = MasterBehavior.Popover;
...
}
}

Contudo, o valor da propriedade MasterBehavior afeta apenas aplicativos em execução em tablets ou na área de
trabalho. Aplicativos em execução nos telefones sempre têm o comportamento Popover.

Resumo
Este artigo demonstrou como usar uma MasterDetailPage e navegar entre suas páginas de informações. O
MasterDetailPage do Xamarin.Forms é uma página que gerencia duas páginas de informações relacionadas – uma
página mestra que apresenta itens e uma página de detalhes que apresenta detalhes sobre os itens na página
mestra.

Links relacionados
Variedades de página
MasterDetailPage (exemplo)
MasterDetailPage
Páginas modais do Xamarin.Forms
12/04/2019 • 12 minutes to read • Edit Online

Baixar o exemplo
O Xamarin.Forms dá suporte a páginas modais. Uma página modal incentiva os usuários a concluir uma tarefa
independente da qual não se pode sair via navegação até que essa tarefa seja concluída ou cancelada. Este artigo
demonstra como navegar até as páginas modais.
Este artigo aborda os seguintes tópicos:
Executar a navegação – enviar páginas por push para a pilha modal, remover páginas da pilha modal,
desabilitar o botão Voltar e animar transições de página.
Passar dados ao navegar – passar dados por meio de um construtor de página e de um BindingContext .

Visão geral
Uma página restrita pode ser qualquer um dos tipos de Página para os quais o Xamarin.Forms dá suporte. Para
exibir uma página modal, o aplicativo a enviará por push para a pilha modal, na qual ela se tornará a página ativa,
conforme mostrado no diagrama a seguir:

Para retornar à página anterior, o aplicativo removerá a página atual da pilha modal e, em seguida, a nova página
de nível superior se tornará a página ativa, conforme mostrado no diagrama a seguir:

Executando a navegação
Os métodos de navegação modal são expostos pela propriedade Navigation em quaisquer tipos derivados de
Page . Esses métodos possibilitam enviar páginas modais por push para a pilha modal e remover páginas modais
da pilha modal.
A propriedade Navigation também expõe uma propriedade ModalStack da qual as páginas modais na pilha
modal podem ser obtidas. No entanto, não há nenhum conceito de realização de manipulação de pilha modal ou
remoção do item mais recente da pilha até a página raiz na navegação modal. Isso ocorre porque não há suporte
universal para essas operações pelas plataformas subjacentes.

NOTE
Uma instância de NavigationPage não é necessária para executar a navegação de página modal.

Enviando páginas por push para a pilha modal


Para navegar até o ModalPage , é necessário invocar o método PushModalAsync na propriedade Navigation da
página atual, conforme demonstrado no exemplo de código a seguir:

async void OnItemSelected (object sender, SelectedItemChangedEventArgs e)


{
if (listView.SelectedItem != null) {
var detailPage = new DetailPage ();
...
await Navigation.PushModalAsync (detailPage);
}
}

Isso faz com que a instância de ModalPage seja enviada por push para a pilha modal, na qual ela se torna a página
ativa, desde que um item tenha sido selecionado no ListView na instância de MainPage . A instância de ModalPage
é mostrada nas capturas de tela a seguir:

Quando PushModalAsync é invocado, os seguintes eventos ocorrem:


A página que chama PushModalAsync tem sua substituição de OnDisappearing invocada, desde que a
plataforma subjacente não seja o Android.
A página para a qual o usuário está navegando tem sua substituição OnAppearing invocada.
A tarefa PushAsync é concluída.

No entanto, a ordem exata em que esses eventos ocorrem depende da plataforma. Para obter mais informações,
confira o Capítulo 24 do livro de Charles Petzold sobre Xamarin.Forms.

NOTE
Chamadas para as substituições OnDisappearing e OnAppearing não podem ser tratadas como indicações garantidas de
navegação de página. Por exemplo, no iOS, a substituição OnDisappearing é chamada na página ativa quando o aplicativo
é encerrado.

Removendo páginas da pilha modal


A página ativa pode ser removida como o item mais recente da pilha modal pressionando o botão Voltar no
dispositivo, independentemente de este ser um botão físico no dispositivo ou um botão na tela.
Para retornar programaticamente à página original, a instância ModalPage deve invocar o método PopModalAsync ,
conforme demonstrado no exemplo de código a seguir:
async void OnDismissButtonClicked (object sender, EventArgs args)
{
await Navigation.PopModalAsync ();
}

Isso faz com que a instância ModalPage seja removida da pilha modal, com a nova página de nível superior
tornando-se a página ativa. Quando PopModalAsync é invocado, os seguintes eventos ocorrem:
A página que chama PopModalAsync tem sua substituição OnDisappearing invocada.
A página para a qual o usuário está voltando tem sua substituição de OnAppearing invocada, desde que a
plataforma subjacente não seja o Android.
A tarefa PopModalAsync é retornada.
No entanto, a ordem exata em que esses eventos ocorrem depende da plataforma. Para obter mais informações,
confira o Capítulo 24 do livro de Charles Petzold sobre Xamarin.Forms.
Desabilitando o botão Voltar
No Android, o usuário sempre pode retornar à página anterior pressionando o botão Voltar padrão no dispositivo.
Se a página modal exigir que o usuário conclua uma tarefa independente antes de sair da página, o aplicativo
deverá desabilitar o botão Voltar. Isso pode ser feito substituindo o método Page.OnBackButtonPressed na página
modal. Para obter mais informações, confira o Capítulo 24 do livro de Charles Petzold sobre Xamarin.Forms.
Animando transições de página
A propriedade Navigation de cada página também fornece métodos de envio por push e remoção substituídos
que incluem um parâmetro boolean que controla se deve ser exibida uma animação de página durante a
navegação, conforme mostrado no código de exemplo a seguir:

async void OnNextPageButtonClicked (object sender, EventArgs e)


{
// Page appearance not animated
await Navigation.PushModalAsync (new DetailPage (), false);
}

async void OnDismissButtonClicked (object sender, EventArgs args)


{
// Page appearance not animated
await Navigation.PopModalAsync (false);
}

Definir o parâmetro boolean como false desabilita a animação de transição de página, enquanto definir o
parâmetro como true habilita a animação de transição de página, desde que ela tenha suporte da plataforma
subjacente. No entanto, os métodos de envio por push e remoção que não têm esse parâmetro habilitam a
animação por padrão.

Transmitindo dados ao navegar


Às vezes, é necessário que uma página transmita dados para outra página durante a navegação. Duas técnicas
para fazer isso são transmitir dados por meio de um construtor de página e definir o BindingContext como os
dados. Descreveremos cada técnica separadamente.
Transmitindo dados por meio de um construtor de página
A técnica mais simples para transmitir dados para outra página durante a navegação é por meio de um parâmetro
de construtor de página, que é mostrado no exemplo de código a seguir:
public App ()
{
MainPage = new MainPage (DateTime.Now.ToString ("u")));
}

Esse código cria uma instância de MainPage , transmitindo a data e a hora atuais no formato ISO8601.
A instância de MainPage recebe os dados por meio de um parâmetro de construtor, conforme mostrado no
exemplo de código a seguir:

public MainPage (string date)


{
InitializeComponent ();
dateLabel.Text = date;
}

Em seguida, os dados são exibidos na página definindo a propriedade Label.Text .


Transmitindo dados por meio de um BindingContext
Outra abordagem para transmitir dados para outra página durante a navegação é definir o BindingContext da
nova página como os dados, conforme mostrado no exemplo de código a seguir:

async void OnItemSelected (object sender, SelectedItemChangedEventArgs e)


{
if (listView.SelectedItem != null) {
var detailPage = new DetailPage ();
detailPage.BindingContext = e.SelectedItem as Contact;
listView.SelectedItem = null;
await Navigation.PushModalAsync (detailPage);
}
}

Esse código define o BindingContext da instância de DetailPage como a instância de Contact e, em seguida,
navega para o DetailPage .
O DetailPage , em seguida, usa a associação de dados para exibir os dados da instância de Contact , conforme
mostrado no exemplo de código XAML a seguir:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ModalNavigation.DetailPage">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="0,40,0,0" />
</OnPlatform>
</ContentPage.Padding>
<ContentPage.Content>
<StackLayout HorizontalOptions="Center" VerticalOptions="Center">
<StackLayout Orientation="Horizontal">
<Label Text="Name:" FontSize="Medium" HorizontalOptions="FillAndExpand" />
<Label Text="{Binding Name}" FontSize="Medium" FontAttributes="Bold" />
</StackLayout>
...
<Button x:Name="dismissButton" Text="Dismiss" Clicked="OnDismissButtonClicked" />
</StackLayout>
</ContentPage.Content>
</ContentPage>

O exemplo de código a seguir mostra como a associação de dados pode ser feita em C#:
public class DetailPageCS : ContentPage
{
public DetailPageCS ()
{
var nameLabel = new Label {
FontSize = Device.GetNamedSize (NamedSize.Medium, typeof(Label)),
FontAttributes = FontAttributes.Bold
};
nameLabel.SetBinding (Label.TextProperty, "Name");
...
var dismissButton = new Button { Text = "Dismiss" };
dismissButton.Clicked += OnDismissButtonClicked;

Thickness padding;
switch (Device.RuntimePlatform)
{
case Device.iOS:
padding = new Thickness(0, 40, 0, 0);
break;
default:
padding = new Thickness();
break;
}

Padding = padding;
Content = new StackLayout {
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center,
Children = {
new StackLayout {
Orientation = StackOrientation.Horizontal,
Children = {
new Label{ Text = "Name:", FontSize = Device.GetNamedSize (NamedSize.Medium, typeof(Label)),
HorizontalOptions = LayoutOptions.FillAndExpand },
nameLabel
}
},
...
dismissButton
}
};
}

async void OnDismissButtonClicked (object sender, EventArgs args)


{
await Navigation.PopModalAsync ();
}
}

Em seguida, os dados são exibidos na página por uma série de controles de Label .
Para obter mais informações sobre vinculação de dados, veja Noções básicas de vinculação de dados.

Resumo
Este artigo demonstrou como navegar até as páginas modais. Uma página modal incentiva os usuários a concluir
uma tarefa independente da qual não se pode sair via navegação até que essa tarefa seja concluída ou cancelada.

Links relacionados
Navegação da página
Modal (amostra)
PassingData (amostra)
Exibindo pop-ups
12/04/2019 • 4 minutes to read • Edit Online

Baixar o exemplo
O Xamarin.Forms fornece dois elementos de interface do usuário semelhantes a pop -up: um alerta e uma folha de
ações. Este artigo demonstra como usar as APIs de folha de alerta e de ação para fazer perguntas simples para os
usuários e orientá -los em suas tarefas.
Exibir um alerta ou pedir que um usuário faça uma escolha é uma tarefa comum da interface do usuário. O
Xamarin.Forms tem dois métodos na classe Page para interagir com o usuário por meio de um pop-up:
DisplayAlert e DisplayActionSheet . Eles são renderizados com os controles nativos apropriados em cada
plataforma.

Exibindo um alerta
Todas as plataformas com suporte do Xamarin.Forms têm um pop-up modal para alertar o usuário ou fazer
perguntas simples a ele. Para exibir esses alertas no Xamarin.Forms, use o método DisplayAlert em qualquer
Page . A linha de código a seguir mostra uma mensagem simples para o usuário:

DisplayAlert ("Alert", "You have been alerted", "OK");

Este exemplo não coleta informações do usuário. O alerta é exibido de forma modal e, após descartado, o usuário
continua interagindo com o aplicativo.
O método DisplayAlert também pode ser usado para capturar a resposta do usuário apresentando dois botões e
retornando um boolean . Para obter uma resposta a um alerta, forneça texto para os dois botões e para o método
await . Após o usuário selecionar uma das opções, a resposta será retornada ao seu código. Observe as palavras-
chave async e await no código de exemplo abaixo:
async void OnAlertYesNoClicked (object sender, EventArgs e)
{
bool answer = await DisplayAlert ("Question?", "Would you like to play a game", "Yes", "No");
Debug.WriteLine ("Answer: " + answer);
}

Orientando usuários em tarefas


A UIActionSheet é um elemento de interface do usuário comum no iOS. O método DisplayActionSheet do
Xamarin.Forms permite que você inclua esse controle em aplicativos de plataforma cruzada, renderizando
alternativas nativas no Android e na UWP.
Para exibir uma folha de ação, await DisplayActionSheet em qualquer Page , passando a mensagem e os rótulos
do botão como cadeias de caracteres. O método retorna o rótulo de cadeia de caracteres do botão que foi clicado
pelo usuário. Um exemplo simples é mostrado aqui:

async void OnActionSheetSimpleClicked (object sender, EventArgs e)


{
string action = await DisplayActionSheet ("ActionSheet: Send to?", "Cancel", null, "Email", "Twitter",
"Facebook");
Debug.WriteLine ("Action: " + action);
}

O botão destroy é renderizado de forma diferente dos outros e pode ser deixado como null ou ser especificado
como o terceiro parâmetro de cadeia de caracteres. O exemplo a seguir usa o botão destroy :

async void OnActionSheetCancelDeleteClicked (object sender, EventArgs e)


{
string action = await DisplayActionSheet ("ActionSheet: SavePhoto?", "Cancel", "Delete", "Photo Roll",
"Email");
Debug.WriteLine ("Action: " + action);
}
Resumo
Este artigo demonstrou como usar as APIs de folha de alerta e de ação para fazer perguntas simples para os
usuários e orientá-los em suas tarefas. O Xamarin.Forms tem dois métodos na classe Page para interagir com o
usuário por meio de um pop-up: DisplayAlert e DisplayActionSheet , e ambos são renderizados com os controles
nativos apropriados em cada plataforma.

Links relacionados
PopupsSample
Shell do Xamarin.Forms
12/04/2019 • 16 minutes to read • Edit Online

Baixar o exemplo
O Shell do Xamarin.Forms é um contêiner para aplicativos, que fornece os recursos fundamentais da interface do
usuário que a maioria dos aplicativos exige, permitindo que você se concentre na carga de trabalho principal do
aplicativo. Os aplicativos do Shell são fornecidos com a seguinte funcionalidade:
Um único lugar para descrever a estrutura visual de um aplicativo.
Uma interface do usuário de navegação comum.
Um serviço de navegação com vinculação profunda.
Um manipulador de pesquisa integrado.
Essa funcionalidade reduz a complexidade dos aplicativos e aumenta a produtividade do desenvolvedor. Além
disso, o Shell é gravado considerando a renderização do consumo de memória e de velocidade.

IMPORTANT
Os aplicativos iOS e Android existentes podem adotar o Shell e beneficiar-se imediatamente das melhorias de navegação,
desempenho e extensibilidade.

O Shell fornece uma interface do usuário de navegação "pretensiosa", com base em guias e submenus. O nível
superior da navegação em um aplicativo do Shell é um submenu:
O próximo nível de navegação é a barra de guias inferior:

Quando o submenu não estiver aberto, a barra de guias inferior será considerada o nível superior do painel de
navegação
Em cada guia inferior, o próximo nível de navegação é a barra de guias superior, em que cada guia é uma
ContentPage :
Dentro de cada ContentPage , instâncias de ContentPage adicionais podem ser adicionadas e removidas da pilha de
navegação.

Inicializando um aplicativo do Shell


Um aplicativo do Shell é inicializado definindo a propriedade MainPage da classe App para uma instância de um
arquivo Shell:

namespace TailwindTraders.Mobile
{
public partial class App : Application
{
public App()
{
InitializeComponent();

MainPage = new TheShell();


}
}
}

A classe TheShell é um arquivo XAML que descreve a estrutura visual do aplicativo.

IMPORTANT
O Shell é experimental no momento e só pode ser usado com a adição de Forms.SetFlags("Shell_Experimental"); ao
projeto de plataforma, antes da invocação do método Forms.Init .

Android
iOS
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
global::Xamarin.Forms.Forms.SetFlags("Shell_Experimental");

TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;

base.OnCreate(savedInstanceState);

global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}
}

Hierarquia de arquivos do Shell


Um arquivo do Shell consiste em três elementos hierárquicos:
ShellItem . Um ou mais itens no submenu. Cada ShellItem é um filho de um Shell .
ShellSection . Conteúdo agrupado, navegável pelas guias inferiores. Cada ShellSection é um filho de um
ShellItem .
ShellContent . As instâncias de ContentPage no aplicativo, que são navegáveis pelas guias superiores. Cada
ShellContent é um filho de uma ShellSection .

Nenhum desses elementos representa uma interface do usuário, mas sim a organização da estrutura visual do
aplicativo. O Shell usará esses elementos e produzirá a interface do usuário de navegação do conteúdo.
O XAML a seguir mostra um exemplo simples de um arquivo Shell:

<Shell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:TailwindTraders.Mobile.Features.Shell"
x:Class="TailwindTraders.Mobile.Features.Shell.TheShell"
Title="TailwindTraders">
<ShellItem Title="Home">
<ShellSection>
<ShellContent>
<local:HomePage />
</ShellContent>
</ShellSection>
</ShellItem>
</Shell>

NOTE
Cada ShellItem também pode definir uma propriedade FlyoutIcon para um ImageSource , que será exibido à esquerda
do título.

Esse XAML exibe a HomePage , pois esse é o primeiro item de conteúdo declarado no arquivo do Shell:
Quando o botão de hambúrguer é pressionado, o menu suspenso é exibido:

O número de itens no submenu pode ser aumentado com a adição de mais instâncias de ShellItem ao arquivo do
Shell. No entanto, observe que HomePage é criado durante a inicialização do aplicativo, e a adição de mais
instâncias de ShellItem usando essa abordagem fará com que essas páginas também sejam criadas durante a
inicialização do aplicativo. Isso pode ser evitado definindo a propriedade ShellContent.ContentTemplate para um
DataTemplate :
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:TailwindTraders.Mobile.Features.Shell"
x:Class="TailwindTraders.Mobile.Features.Shell.TheShell"
Title="TailwindTraders">
<ShellItem Title="Home">
<ShellSection>
<ShellContent>
<local:HomePage />
</ShellContent>
</ShellSection>
<ShellItem>
<ShellContent Title="Profile"
ContentTemplate="{DataTemplate local:ProfilePage}" />
</Shell>

Com essa abordagem, a ProfilePage é criada somente quando o usuário navega para ela e não na inicialização do
aplicativo. Além disso, observe que para a ProfilePage , os objetos ShellItem e ShellSection são omitidos, e a
propriedade Title é definida na instância de ShellContent . Essa abordagem concisa requer menos marcação
com o Shell fornecendo os wrappers lógicos necessários (sem introduzir exibições adicionais à árvore visual).
Além disso, a aparência de cada ShellItem pode ser personalizada definindo a propriedade Shell.ItemTemplate
para um DataTemplate :

<Shell.ItemTemplate>
<DataTemplate>
<ContentView HeightRequest="32">
<ContentView.Padding>
<Thickness Left="32"
Top="16" />
</ContentView.Padding>
<Label Text="{Binding Title}" />
</ContentView>
</DataTemplate>
</Shell.ItemTemplate>

Esse código simplesmente reposiciona o texto para cada ShellItem dentro do submenu. Observe que o Shell
fornece as propriedades Title (e Icon ) para o BindingContext do DataTemplate .

Submenu
O submenu é o menu raiz do aplicativo e consiste em um cabeçalho de submenu e em itens de menu:
Comportamento do submenu
O submenu por ser acessado pelo botão de hambúrguer ou passando o dedo na lateral tela. No entanto, esse
comportamento pode ser alterado definindo a propriedade Shell.FlyoutBehavior para um dos membros da
enumeração FlyoutBehavior :

<Shell ...
FlyoutBehavior="Disabled">
...
</Shell>

A definição da propriedade FlyoutBehavior para Disabled oculta o submenu, o que é útil quando há apenas um
ShellItem . Outros valores válidos de FlyoutBehavior são Flyout (padrão) e Locked .

Cabeçalho do submenu
O cabeçalho do submenu é o conteúdo que é exibido, opcionalmente, na parte superior do submenu, com sua
aparência definida por uma View que pode ser configurada por meio do valor da propriedade Shell.FlyoutHeader
:

<Shell.FlyoutHeader>
<local:FlyoutHeader />
</Shell.FlyoutHeader>

Como alternativa, a aparência do cabeçalho do submenu pode ser definida configurando a propriedade
Shell.FlyoutHeaderTemplate para um DataTemplate :
<Shell.FlyoutHeaderTemplate>
<DataTemplate>
<StackLayout HorizontalOptions="Fill"
VerticalOptions="Fill"
BackgroundColor="White"
Padding="16">
<Label FontSize="Medium"
Text="Smart Shopping">
<Label.Margin>
<Thickness Left="8" />
</Label.Margin>
</Label>
<Button Image="photo"
Text="By taking a photo">
<Button.Margin>
<Thickness Top="16" />
</Button.Margin>
</Button>
<Button Image="ia"
Text="By using AR">
<Button.Margin>
<Thickness Top="8" />
</Button.Margin>
</Button>
</StackLayout>
</DataTemplate>
</Shell.FlyoutHeaderTemplate>

Esse XAML resulta no cabeçalho de submenu a seguir:

Por padrão, o cabeçalho do submenu ficará fixo no submenu enquanto o conteúdo abaixo poderá ser rolado se
houver itens suficientes. No entanto, esse comportamento pode ser alterado definindo a propriedade
Shell.FlyoutHeaderBehavior para um dos membros da enumeração FlyoutHeaderBehavior :

<Shell ...
FlyoutHeaderBehavior="CollapseOnScroll">
...
</Shell>

A definição do FlyoutHeaderBehavior para CollapseOnScroll recolhe o submenu conforme a rolagem ocorre. Os


outros valores válidos de FlyoutHeaderBehavior são Default , Fixed e Scroll (rolar com os itens de menu).

Itens de menu
O número de itens no submenu pode ser aumentado adicionando mais instâncias de ShellItem . No entanto,
também é possível adicionar instâncias de MenuItem no menu suspenso. Isso permite cenários como a navegação
até uma página idêntica passando dados por meio da propriedade MenuItem.CommandParameter .
As instâncias de MenuItem devem ser adicionadas à coleção Shell.MenuItems :

<Shell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:TailwindTraders.Views"
x:Class="TailwindTraders.Shell"
FlyoutHeaderBehavior="Fixed"
Title="Tailwind Traders"
...>
<Shell.MenuItems>
<MenuItem Command="{Binding ProductTypeCommand}"
CommandParameter="1"
Text="Holiday decorations" />
<MenuItem Command="{Binding ProductTypeCommand}"
CommandParameter="2"
Text="Appliances" />
<MenuItem Command="{Binding ProductTypeCommand}"
CommandParameter="3"
Text="Bathrooms" />
...
</Shell.MenuItems>
<ShellItem Title="Home">
<ShellSection>
<ShellContent>
<local:HomePage />
</ShellContent>
</ShellSection>
</ShellItem>
</Shell>

NOTE
Cada MenuItem também pode definir uma propriedade Icon para uma FileImageSource , que será exibida à esquerda
do texto.

Esse XAML resulta no submenu a seguir:


Além disso, a aparência do MenuItem pode ser personalizada definindo a propriedade Shell.MenuItemTemplate
para um DataTemplate :

<Shell.MenuItemTemplate>
<DataTemplate>
<ContentView HeightRequest="32">
<ContentView.Padding>
<Thickness Left="32"
Top="16" />
</ContentView.Padding>
<Label Text="{Binding Text}"
FontAttributes="Bold" />
</ContentView>
</DataTemplate>
</Shell.MenuItemTemplate>

Isso resulta em instâncias de MenuItem com o texto renderizado em negrito:


Tabulações
As instâncias de ShellSection serão renderizadas como guias inferiores, desde que haja várias instâncias de
ShellSection em um único ShellItem :

<ShellItem Title="Bottom Tab Sample"


Style="{StaticResource BaseStyle}">
<ShellSection Title="AR" Icon="ia.png">
<ShellContent ContentTemplate="{DataTemplate local:ARPage}"/>
</ShellSection>
<ShellSection Title="Photo" Icon="photo.png">
<ShellContent ContentTemplate="{DataTemplate local:PhotoPage}"/>
</ShellSection>
</ShellItem>

Neste exemplo, as instâncias de ShellSection serão renderizadas como guias inferiores:

Os itens serão renderizados como guias superiores, desde que haja várias instâncias de
ShellContent
ShellContent em uma única ShellSection :
<ShellItem Title="Store Home"
Shell.TitleView="Store Home"
Style="{StaticResource BaseStyle}">
<ShellSection Title="Browse Product">
<ShellContent Title="Featured"
ContentTemplate="{DataTemplate local:FeaturedPage}" />
<ShellContent Title="On Sale"
ContentTemplate="{DataTemplate local:SalePage}" />
</ShellSection>
</ShellItem>

Neste exemplo, as instâncias de ShellContent serão renderizadas como guias superiores:

As guias podem ser estilizadas usando estilos XAML ou fornecendo um renderizador personalizado. Por exemplo,
o exemplo a seguir mostra um estilo XAML que define a cor da guia:

<Style x:Key="BaseStyle"
TargetType="Element">
<Setter Property="Shell.ShellTabBarBackgroundColor"
Value="#3498DB" />
<Setter Property="Shell.ShellTabBarTitleColor"
Value="White" />
<Setter Property="Shell.ShellTabBarUnselectedColor"
Value="#B4FFFFFF" />
</Style>

Navegação
O Shell inclui uma experiência de navegação baseada em URI. Os URIs fornecem uma experiência de navegação
aprimorada que permite a navegação para qualquer página no aplicativo, sem precisar seguir uma hierarquia de
navegação definida. Além disso, eles também oferecem a capacidade de navegar para trás, sem precisar visitar
todas as páginas na pilha de navegação.
Essa navegação baseada em URI é realizada com rotas, que são segmentos de URI usados para navegar dentro do
aplicativo. O arquivo Shell deve declarar um esquema de rota, um host de rota e uma rota:

<Shell ...
Route="tailwindtraders"
RouteHost="www.microsoft.com"
RouteScheme="app">
...
</Shell>

Combinados, os valores de propriedade RouteScheme , RouteHost e Route formam o URI raiz de


app://www.microsoft.com/tailwindtraders .
Cada elemento no arquivo Shell também pode definir uma propriedade de rota que pode ser usada na navegação
programática.
No construtor do arquivo Shell ou em qualquer outro local que seja executado antes da invocação de uma rota, é
possível registrar explicitamente rotas adicionais para todas as páginas que não sejam representadas por um
elemento do Shell (como instâncias de MenuItem ):
Routing.RegisterRoute("productcategory", typeof(ProductCategoryPage));

Implementando a navegação
Os itens de menu expõem uma propriedade Command que pode ser usada para implementar a navegação:

public ICommand ProductTypeCommand { get; } = new Command<string>(NavigateToProductType);

static void NavigateToProductType(string typeId)


{
(App.Current.MainPage as Xamarin.Forms.Shell).GoToAsync($"app://tailwindtraders/productcategory?id=
{typeId}", true);
}

Para invocar a navegação, é necessário obter uma referência ao aplicativo Shell por meio da propriedade
MainPage da classe Application . Em seguida, a navegação poderá ser invocada ao chamar o método GoToAsync
passando um URI válido como um argumento. O método GoToAsync navega usando um objeto
ShellNavigationState , que será construído usando uma string ou um Uri .

Passando dados
Os dados podem ser passados entre as páginas por meio de parâmetros de cadeia de consulta. O Shell definirá os
valores dos parâmetros de cadeia de consulta na ContentPage ou no ViewModel quando você adicionar atributos
de propriedade de consulta à classe:

[QueryProperty("TypeID", "id")]
public partial class ProductCategoryPage : ContentPage
{
private string _typeId;

public ProductCategoryPage()
{
InitializeComponent();

BindingContext = new ProductCategoryViewModel();


}

public string TypeID


{
get => _typeId;
set => MyLabel.Text = value;
}
}

O atributo QueryProperty especifica que o TypeID receberá os dados passados no parâmetro de cadeia de
consulta id do URI na chamada de método GoToAsync .
Interceptando a navegação
O Shell fornece a capacidade de interceptar o roteamento de navegação antes que ele seja concluído e após sua
conclusão. Isso pode ser feito registrando manipuladores de eventos para os eventos Navigating e Navigated ,
respectivamente:

<Shell ...
Navigating="OnShellNavigating">
...
</Shell>
void OnShellNavigating(object sender, ShellNavigatingEventArgs e)
{
if (...)
{
e.Cancel(); // Cancel the navigation
}
}

A classe ShellNavigatingEventArgs fornece as seguintes propriedades:

PROPRIEDADE TIPO DESCRIÇÃO

Atual ShellNavigationState O URI da página atual.

Origem ShellNavigationState O URI que representa onde a


navegação foi originada.

Destino ShellNavigationSource O URI que representa para onde a


navegação se destina.

CanCancel bool Um valor que indica se é possível


cancelar a navegação.

Cancelada bool Um valor que indica se a navegação foi


cancelada.

Além disso, a classe ShellNavigatingEventArgs fornece um método Cancel .


A classe ShellNavigatedEventArgs fornece as seguintes propriedades:

PROPRIEDADE TIPO DESCRIÇÃO

Atual ShellNavigationState O URI da página atual.

Voltar ShellNavigationState O URI da página anterior.

Origem ShellNavigationSource O URI que representa onde a


navegação foi originada.

Além disso, o Shell fornece um método OnBackButtonPressed substituível que pode ser usado para interceptar um
pressionamento do botão de retorno.

Links relacionados
Tailwind Traders (exemplo)
Modelos do Xamarin.Forms
12/04/2019 • 2 minutes to read • Edit Online

Modelos de controle
Os modelos de controle do Xamarin.Forms fornecem a capacidade de tematizar e tematizar novamente páginas de
aplicativo em tempo de execução.

Modelos de dados
Os modelos de dados do Xamarin.Forms fornecem a capacidade de definir a apresentação de dados em controles
compatíveis.
Modelos de Controle do Xamarin.Forms
12/04/2019 • 2 minutes to read • Edit Online

Modelos de controle fornecem uma separação clara entre a aparência de uma página e seu conteúdo,
permitindo a criação de páginas cujo tema pode ser definido facilmente.

Introdução
Os modelos de controle do Xamarin.Forms fornecem a capacidade de tematizar e tematizar novamente páginas
de aplicativo em tempo de execução. Este artigo fornece uma introdução a modelos de controle.

Criando um ControlTemplate
Modelos de controle podem ser definidos no nível do aplicativo ou no nível da página. Este artigo demonstra
como criar e consumir modelos de controle.

Associando de um ControlTemplate
Associações do modelo permitem que os controles em um modelo de controle associem dados a propriedades
públicas, permitindo que os valores de propriedade em controles no modelo de controle sejam alterados
facilmente. Este artigo demonstra como usar associações de modelo para realizar a associação de dados de um
modelo de controle.
Introdução aos modelos de controle do
Xamarin.Forms
12/04/2019 • 6 minutes to read • Edit Online

Os modelos de controle do Xamarin.Forms fornecem a capacidade de tematizar e tematizar novamente páginas


de aplicativo em tempo de execução. Este artigo fornece uma introdução a modelos de controle.
Os controles têm propriedades diferentes, tais como BackgroundColor e TextColor , que podem definir aspectos da
aparência do controle. Essas propriedades podem ser definidas usando estilos, que pode ser alterado em tempo de
execução para implementar temas básicos. No entanto, os estilos não mantêm uma separação clara entre a
aparência de uma página e seu conteúdo e as alterações que podem ser feitas ao definir essas propriedades são
limitadas.
Os modelos de controle fornecem uma separação clara entre a aparência de uma página e seu conteúdo,
permitindo, portanto, a criação de páginas cujo tema pode ser definido facilmente. Por exemplo, um aplicativo
pode conter modelos de controle de nível de aplicativo que fornecem um tema claro e um escuro. Cada
ContentPage no aplicativo pode ser tematizado aplicando um dos modelos de controle sem alterar o conteúdo que
está sendo exibido por cada página. Além disso, os temas fornecidos pelos modelos de controle não estão
limitados a alterar as propriedades de controles. Eles também podem alterar os controles usados para
implementar o tema.

Criando um ControlTemplate
Um ControlTemplate especifica a aparência de uma página ou de uma exibição e contém um layout raiz e, dentro
do layout, os controles que implementam o modelo. Normalmente, um ControlTemplate utilizará um
ContentPresenter para marcar onde o conteúdo a ser exibido pela página ou pela exibição será exibido. A página
ou a exibição que consome o ControlTemplate definirá o conteúdo a ser exibido pelo ContentPresenter . O
diagrama a seguir ilustra um ControlTemplate para uma página que contém um número de controles, incluindo
um ContentPresenter marcado por um retângulo azul:
Um ControlTemplate pode ser aplicado aos seguintes tipos definindo suas propriedades ControlTemplate :
ContentPage
ContentView
TemplatedPage
TemplatedView

Quando um ControlTemplate é criado e atribuído a esses tipos, qualquer aparência existente é substituída pela
aparência definida no ControlTemplate . Ademais, além de definir a aparência usando a propriedade
ControlTemplate , os modelos de controle também podem ser aplicados usando estilos para expandir ainda mais a
capacidade do tema.

NOTE
O que são os tipos TemplatedPage e TemplatedView ? TemplatedPage é a classe base para ContentPage e é o tipo de
página mais básico fornecido pelo Xamarin.Forms. Diferentemente de ContentPage , TemplatedPage não tem uma
propriedade Content . Portanto, o conteúdo não pode ser diretamente adicionado a uma instância TemplatedPage . Em vez
disso, o conteúdo é adicionado, definindo o modelo de controle para a instância TemplatedPage . De maneira semelhante,
TemplatedView é a classe base para ContentView . Diferentemente de ContentView , TemplatedView não tem uma
propriedade Content . Portanto, o conteúdo não pode ser diretamente adicionado a uma instância TemplatedView . Em vez
disso, o conteúdo é adicionado, definindo o modelo de controle para a instância TemplatedView .

Os modelos de controle podem ser criados em XAML e em C#:


Os modelos de controle criados em XAML são definidos em um ResourceDictionary atribuído à coleção
Resources de uma página ou mais normalmente à coleção Resources do aplicativo.
Normalmente, os modelos de controle criados em C# são definidos na classe da página ou em uma classe que
pode ser acessada globalmente.
Escolher onde definir uma instância ControlTemplate afeta onde ela pode ser usada:
As instâncias ControlTemplate definidas no nível da página só podem ser aplicadas a ela.
As instâncias ControlTemplate definidas no nível do aplicativo podem ser aplicadas às páginas em todo o
aplicativo.
Os modelos de controle mais baixos na hierarquia de exibição têm precedência sobre os definidos na parte de
cima. Por exemplo, um ControlTemplate denominado DarkTheme definido no nível da página tem precedência
sobre um modelo com o mesmo nome definido no nível do aplicativo. Portanto, um modelo de controle que define
um tema a ser aplicado a cada página em um aplicativo deve ser definido no nível do aplicativo.

Links relacionados
Estilos
ControlTemplate
ContentPresenter
Criando um ControlTemplate
12/04/2019 • 7 minutes to read • Edit Online

Baixar o exemplo
Modelos de controle podem ser definidos no nível do aplicativo ou no nível da página. Este artigo demonstra
como criar e consumir modelos de controle.

Criando um ControlTemplate em XAML


Para definir um ControlTemplate no nível do aplicativo, um ResourceDictionary deve ser adicionado à classe App .
Por padrão, todos os aplicativos do Xamarin.Forms criados de um modelo usam a classe App para implementar a
subclasse Application . Para declarar um ControlTemplate no nível do aplicativo, no ResourceDictionary do
aplicativo usando XAML, a classe App padrão deve ser substituída por uma classe App XAML e pelo code-behind
associado, conforme mostrado no exemplo de código a seguir:

<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="SimpleTheme.App">
<Application.Resources>
<ResourceDictionary>
<ControlTemplate x:Key="TealTemplate">
<Grid>
...
<BoxView ... />
<Label Text="Control Template Demo App"
TextColor="White"
VerticalOptions="Center" ... />
<ContentPresenter ... />
<BoxView Color="Teal" ... />
<Label Text="(c) Xamarin 2016"
TextColor="White"
VerticalOptions="Center" ... />
</Grid>
</ControlTemplate>
<ControlTemplate x:Key="AquaTemplate">
...
</ControlTemplate>
</ResourceDictionary>
</Application.Resources>
</Application>

Cada instância de ControlTemplate é criada como um objeto reutilizável em um ResourceDictionary . Isso é feito
dando a cada declaração um atributo x:Key exclusivo, que fornece a ela uma chave descritiva no
ResourceDictionary .

O exemplo de código a seguir mostra o code-behind do App associado:

public partial class App : Application


{
public App ()
{
InitializeComponent ();
MainPage = new HomePage ();
}
}
Além de configurar a propriedade MainPage , o code-behind também deve chamar o método InitializeComponent
para carregar e analisar o XAML associado.
O exemplo de código a seguir mostra um ContentPage aplicando um TealTemplate ao ContentView :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="SimpleTheme.HomePage">
<ContentView x:Name="contentView" Padding="0,20,0,0"
ControlTemplate="{StaticResource TealTemplate}">
<StackLayout VerticalOptions="CenterAndExpand">
<Label Text="Welcome to the app!" HorizontalOptions="Center" />
<Button Text="Change Theme" Clicked="OnButtonClicked" />
</StackLayout>
</ContentView>
</ContentPage>

O TealTemplate é atribuído à propriedade ContentView.ControlTemplate usando a extensão de marcação


StaticResource . A propriedade ContentView.Content é definida como um StackLayout que define o conteúdo a
ser exibido no ContentPage . Esse conteúdo será exibido pelo ContentPresenter contido no TealTemplate . Isso
resulta na aparência mostrada nas capturas de tela seguir:

Redefinindo o tema de um aplicativo em tempo de execução


Clicar no botão Alterar Tema executa o método OnButtonClicked , que é mostrado no exemplo de código a seguir:

void OnButtonClicked (object sender, EventArgs e)


{
originalTemplate = !originalTemplate;
contentView.ControlTemplate = (originalTemplate) ? tealTemplate : aquaTemplate;
}

Esse método substitui a instância ativa de ControlTemplate pela instância alternativa de ControlTemplate ,
resultando na seguinte captura de tela:
NOTE
Em um ContentPage , a propriedade Content pode ser atribuída e a propriedade ControlTemplate também pode ser
definida. Quando isso ocorre, se o ControlTemplate contiver uma instância de ContentPresenter , o conteúdo atribuído à
propriedade Content será apresentado pelo ContentPresenter dentro do ControlTemplate .

Definindo um ControlTemplate com um estilo


Um ControlTemplate também podem ser aplicado por meio de um Style para expandir ainda mais a
funcionalidade de tema. Isso pode ser feito criando um estilo implícito ou explícito para a exibição de destino em
um ResourceDictionary e definindo a propriedade ControlTemplate da exibição de destino na instância de Style .
O seguinte exemplo de código mostra um estilo implícito que foi adicionado ao nível de aplicativo
ResourceDictionary :

<Style TargetType="ContentView">
<Setter Property="ControlTemplate" Value="{StaticResource TealTemplate}" />
</Style>

Como a instância de Style é implícita, ela será aplicada a todas as instâncias de ContentView no aplicativo.
Portanto, não é mais necessário definir a propriedade ContentView.ControlTemplate , conforme demonstrado no
exemplo de código a seguir:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="SimpleTheme.HomePage">
<ContentView x:Name="contentView" Padding="0,20,0,0">
...
</ContentView>
</ContentPage>

Para mais informações sobre estilos, confira Estilos.


Criando um ControlTemplate no nível da página
Além de criar instâncias de ControlTemplate no nível do aplicativo, elas também podem ser criadas no nível da
página, conforme mostrado no exemplo de código a seguir:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="SimpleTheme.HomePage">
<ContentPage.Resources>
<ResourceDictionary>
<ControlTemplate x:Key="TealTemplate">
...
</ControlTemplate>
<ControlTemplate x:Key="AquaTemplate">
...
</ControlTemplate>
</ResourceDictionary>
</ContentPage.Resources>
<ContentView ... ControlTemplate="{StaticResource TealTemplate}">
...
</ContentView>
</ContentPage>

Ao adicionar um ControlTemplate no nível da página, um ResourceDictionary é adicionado ao ContentPage e, em


seguida, as instâncias de ControlTemplate são incluídas no ResourceDictionary .

Criando um ControlTemplate em C#
Para definir um ControlTemplate no nível do aplicativo, deve ser criado um class que representa o
ControlTemplate . A classe deve derivar do layout que está sendo usado para o modelo, conforme mostrado no
exemplo de código a seguir:

class TealTemplate : Grid


{
public TealTemplate ()
{
...
var contentPresenter = new ContentPresenter ();
Children.Add (contentPresenter, 0, 1);
Grid.SetColumnSpan (contentPresenter, 2);
...
}
}

class AquaTemplate : Grid


{
...
}

A classe AquaTemplate é idêntica à classe TealTemplate , exceto pelo fato de que cores diferentes são usadas para
as propriedades BoxView.Color e Label.TextColor .
O exemplo de código a seguir mostra um ContentPage aplicando um TealTemplate ao ContentView :
public class HomePageCS : ContentPage
{
...
ControlTemplate tealTemplate = new ControlTemplate (typeof(TealTemplate));
ControlTemplate aquaTemplate = new ControlTemplate (typeof(AquaTemplate));

public HomePageCS ()
{
var button = new Button { Text = "Change Theme" };
var contentView = new ContentView {
Padding = new Thickness (0, 20, 0, 0),
Content = new StackLayout {
VerticalOptions = LayoutOptions.CenterAndExpand,
Children = {
new Label { Text = "Welcome to the app!", HorizontalOptions = LayoutOptions.Center },
button
}
},
ControlTemplate = tealTemplate
};
...
Content = contentView;
}
}

As instâncias de ControlTemplate são criadas especificando o tipo das classes que definem os modelos de controle,
no construtor ControlTemplate .
A propriedade ContentView.Content é definida como um StackLayout que define o conteúdo a ser exibido no
ContentPage . Esse conteúdo será exibido pelo ContentPresenter contido no TealTemplate . O mesmo mecanismo
descrito anteriormente é usado para alterar o tema em tempo de execução para o AquaTheme .

Resumo
Este artigo demonstrou como criar e consumir modelos de controle. Modelos de controle podem ser definidos no
nível do aplicativo ou no nível da página.

Links relacionados
Estilos
Tema simples (amostra)
ControlTemplate
ContentPresenter
ContentView
ResourceDictionary
Associação de um ControlTemplate do
Xamarin.Forms
12/04/2019 • 8 minutes to read • Edit Online

Baixar o exemplo
Associações de modelo permitem que os controles em um modelo de controle associem dados a propriedades
públicas, permitindo que os valores de propriedade em controles no modelo de controle sejam alterados
facilmente. Este artigo demonstra como usar associações de modelo para realizar a associação de dados de um
modelo de controle.
Um TemplateBinding é usado para associar a propriedade de um controle em um modelo de controle a uma
propriedade associável no pai da exibição de destino é proprietária do modelo de controle. Por exemplo, em vez
de definir o texto exibido por instâncias de Label dentro do ControlTemplate , você poderia usar uma associação
de modelo para associar a propriedade Label.Text a propriedades vinculáveis que definem o texto a ser exibido.
Um TemplateBindingé semelhante a um Binding existente, exceto pelo fato de que a origem de um
TemplateBinding sempre é definida automaticamente como pai da exibição de destino que é proprietária do
modelo de controle. No entanto, observe que não há suporte para usar um TemplateBinding fora de um
ControlTemplate .

Criando um TemplateBinding em XAML


Em XAML, um TemplateBinding é criado usando a extensão de marcação TemplateBinding , conforme
demonstrado no exemplo de código a seguir:

<ControlTemplate x:Key="TealTemplate">
<Grid>
...
<Label Text="{TemplateBinding Parent.HeaderText}" ... />
...
<Label Text="{TemplateBinding Parent.FooterText}" ... />
</Grid>
</ControlTemplate>

Em vez de definir as propriedades de Label.Text como texto estático, as propriedades podem usar associações de
modelo para associar a propriedades associáveis no pai da exibição de destino que é proprietária do
ControlTemplate . No entanto, observe que as associações de modelo se associam a Parent.HeaderText e
Parent.FooterText , em vez de HeaderText e FooterText . Isso ocorre porque, neste exemplo, as propriedades
associáveis são definidas no avô da exibição de destino, em vez do pai, conforme demonstrado no exemplo de
código a seguir:

<ContentPage ...>
<ContentView ... ControlTemplate="{StaticResource TealTemplate}">
...
</ContentView>
</ContentPage>

A origem da associação de modelo sempre é definida automaticamente como pai da exibição de destino que é
proprietária do modelo de controle, que aqui é a instância de ContentView . A associação de modelo usa a
propriedade Parent para retornar o elemento pai da instância de ContentView , que é a instância de ContentPage .
Portanto, usar um TemplateBinding no ControlTemplate para associar a Parent.HeaderText e Parent.FooterText
localiza as propriedades associáveis que estão definidas no ContentPage , conforme demonstrado no exemplo de
código a seguir:

public static readonly BindableProperty HeaderTextProperty =


BindableProperty.Create ("HeaderText", typeof(string), typeof(HomePage), "Control Template Demo App");
public static readonly BindableProperty FooterTextProperty =
BindableProperty.Create ("FooterText", typeof(string), typeof(HomePage), "(c) Xamarin 2016");

public string HeaderText {


get { return (string)GetValue (HeaderTextProperty); }
}

public string FooterText {


get { return (string)GetValue (FooterTextProperty); }
}

Isso resulta na aparência mostrada nas capturas de tela seguir:

Criando um TemplateBinding em C#
Em C#, um TemplateBinding é criado usando o construtor TemplateBinding , conforme demonstrado no exemplo
de código a seguir:

class TealTemplate : Grid


{
public TealTemplate ()
{
...
var topLabel = new Label { TextColor = Color.White, VerticalOptions = LayoutOptions.Center };
topLabel.SetBinding (Label.TextProperty, new TemplateBinding ("Parent.HeaderText"));
...
var bottomLabel = new Label { TextColor = Color.White, VerticalOptions = LayoutOptions.Center };
bottomLabel.SetBinding (Label.TextProperty, new TemplateBinding ("Parent.FooterText"));
...
}
}

Em vez de definir as propriedades de Label.Text como texto estático, as propriedades podem usar associações de
modelo para associar a propriedades associáveis no pai da exibição de destino que é proprietária do
ControlTemplate . A associação de modelo é criada usando o método SetBinding , especificando uma instância de
TemplateBinding como o segundo parâmetro. Observe que as associações de modelo se associam a
Parent.HeaderText e Parent.FooterText , porque as propriedades associáveis são definidas no avô da exibição de
destino, em vez do pai, conforme demonstrado no exemplo de código a seguir:

public class HomePageCS : ContentPage


{
...
public HomePageCS ()
{
Content = new ContentView {
ControlTemplate = tealTemplate,
Content = new StackLayout {
...
},
...
};
...
}
}

As propriedades associáveis são definidas no ContentPage , conforme descrito anteriormente.


Associando uma BindableProperty a uma propriedade de ViewModel
Conforme descrito anteriormente, um TemplateBinding associa a propriedade de um controle em um modelo de
controle a uma propriedade associável no pai da exibição de destino é proprietária do modelo de controle. Por sua
vez, essas propriedades associáveis podem ser associadas a propriedades em ViewModels.
O exemplo de código a seguir define duas propriedades em um ViewModel:

public class HomePageViewModel


{
public string HeaderText { get { return "Control Template Demo App"; } }
public string FooterText { get { return "(c) Xamarin 2016"; } }
}

As propriedades HeaderText e FooterText de ViewModel podem receber associações, conforme mostrado no


exemplo de código XAML a seguir:

<ContentPage xmlns:local="clr-namespace:SimpleTheme;assembly=SimpleTheme"
HeaderText="{Binding HeaderText}" FooterText="{Binding FooterText}" ...>
<ContentPage.BindingContext>
<local:HomePageViewModel />
</ContentPage.BindingContext>
<ContentView ControlTemplate="{StaticResource TealTemplate}" ...>
...
</ContentView>
</ContentPage>

As propriedades associáveis HeaderText e são associadas às propriedades


FooterText
HomePageViewModel.HeaderText e HomePageViewModel.FooterText , devido à configuração de BindingContext como
uma instância da classe HomePageViewModel . De modo geral, isso faz com que propriedades de controle no
ControlTemplate sejam associadas às instâncias de BindableProperty no ContentPage , que, por sua vez, são
associadas às propriedades de ViewModel.
O código C# equivalente é mostrado no exemplo de código a seguir:
public class HomePageCS : ContentPage
{
...
public HomePageCS ()
{
BindingContext = new HomePageViewModel ();
this.SetBinding (HeaderTextProperty, "HeaderText");
this.SetBinding (FooterTextProperty, "FooterText");
...
}
}

Você também pode estabelecer a associação com as propriedades do modelo de exibição diretamente, para que
não seja necessário declarar BindableProperty s para HeaderText e FooterText no ContentPage , associando o
modelo de controle a Parent.BindingContext.PropertyName, por exemplo:

<ControlTemplate x:Key="TealTemplate">
<Grid>
...
<Label Text="{TemplateBinding Parent.BindingContext.HeaderText}" ... />
...
<Label Text="{TemplateBinding Parent.BindingContext.FooterText}" ... />
</Grid>
</ControlTemplate>

Para obter mais informações sobre a associação de dados para ViewModels, confira De associações de dados a
MVVM.

Resumo
Este artigo demonstrou como usar associações de modelo para realizar a associação de dados de um modelo de
controle. Associações de modelo permitem que os controles em um modelo de controle associem dados a
propriedades públicas, permitindo que os valores de propriedade em controles no modelo de controle sejam
alterados facilmente.

Links relacionados
Conceitos básicos da associação de dados
De associações de dados a MVVM
Tema simples com associação de modelo (amostra)
Tema simples com associação de modelo e ViewModel (amostra)
TemplateBinding
ControlTemplate
ContentView
Modelos de dados do Xamarin.Forms
12/04/2019 • 2 minutes to read • Edit Online

Baixar o exemplo
Um DataTemplate é usado para especificar a aparência dos dados em controles compatíveis e geralmente é
associado aos dados a serem exibidos.

Introdução
Os modelos de dados do Xamarin.Forms fornecem a capacidade de definir a apresentação de dados em
controles compatíveis. Este artigo fornece uma introdução aos modelos de dados, examinando o motivo pelo
qual eles são necessários.

Criando um DataTemplate
Modelos de dados podem ser criados embutidos, em um ResourceDictionary ou de um tipo personalizado ou
um tipo de célula apropriado do Xamarin.Forms. Um modelo embutido deve ser usado se não há nenhuma
necessidade de reutilizar o modelo de dados em outro lugar. Como alternativa, um modelo de dados pode ser
reutilizado, definindo-o como um tipo personalizado ou como um recurso de aplicativo de nível de controle, de
página ou de aplicativo.

Criando um DataTemplateSelector
Um DataTemplateSelector pode ser usado para escolher um DataTemplate em tempo de execução com base no
valor de uma propriedade associada a dados. Isso permite que várias instâncias de DataTemplate sejam aplicadas
ao mesmo tipo de objeto, para personalizar a aparência de objetos específicos. Este artigo demonstra como criar
e consumir um DataTemplateSelector .

Links relacionados
Modelos de dados (amostra)
Introdução a modelos de dados do Xamarin.Forms
12/04/2019 • 6 minutes to read • Edit Online

Baixar o exemplo
Os modelos de dados do Xamarin.Forms fornecem a capacidade de definir a apresentação de dados em controles
compatíveis. Este artigo fornece uma introdução aos modelos de dados, examinando o motivo pelo qual eles são
necessários.
Considere uma ListView que exibe uma coleção de objetos Person . O exemplo de código a seguir mostra a
definição da classe Person :

public class Person


{
public string Name { get; set; }
public int Age { get; set; }
public string Location { get; set; }
}

A classe Persondefine as propriedades Name , Age e Location , que podem ser definidas quando um objeto
Person é criado. O ListView é usado para exibir a coleção de objetos Person , conforme mostrado no exemplo de
código XAML a seguir:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataTemplates"
...>
<StackLayout Margin="20">
...
<ListView Margin="0,20,0,0">
<ListView.ItemsSource>
<x:Array Type="{x:Type local:Person}">
<local:Person Name="Steve" Age="21" Location="USA" />
<local:Person Name="John" Age="37" Location="USA" />
<local:Person Name="Tom" Age="42" Location="UK" />
<local:Person Name="Lucas" Age="29" Location="Germany" />
<local:Person Name="Tariq" Age="39" Location="UK" />
<local:Person Name="Jane" Age="30" Location="USA" />
</x:Array>
</ListView.ItemsSource>
</ListView>
</StackLayout>
</ContentPage>

Itens são adicionados ao ListView no XAML inicializando a propriedade ItemsSource de uma matriz de instâncias
de Person .

NOTE
Observe que o elemento x:Array requer um atributo Type que indica o tipo dos itens na matriz.

A página em C# equivalente é mostrada no exemplo de código a seguir, que inicializa a propriedade ItemsSource
para um List de instâncias de Person :
public WithoutDataTemplatePageCS()
{
...
var people = new List<Person>
{
new Person { Name = "Steve", Age = 21, Location = "USA" },
new Person { Name = "John", Age = 37, Location = "USA" },
new Person { Name = "Tom", Age = 42, Location = "UK" },
new Person { Name = "Lucas", Age = 29, Location = "Germany" },
new Person { Name = "Tariq", Age = 39, Location = "UK" },
new Person { Name = "Jane", Age = 30, Location = "USA" }
};

Content = new StackLayout


{
Margin = new Thickness(20),
Children = {
...
new ListView { ItemsSource = people, Margin = new Thickness(0, 20, 0, 0) }
}
};
}

O ListView chama ToString ao exibir os objetos na coleção. Como não há uma substituição de Person.ToString ,
ToString retorna o nome do tipo de cada objeto, conforme mostrado nas capturas de tela seguir:

O objeto Person pode substituir o método ToString para exibir dados significativos, conforme mostrado no
exemplo de código a seguir:

public class Person


{
...
public override string ToString ()
{
return Name;
}
}

Isso faz com que ListView exiba o valor da propriedade Person.Name para cada objeto na coleção, conforme
mostrado nas capturas de tela seguir:
A substituição Person.ToString poderia retornar uma cadeia de caracteres formatada composta pelas
propriedades Name , Age e Location . No entanto, essa abordagem oferece apenas controle limitado sobre a
aparência de cada item de dados. Para ter mais flexibilidade, é possível criar um DataTemplate que define a
aparência dos dados.

Criando um DataTemplate
Um DataTemplate é usado para especificar a aparência dos dados e normalmente usa a associação de dados para
exibir dados. Um cenário de uso comum é exibir dados de uma coleção de objetos em um ListView . Por exemplo,
quando um ListView está associado a uma coleção de objetos Person , a propriedade ListView.ItemTemplate é
definida como um DataTemplate que define a aparência de cada objeto Person no ListView . O DataTemplate
conterá elementos que associam aos valores de propriedade de cada objeto Person . Para obter mais informações
sobre vinculação de dados, veja Noções básicas de vinculação de dados.
Um DataTemplate pode ser usado como um valor para as seguintes propriedades:
ListView.HeaderTemplate
ListView.FooterTemplate
ListView.GroupHeaderTemplate
ItemsView.ItemTemplate , que é herdado por ListView .
MultiPage.ItemTemplate , que é herdado por CarouselPage , MasterDetailPage e TabbedPage .

NOTE
Observe que, embora o TableView use objetos Cell , ele não usa um DataTemplate . Isso acontece porque as
associações de dados sempre são definidas diretamente em objetos Cell .

Um DataTemplate que é colocado como filho direto das propriedades listadas acima é conhecido como um
modelo embutido. Como alternativa, é possível definir um DataTemplate como um recurso de nível de controle,
nível de página ou nível de aplicativo. Escolher onde definir um DataTemplate afeta onde ele pode ser usado:
Um DataTemplate definido no nível do controle só pode ser aplicado ao controle.
Um DataTemplate definido no nível da página só pode ser aplicado a vários controles válidos na página.
Um DataTemplate definido no nível do aplicativo pode ser aos controles válidos em todo o aplicativo.

Modelos de dados posicionados mais baixo na hierarquia de exibição têm precedência sobre os definidos mais
acima quando eles compartilham atributos de x:Key . Por exemplo, um modelo de dados no nível do aplicativo
será substituído por um modelo de dados no nível da página e um modelo de dados no nível da página será
substituído por um modelo de dados no nível de controle ou por um modelo de dados embutido.

Links relacionados
Aparência de célula
Modelos de dados (amostra)
DataTemplate
Criando um DataTemplate do Xamarin.Forms
12/04/2019 • 8 minutes to read • Edit Online

Baixar o exemplo
Os modelos de dados podem ser criados embutidos, em um ResourceDictionary ou de um tipo personalizado ou
um tipo de célula apropriado do Xamarin.Forms. Este artigo explora cada técnica.
Um cenário de uso comum para um DataTemplate é exibir dados de uma coleção de objetos em um ListView . A
aparência dos dados para cada célula no ListView pode ser gerenciada definindo a propriedade
ListView.ItemTemplate como um DataTemplate . Há várias técnicas que podem ser usadas para fazer isso:

Criando um DataTemplate embutido.


Criando um DataTemplate com um tipo.
Criando um DataTemplate como um recurso.
Independentemente da técnica que está sendo usada, o resultado é que a aparência de cada célula no ListView é
definida por um DataTemplate , conforme mostrado nas seguintes capturas de tela:

Criando um DataTemplate embutido


A propriedade ListView.ItemTemplate pode ser definida como um DataTemplate embutido. Um modelo embutido,
que é inserido como um filho direto de uma propriedade de controle apropriada, deverá ser usado se não houver
necessidade de reutilizar o modelo de dados em outro lugar. Os elementos especificados no DataTemplate
definem a aparência de cada célula, conforme mostrado no exemplo de código XAML a seguir:
<ListView Margin="0,20,0,0">
<ListView.ItemsSource>
<x:Array Type="{x:Type local:Person}">
<local:Person Name="Steve" Age="21" Location="USA" />
<local:Person Name="John" Age="37" Location="USA" />
<local:Person Name="Tom" Age="42" Location="UK" />
<local:Person Name="Lucas" Age="29" Location="Germany" />
<local:Person Name="Tariq" Age="39" Location="UK" />
<local:Person Name="Jane" Age="30" Location="USA" />
</x:Array>
</ListView.ItemsSource>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
...
<Label Text="{Binding Name}" FontAttributes="Bold" />
<Label Grid.Column="1" Text="{Binding Age}" />
<Label Grid.Column="2" Text="{Binding Location}" HorizontalTextAlignment="End" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

O filho de um DataTemplate embutido deve ser do tipo Cell ou derivado dele. Este exemplo usa um ViewCell ,
que deriva de Cell . O layout dentro do ViewCell é gerenciado aqui por um Grid . O Grid contém três
instâncias Label que associam suas propriedades Text às propriedades adequadas de cada objeto Person na
coleção.
O código C# equivalente é mostrado no exemplo de código a seguir:
public class WithDataTemplatePageCS : ContentPage
{
public WithDataTemplatePageCS()
{
...
var people = new List<Person>
{
new Person { Name = "Steve", Age = 21, Location = "USA" },
...
};

var personDataTemplate = new DataTemplate(() =>


{
var grid = new Grid();
...
var nameLabel = new Label { FontAttributes = FontAttributes.Bold };
var ageLabel = new Label();
var locationLabel = new Label { HorizontalTextAlignment = TextAlignment.End };

nameLabel.SetBinding(Label.TextProperty, "Name");
ageLabel.SetBinding(Label.TextProperty, "Age");
locationLabel.SetBinding(Label.TextProperty, "Location");

grid.Children.Add(nameLabel);
grid.Children.Add(ageLabel, 1, 0);
grid.Children.Add(locationLabel, 2, 0);

return new ViewCell { View = grid };


});

Content = new StackLayout


{
Margin = new Thickness(20),
Children = {
...
new ListView { ItemsSource = people, ItemTemplate = personDataTemplate, Margin = new
Thickness(0, 20, 0, 0) }
}
};
}
}

Em C#, o DataTemplate embutido é criado usando uma sobrecarga de construtor que especifica um argumento
Func .

Criando um DataTemplate com um tipo


A propriedade ListView.ItemTemplate também pode ser definida como uma DataTemplate criada com base em
um tipo de célula. A vantagem dessa abordagem é que a aparência definida pelo tipo de célula pode ser reutilizado
por vários modelos de dados em todo o aplicativo. O código XAML a seguir mostra um exemplo dessa
abordagem:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataTemplates"
...>
<StackLayout Margin="20">
...
<ListView Margin="0,20,0,0">
<ListView.ItemsSource>
<x:Array Type="{x:Type local:Person}">
<local:Person Name="Steve" Age="21" Location="USA" />
...
</x:Array>
</ListView.ItemsSource>
<ListView.ItemTemplate>
<DataTemplate>
<local:PersonCell />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>

Aqui, a propriedade ListView.ItemTemplate é definida como um DataTemplate criado com base em um tipo
personalizado que define a aparência da célula. O tipo personalizado deve ser derivado do tipo ViewCell ,
conforme mostrado no exemplo de código a seguir:

<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataTemplates.PersonCell">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*" />
<ColumnDefinition Width="0.2*" />
<ColumnDefinition Width="0.3*" />
</Grid.ColumnDefinitions>
<Label Text="{Binding Name}" FontAttributes="Bold" />
<Label Grid.Column="1" Text="{Binding Age}" />
<Label Grid.Column="2" Text="{Binding Location}" HorizontalTextAlignment="End" />
</Grid>
</ViewCell>

Dentro do ViewCell , o layout é gerenciado aqui por um Grid . O Grid contém três instâncias Label que
associam suas propriedades Text às propriedades adequadas de cada objeto Person na coleção.
O código C# equivalente é mostrado no exemplo a seguir:
public class WithDataTemplatePageFromTypeCS : ContentPage
{
public WithDataTemplatePageFromTypeCS()
{
...
var people = new List<Person>
{
new Person { Name = "Steve", Age = 21, Location = "USA" },
...
};

Content = new StackLayout


{
Margin = new Thickness(20),
Children = {
...
new ListView { ItemTemplate = new DataTemplate(typeof(PersonCellCS)), ItemsSource = people,
Margin = new Thickness(0, 20, 0, 0) }
}
};
}
}

Em C#, o DataTemplate é criado usando uma sobrecarga de construtor que especifica o tipo de célula como um
argumento. O tipo de célula deve ser derivado do tipo ViewCell , conforme mostrado no exemplo de código a
seguir:

public class PersonCellCS : ViewCell


{
public PersonCellCS()
{
var grid = new Grid();
...
var nameLabel = new Label { FontAttributes = FontAttributes.Bold };
var ageLabel = new Label();
var locationLabel = new Label { HorizontalTextAlignment = TextAlignment.End };

nameLabel.SetBinding(Label.TextProperty, "Name");
ageLabel.SetBinding(Label.TextProperty, "Age");
locationLabel.SetBinding(Label.TextProperty, "Location");

grid.Children.Add(nameLabel);
grid.Children.Add(ageLabel, 1, 0);
grid.Children.Add(locationLabel, 2, 0);

View = grid;
}
}

NOTE
Observe que o Xamarin.Forms também inclui tipos de células que podem ser usados para exibir dados simples em células
ListView . Para saber mais, confira Cell Appearance (Aparência da célula).

Criando um DataTemplate como um recurso


Os modelos de dados também podem ser criados como objetos reutilizáveis em um ResourceDictionary . Isso é
feito dando a cada declaração um atributo x:Key exclusivo, que fornece a ela uma chave descritiva no
ResourceDictionary , conforme mostrado no exemplo de código XAML a seguir:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
...>
<ContentPage.Resources>
<ResourceDictionary>
<DataTemplate x:Key="personTemplate">
<ViewCell>
<Grid>
...
</Grid>
</ViewCell>
</DataTemplate>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout Margin="20">
...
<ListView ItemTemplate="{StaticResource personTemplate}" Margin="0,20,0,0">
<ListView.ItemsSource>
<x:Array Type="{x:Type local:Person}">
<local:Person Name="Steve" Age="21" Location="USA" />
...
</x:Array>
</ListView.ItemsSource>
</ListView>
</StackLayout>
</ContentPage>

O DataTemplate é atribuído à propriedade ListView.ItemTemplate usando a extensão de marcação


StaticResource . Observe que, embora o DataTemplate seja definido no ResourceDictionary da página, ele
também poderia ser definido no nível do controle ou do aplicativo.
O exemplo de código a seguir mostra a página equivalente em C#:

public class WithDataTemplatePageCS : ContentPage


{
public WithDataTemplatePageCS ()
{
...
var personDataTemplate = new DataTemplate (() => {
var grid = new Grid ();
...
return new ViewCell { View = grid };
});

Resources = new ResourceDictionary ();


Resources.Add ("personTemplate", personDataTemplate);

Content = new StackLayout {


Margin = new Thickness(20),
Children = {
...
new ListView { ItemTemplate = (DataTemplate)Resources ["personTemplate"], ItemsSource = people };
}
};
}
}

O DataTemplate é adicionado ao ResourceDictionary usando o método Add , que especifica uma cadeia de
caracteres Key usada para referenciar o DataTemplate ao recuperá-la.

Resumo
Este artigo explicou como criar modelos de dados, embutidos, com base em um tipo personalizado ou em um
ResourceDictionary . Um modelo embutido deve ser usado caso não haja necessidade de reutilizar o modelo de
dados em outro lugar. Como alternativa, um modelo de dados pode ser reutilizado, definindo-o como um tipo
personalizado ou como um recurso de aplicativo de nível de controle, de página ou de aplicativo.

Links relacionados
Aparência de célula
Modelos de dados (amostra)
DataTemplate
Criando um DataTemplateSelector do Xamarin.Forms
12/04/2019 • 6 minutes to read • Edit Online

Baixar o exemplo
Um DataTemplateSelector pode ser usado para escolher um DataTemplate em tempo de execução com base no
valor de uma propriedade associada a dados. Isso permite que várias instâncias de DataTemplates sejam
aplicadas ao mesmo tipo de objeto, para personalizar a aparência de objetos específicos. Este artigo demonstra
como criar e consumir um DataTemplateSelector.
Um seletor de modelo de dados permite cenários como uma associação do ListView a uma coleção de objetos,
em que a aparência de cada objeto no ListView pode ser escolhida em tempo de execução pelo seletor de
modelo de dados que retorna um DataTemplate específico.

Criando um DataTemplateSelector
Um seletor de modelo de dados é implementado criando uma classe herdada de DataTemplateSelector . O método
OnSelectTemplate é substituído para retornar um determinado DataTemplate , conforme mostrado no exemplo de
código a seguir:

public class PersonDataTemplateSelector : DataTemplateSelector


{
public DataTemplate ValidTemplate { get; set; }
public DataTemplate InvalidTemplate { get; set; }

protected override DataTemplate OnSelectTemplate (object item, BindableObject container)


{
return ((Person)item).DateOfBirth.Year >= 1980 ? ValidTemplate : InvalidTemplate;
}
}

O método OnSelectTemplate retorna o modelo apropriado com base no valor da propriedade DateOfBirth . O
modelo a ser retornado é o valor da propriedade ValidTemplate ou da propriedade InvalidTemplate , que são
definidas ao consumir o PersonDataTemplateSelector .
Uma instância da classe de seletor de modelo de dados pode ser atribuída às propriedades de controle do
Xamarin.Forms, como ListView.ItemTemplate . Para obter uma lista de propriedades válidas, confira Criando um
DataTemplate.
Limitações
As instâncias DataTemplateSelector têm as seguintes limitações:
A subclasse DataTemplateSelector deve sempre retornar o mesmo modelo para os mesmos dados se
consultada várias vezes.
A subclasse DataTemplateSelector não deve retornar outra subclasse DataTemplateSelector .
A subclasse DataTemplateSelector não deve retornar novas instâncias de um DataTemplate em cada chamada.
Em vez disso, a mesma instância deve ser retornada. Não fazer isso criará uma perda de memória e
desabilitará a virtualização.
No Android, não pode haver mais de 20 modelos de dados diferentes por ListView .

Consumindo um DataTemplateSelector em XAML


Em XAML, o PersonDataTemplateSelector pode ser instanciado ao declará-lo como um recurso, conforme
mostrado no exemplo de código a seguir:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:Selector;assembly=Selector"
x:Class="Selector.HomePage">
<ContentPage.Resources>
<ResourceDictionary>
<DataTemplate x:Key="validPersonTemplate">
<ViewCell>
...
</ViewCell>
</DataTemplate>
<DataTemplate x:Key="invalidPersonTemplate">
<ViewCell>
...
</ViewCell>
</DataTemplate>
<local:PersonDataTemplateSelector x:Key="personDataTemplateSelector"
ValidTemplate="{StaticResource validPersonTemplate}"
InvalidTemplate="{StaticResource invalidPersonTemplate}" />
</ResourceDictionary>
</ContentPage.Resources>
...
</ContentPage>

Esse nível de página ResourceDictionary define duas instâncias e uma instância


DataTemplate
PersonDataTemplateSelector . A instância PersonDataTemplateSelector define suas propriedades ValidTemplate e
InvalidTemplate como as instâncias DataTemplate apropriadas usando a extensão de marcação StaticResource .
Observe que, embora os recursos sejam definidos no ResourceDictionary da página, eles também podem ser
definidos no nível de controle ou do aplicativo.
A instância PersonDataTemplateSelector é consumida atribuindo-a à propriedade ListView.ItemTemplate ,
conforme mostrado no exemplo de código a seguir:

<ListView x:Name="listView" ItemTemplate="{StaticResource personDataTemplateSelector}" />

Em tempo de execução, o ListView chama o método PersonDataTemplateSelector.OnSelectTemplate para cada um


dos itens na coleção subjacente, com a chamada passando o objeto de dados como o parâmetro item . O
DataTemplate retornado pelo método é aplicado a esse objeto.

As capturas de tela a seguir mostram o resultado do ListView aplicando o PersonDataTemplateSelector a cada


objeto na coleção subjacente:
Qualquer objeto Person que tem o valor da propriedade DateOfBirth maior que ou igual a 1980 é exibido em
verde, com os objetos restantes sendo exibidos em vermelho.

Consumindo um DataTemplateSelector em C#
Em C#, o PersonDataTemplateSelector pode ser instanciado e atribuído à propriedade ListView.ItemTemplate ,
conforme mostrado no exemplo de código a seguir:

public class HomePageCS : ContentPage


{
DataTemplate validTemplate;
DataTemplate invalidTemplate;

public HomePageCS ()
{
...
SetupDataTemplates ();
var listView = new ListView {
ItemsSource = people,
ItemTemplate = new PersonDataTemplateSelector {
ValidTemplate = validTemplate,
InvalidTemplate = invalidTemplate }
};

Content = new StackLayout {


Margin = new Thickness (20),
Children = {
...
listView
}
};
}
...
}

A instância PersonDataTemplateSelector define suas propriedades ValidTemplate e InvalidTemplate como as


instâncias DataTemplate apropriadas pelo método SetupDataTemplates . Em tempo de execução, o ListView
chama o método PersonDataTemplateSelector.OnSelectTemplate para cada um dos itens na coleção subjacente, com
a chamada passando o objeto de dados como o parâmetro item . O DataTemplate retornado pelo método é
aplicado a esse objeto.
Resumo
Este artigo demonstrou como criar e consumir um DataTemplateSelector . Um DataTemplateSelector pode ser
usado para escolher um DataTemplate em tempo de execução com base no valor de uma propriedade associada a
dados. Isso permite que várias instâncias de DataTemplate sejam aplicadas ao mesmo tipo de objeto, para
personalizar a aparência de objetos específicos.

Links relacionados
Seletor de Modelo de Dados (exemplo)
DataTemplateSelector
Gatilhos do Xamarin.Forms
12/04/2019 • 12 minutes to read • Edit Online

Baixar o exemplo
Os gatilhos permitem expressar ações declarativamente em XAML que alteram a aparência dos controles com
base em eventos ou alterações de propriedade.
Você pode atribuir um gatilho diretamente a um controle ou adicioná-lo a um dicionário de recursos na página ou
aplicativo a ser aplicado a vários controles.
Há quatro tipos de gatilho:
Gatilho de propriedade – ocorre quando uma propriedade em um controle é definida como um valor
específico.
Gatilho de dados – usa associação de dados para disparar com base nas propriedades de outro controle.
Gatilho de evento – ocorre quando acontece um evento no controle.
Gatilho múltiplo – permite que várias condições de gatilho sejam definidas antes que uma ação ocorra.

Gatilhos de propriedade
Um gatilho simples pode ser expresso puramente em XAML, adicionando um elemento Trigger a uma coleção
de gatilhos do controle. Este exemplo mostra um gatilho que altera uma cor da tela de fundo Entry quando
recebe o foco:

<Entry Placeholder="enter name">


<Entry.Triggers>
<Trigger TargetType="Entry"
Property="IsFocused" Value="True">
<Setter Property="BackgroundColor" Value="Yellow" />
</Trigger>
</Entry.Triggers>
</Entry>

As partes importantes da declaração do gatilho são:


TargetType – o tipo de controle ao qual o gatilho se aplica.
Propriedade – a propriedade no controle que é monitorado.
Valor – o valor, quando ele ocorre para a propriedade monitorada, que faz o gatilho ativar.
Setter – uma coleção de elementos Setter pode ser adicionada quando a condição do gatilho for
atendida. Você deve especificar Property e Value para definir.
EnterActions e ExitActions (não mostrado) – são escritos em código e podem ser usados em (ou em vez
de) elementos Setter . Eles são descritos abaixo.
Aplicação de um gatilho usando um estilo
Gatilhos também podem ser adicionados a uma declaração Style em um controle, em uma página ou um
aplicativo ResourceDictionary . Este exemplo declara um estilo implícito (por exemplo, nenhum Key está
definido), o que significa que ele se aplicará a todos os controles Entry na página.
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Entry">
<Style.Triggers>
<Trigger TargetType="Entry"
Property="IsFocused" Value="True">
<Setter Property="BackgroundColor" Value="Yellow" />
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
</ContentPage.Resources>

Gatilhos de dados
Os gatilhos de dados usam a associação de dados para monitorar outro controle para fazer com que Setter s
sejam chamados. Em vez do atributo Property em um gatilho de propriedade, defina o atributo Binding para
monitorar o valor especificado.
O exemplo a seguir usa a sintaxe de associação de dados {Binding Source={x:Reference entry}, Path=Text.Length}
que é como nos referimos a outras propriedades do controle. Quando o tamanho do entry for zero, o gatilho
será ativado. Neste exemplo, o gatilho desabilita o botão quando a entrada está vazia.

<!-- the x:Name is referenced below in DataTrigger-->


<!-- tip: make sure to set the Text="" (or some other default) -->
<Entry x:Name="entry"
Text=""
Placeholder="required field" />

<Button x:Name="button" Text="Save"


FontSize="Large"
HorizontalOptions="Center">
<Button.Triggers>
<DataTrigger TargetType="Button"
Binding="{Binding Source={x:Reference entry},
Path=Text.Length}"
Value="0">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Button.Triggers>
</Button>

Dica: ao avaliar Path=Text.Length , sempre forneça um valor padrão para a propriedade de destino (por exemplo,
Text="" ), pois, caso contrário, ele será null e o gatilho não funcionará como esperado.

Além de especificar Setter s, você também pode fornecer EnterActions e ExitActions .

Gatilhos de evento
O elemento EventTrigger requer apenas uma propriedade Event , como "Clicked" no exemplo a seguir.

<EventTrigger Event="Clicked">
<local:NumericValidationTriggerAction />
</EventTrigger>

Observe que não há elementos , mas, em vez disso, uma referência a uma classe definida por
Setter
local:NumericValidationTriggerAction , que requer que o xmlns:local seja declarado no XAML da página:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:WorkingWithTriggers;assembly=WorkingWithTriggers"

A classe em si implementa TriggerAction , o que significa que ela deve fornecer uma substituição para o método
Invoke que é chamado sempre que ocorre o evento de gatilho.

Uma implementação de ação do gatilho deve:


Implementar a classe TriggerAction<T> genérica com o parâmetro genérico correspondente com o tipo de
controle ao qual o gatilho será aplicado. É possível usar superclasses, como VisualElement , para gravar
ações de gatilho que funcionam com uma variedade de controles ou especificar um tipo de controle, como
Entry .

Substituir o método Invoke – isso é chamado sempre que os critérios do gatilho forem atendidos.
Outra opção é expor propriedades que podem ser definidas no XAML quando o gatilho é declarado (como
Anchor , Scale e Length neste exemplo).

public class NumericValidationTriggerAction : TriggerAction<Entry>


{
protected override void Invoke (Entry entry)
{
double result;
bool isValid = Double.TryParse (entry.Text, out result);
entry.TextColor = isValid ? Color.Default : Color.Red;
}
}

As propriedades expostas pela ação de gatilho podem ser definidas na declaração de XAML da seguinte maneira:

<EventTrigger Event="TextChanged">
<local:NumericValidationTriggerAction />
</EventTrigger>

Tenha cuidado ao compartilhar gatilhos em um ResourceDictionary , pois uma instância será compartilhada entre
os controles para que qualquer estado que está configurado uma vez se aplique a todos.
Observe que os gatilhos de evento não dão suporte a EnterActions nem a ExitActions descrito abaixo.

Múltiplos gatilhos
Um MultiTrigger é semelhante a um Trigger ou DataTrigger , exceto que pode haver mais de uma condição.
Todas as condições devem ser verdadeiras antes de Setter s serem disparados.
Aqui está um exemplo de um gatilho para um botão que é associado a duas entradas diferentes ( email e phone ):
<MultiTrigger TargetType="Button">
<MultiTrigger.Conditions>
<BindingCondition Binding="{Binding Source={x:Reference email},
Path=Text.Length}"
Value="0" />
<BindingCondition Binding="{Binding Source={x:Reference phone},
Path=Text.Length}"
Value="0" />
</MultiTrigger.Conditions>

<Setter Property="IsEnabled" Value="False" />


<!-- multiple Setter elements are allowed -->
</MultiTrigger>

A coleção Conditions também pode conter elementos PropertyCondition como este:

<PropertyCondition Property="Text" Value="OK" />

Criar um gatilho múltiplo que “exige tudo”


O gatilho múltiplo apenas atualiza seu controle quando todas as condições são verdadeiras. Fazer o teste para
"todos os tamanhos de campo são zero" (como uma página de logon na qual todas as entradas devem ser
concluídas) é complicado porque você deseja uma condição "em que Text.Length > 0", mas isso não pode ser
expresso em XAML.
Isso pode ser feito com um IValueConverter . O código de conversor abaixo transforma o Text.Length que se
associa a um bool que indica se um campo está vazio ou não:

public class MultiTriggerConverter : IValueConverter


{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
if ((int)value > 0) // length > 0 ?
return true; // some data has been entered
else
return false; // input is empty
}

public object ConvertBack(object value, Type targetType,


object parameter, CultureInfo culture)
{
throw new NotSupportedException ();
}
}

Para usar esse conversor em um gatilho múltiplo, primeiro adicione-o ao dicionário de recursos da página (junto
com uma definição de namespace xmlns:local personalizada):

<ResourceDictionary>
<local:MultiTriggerConverter x:Key="dataHasBeenEntered" />
</ResourceDictionary>

O XAML é mostrado abaixo. Observe as seguintes diferenças do primeiro exemplo de gatilho múltiplo:
O botão tem IsEnabled="false" definido por padrão.
As condições de gatilho múltiplo usam o conversor para transformar o valor Text.Length em um boolean .
Quando todas as condições forem true , o setter transformará o IsEnabled do botão na propriedade true .
<Entry x:Name="user" Text="" Placeholder="user name" />

<Entry x:Name="pwd" Text="" Placeholder="password" />

<Button x:Name="loginButton" Text="Login"


FontSize="Large"
HorizontalOptions="Center"
IsEnabled="false">
<Button.Triggers>
<MultiTrigger TargetType="Button">
<MultiTrigger.Conditions>
<BindingCondition Binding="{Binding Source={x:Reference user},
Path=Text.Length,
Converter={StaticResource dataHasBeenEntered}}"
Value="true" />
<BindingCondition Binding="{Binding Source={x:Reference pwd},
Path=Text.Length,
Converter={StaticResource dataHasBeenEntered}}"
Value="true" />
</MultiTrigger.Conditions>
<Setter Property="IsEnabled" Value="True" />
</MultiTrigger>
</Button.Triggers>
</Button>

Essas capturas de tela mostram a diferença entre os dois exemplos de gatilho múltiplo acima. Na parte superior
das telas, a entrada de texto em apenas um Entry é suficiente para habilitar o botão Salvar. Na parte inferior das
telas, o botão Logon permanece inativo até que ambos os campos contenham dados.

EnterActions e ExitActions
Outra maneira de implementar alterações quando ocorre um gatilho é adicionando as coleções EnterActions e
ExitActions e especificando as implementações TriggerAction<T> .

Você pode fornecer ambos EnterActions e ExitActions , bem como Setter s em um gatilho, mas lembre-se de
que Setter s são chamados imediatamente (eles não aguardam o EnterAction ou o ExitAction ser concluído).
Como alternativa, você pode executar tudo no código e não usar Setter s.

<Entry Placeholder="enter job title">


<Entry.Triggers>
<Trigger TargetType="Entry"
Property="Entry.IsFocused" Value="True">
<Trigger.EnterActions>
<local:FadeTriggerAction StartsFrom="0"" />
</Trigger.EnterActions>

<Trigger.ExitActions>
<local:FadeTriggerAction StartsFrom="1" />
</Trigger.ExitActions>
<!-- You can use both Enter/Exit and Setter together if required -->
</Trigger>
</Entry.Triggers>
</Entry>

Como sempre, quando uma classe é referenciada no XAML você deve declarar um namespace como xmlns:local
, conforme mostrado aqui:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:WorkingWithTriggers;assembly=WorkingWithTriggers"

O código FadeTriggerAction é mostrado abaixo:

public class FadeTriggerAction : TriggerAction<VisualElement>


{
public FadeTriggerAction() {}

public int StartsFrom { set; get; }

protected override void Invoke (VisualElement visual)


{
visual.Animate("", new Animation( (d)=>{
var val = StartsFrom==1 ? d : 1-d;
visual.BackgroundColor = Color.FromRgb(1, val, 1);

}),
length:1000, // milliseconds
easing: Easing.Linear);
}
}

Observação: EnterActions e ExitActions são ignorados em Gatilhos de evento.

Links relacionados
Exemplo de gatilhos
Documentação da API do Xamarin.Forms
Exibições de Interface do usuário do xamarin. Forms
12/04/2019 • 6 minutes to read

baixar o exemplo
Como usar os modos de exibição fornecidos pelo xamarin. Forms

Animação
Xamarin. Forms inclui sua própria infraestrutura de animação que é muito simples para a criação de animações
simples, embora também seja suficientemente versátil para criar animações complexas.

BoxView
O BoxView é apenas um retângulo colorido simple, mas ele pode ser usado para itens decorativos, gráficos
rudimentares e para a obtenção de entrada por toque interativa.

Button
O Button responde a um toque ou clique que direciona um aplicativo para executar uma tarefa específica.

CollectionView
O CollectionView é uma exibição flexível e de alto desempenho para apresentações de listas de dados usando as
especificações de layout diferente.

Cores
Definindo e usando cores entre plataformas podem ser complicados quando cada plataforma tem seus próprios
padrões e os padrões.

Referência de controles
Este documento é uma referência rápida para os modos de exibição da interface do usuário que compõem a
estrutura do xamarin. Forms, tal como páginas, Layouts, modos de exibição e células.

DataPages
DataSourceControl fornece uma API para rápida e facilmente vincular uma fonte de dados para exibições
predefinidas. Itens de lista e páginas de detalhes renderização automaticamente os dados e ser personalizadas
usando temas.

DatePicker
O DatePicker permite que um usuário selecione uma data dentro do intervalo especificado. Ele é implementado
usando o seletor de datas com suporte na plataforma específica que o aplicativo é executado.

Elementos gráficos com SkiaSharp


Como incorporar elementos gráficos em um aplicativo xamarin. Forms usando SkiaSharp.
Imagens
Imagens podem ser compartilhadas entre plataformas com o xamarin. Forms, podem ser carregados
especificamente para cada plataforma ou podem ser baixados para exibição.

ImageButton
O ImageButton exibe uma imagem e responde a um toque ou clique que direciona um aplicativo para executar
uma tarefa específica.

Layouts
Xamarin. Forms tem vários layouts para organizar conteúdos na tela. StackLayout , Grid , FlexLayout ,
AbsoluteLayout , ScrollView , e RelativeLayout cada um pode ser usada para criar interfaces do usuário atraentes
e dinâmicos.

ListView
Xamarin. Forms fornece um controle de exibição de lista para exibir a rolagem de linhas de dados. O controle inclui
ações contextuais, HasUnevenRows o dimensionamento automático, personalização de separador, puxar para
atualizar e cabeçalhos e rodapés.

Mapas
Adicionar mapas requer um download adicional de pacote do NuGet e algumas configurações específicas da
plataforma. Mapas e marcadores de pin que podem ser adicionados em apenas algumas linhas de código depois
que a configuração é feita.

Seletor
O Picker exibição é um controle para selecionar um item de texto em uma lista de dados.

Slider
O Slider permite que um usuário selecione um valor numérico de um intervalo contínuo.

Passador
O Stepper permite que um usuário selecione um valor numérico de um intervalo de valores. Ele consiste em dois
botões rotulados com sinais de adição e de subtração. Manipular os dois botões altera o valor selecionado
incrementalmente.

Estilos
Fonte, cor e outros atributos podem ser agrupados em estilos que podem ser compartilhados entre os controles,
layouts ou todo o aplicativo usando ResourceDictionaries.

TableView
O modo de exibição de tabela é semelhante a uma exibição de lista, mas em vez de que está sendo criado para
listas longas de dados destina-se para telas de estilo de entrada de dados de rolagem controles ou menus simples
de rolagem.
Texto
Xamarin. Forms tem vários modos de exibição para apresentar e receber texto. Modos de exibição de texto podem
ser formatados e personalizados para as plataformas. Configurações de fonte específico podem habilitar a
compatibilidade com os recursos de acessibilidade.

Temas
Temas do xamarin. Forms definem uma aparência visual específica para os controles padrão. Depois que você
adiciona um tema para o dicionário de recursos do aplicativo, a aparência dos controles padrão será alterado.

TimePicker
O TimePicker permite que um usuário selecione uma hora. Ele é implementado usando o seletor de tempo com
suporte na plataforma específica que o aplicativo é executado.

Visual
Material do xamarin. Forms Visual pode ser usado para criar aplicativos xamarin. Forms que se parecem idênticos
ou praticamente idênticas, no iOS e Android.

Visual State Manager


O Gerenciador de estado Visual fornece uma maneira estruturada para disparar alterações na interface do usuário
do código, incluindo layout que se adapta às alterações na orientação do dispositivo ou tamanho.

WebView
Xamarin. Forms usa o controle de navegador da web nativos em cada plataforma e pode exibir cadeias de
caracteres Html geradas, recursos locais e sites.

Links relacionados
Galeria do Xamarin.Forms (amostra)
Animação no xamarin. Forms
12/04/2019 • 2 minutes to read

Xamarin. Forms inclui sua própria infraestrutura de animação que é muito simples para a criação de animações
simples, embora também seja suficientemente versátil para criar animações complexas.
As classes de animação do xamarin. Forms diferentes propriedades de elementos visuais, de destino com uma
animação típica progressivamente alterar uma propriedade de um valor para outro durante um período de tempo.
Observe que não há nenhuma interface XAML para as classes de animação do xamarin. Forms. No entanto, as
animações podem ser encapsuladas em comportamentos e, em seguida, referenciado do XAML.

Animações simples
O ViewExtensions classe fornece métodos de extensão que podem ser usados para construir animações simples
que giram, dimensionarem, traduzam e fade VisualElement instâncias. Este artigo demonstra como criar e
cancelar as animações usando o ViewExtensions classe.

Funções de easing
Xamarin. Forms inclui um Easing classe que permite que você especifique uma função de transferência que
controla como as animações acelerar ou diminuir como elas estão em execução. Este artigo demonstra como
utilizar as funções de easing predefinidas e como criar funções de easing personalizadas.

Animações personalizadas
O Animation classe é o bloco de construção de todas as animações de xamarin. Forms, com os métodos de
extensão no ViewExtensions classe criando um ou mais Animation objetos. Este artigo demonstra como usar o
Animation classe para criar e Cancelar animações, sincronizar várias animações e criar animações personalizadas
que animar propriedades que não estão animadas pelos métodos de animação existentes.
Animações simples no xamarin. Forms
12/04/2019 • 18 minutes to read

baixar o exemplo
A classe ViewExtensions fornece métodos de extensão que podem ser usados para construir animações simples.
Este artigo demonstra como criar e cancelar as animações usando a classe ViewExtensions.
O ViewExtensions classe fornece os seguintes métodos de extensão que podem ser usados para criar animações
simples:
TranslateTo Anima o TranslationX e TranslationY propriedades de um VisualElement .
ScaleTo Anima o Scale propriedade de uma VisualElement .
RelScaleTo aplica-se um aumento incremental animado ou diminuirá para o Scale propriedade de uma
VisualElement .
RotateTo Anima o Rotation propriedade de uma VisualElement .
RelRotateTo aplica-se um aumento incremental animado ou diminuirá para o Rotation propriedade de uma
VisualElement .
RotateXTo Anima o RotationX propriedade de uma VisualElement .
RotateYTo Anima o RotationY propriedade de uma VisualElement .
FadeTo Anima o Opacity propriedade de uma VisualElement .

Por padrão, cada animação levará 250 milissegundos. No entanto, uma duração para cada animação pode ser
especificada ao criar a animação.
O ViewExtensions classe também inclui um CancelAnimations método que pode ser usado para cancelar todas as
animações.

NOTE
O ViewExtensions classe fornece um LayoutTo método de extensão. No entanto, esse método se destina a ser usado
pelo layouts para animar as transições entre estados de layout que contêm o tamanho e posição alterações. Portanto, ele só
deve ser usado pelo Layout subclasses.

Os métodos de extensão de animação na ViewExtensions classe são assíncronas e retorno um Task<bool> objeto.
O valor retornado será false se a animação for concluída, e true se a animação for cancelada. Portanto, os
métodos de animação normalmente devem ser usados com o await operador, que torna possível determinar
facilmente quando uma animação for concluída. Além disso, em seguida, torna possível criar animações
sequenciais com métodos de animação subsequente executados depois que o método anterior foi concluída. Para
obter mais informações, consulte composta animações.
Se houver um requisito para permitir que uma animação completa em segundo plano, em seguida, a await
operador pode ser omitido. Nesse cenário, os métodos de extensão de animação retornará rapidamente após
iniciar a animação, com a animação que ocorrem em segundo plano. Essa operação pode ser aproveitada durante
a criação de animações de composição. Para obter mais informações, consulte animações de composição.
Para obter mais informações sobre o await operador, consulte visão geral do suporte assíncrono.

Animações únicas
Cada método de extensão na ViewExtensions implementa uma operação única animação progressivamente altera
uma propriedade de um valor para outro valor por um período de tempo. Essa seção explora cada operação de
animação.
Rotação
O exemplo de código a seguir demonstra como usar o RotateTo método animar o Rotation propriedade de um
Image :

await image.RotateTo (360, 2000);


image.Rotation = 0;

Esse código é animado a Image instância, girando até 360 graus em 2 segundos (2000 milissegundos). O
RotateTo método obtém atual Rotation propriedade de valor para o início da animação e, em seguida, gira desse
valor para o seu primeiro argumento (360). Depois que a animação for concluída, a imagem Rotation
propriedade é redefinida como 0. Isso garante que o Rotation propriedade não permaneça em 360 depois que a
animação termina, o que impediria rotações adicionais.
As capturas de tela a seguir mostram a rotação em andamento em cada plataforma:

Rotação relativa
O exemplo de código a seguir demonstra como usar o RelRotateTo método para aumentar ou diminuir de forma
incremental o Rotation propriedade de um Image :

await image.RelRotateTo (360, 2000);

Esse código é animado a Image instância por mais de 2 segundos (2000 milissegundos) de rotação de 360 graus
de sua posição inicial. O RelRotateTo método obtém atual Rotation propriedade de valor para o início da
animação e, em seguida, gira desse valor para o valor mais seu primeiro argumento (360). Isso garante que cada
animação sempre será uma rotação de 360 graus a partir da posição inicial. Portanto, se uma nova animação será
invocada, enquanto uma animação já está em andamento, ele será iniciada a partir da posição atual e pode
terminar em uma posição que não é um incremento de 360 graus.
As capturas de tela a seguir mostram a rotação relativa em andamento em cada plataforma:

Dimensionamento
O exemplo de código a seguir demonstra como usar o ScaleTo método animar o Scale propriedade de um
Image :

await image.ScaleTo (2, 2000);

Esse código é animado a Image instância pelo escalar verticalmente para duas vezes o tamanho mais de 2
segundos (2000 milissegundos). O ScaleTo método obtém atual Scale valor da propriedade (valor padrão de 1)
para o início da animação e, em seguida, escalas desse valor para o seu primeiro argumento (2). Isso tem o efeito
de expansão do tamanho da imagem para duas vezes seu tamanho.
As capturas de tela a seguir mostram o dimensionamento em andamento em cada plataforma:
NOTE
O VisualElement classe define também ScaleX e ScaleY propriedades, que podem dimensionar o VisualElement
forma diferente no direções horizontal e vertical. Essas propriedades podem ser animadas com o Animation classe. Para
obter mais informações, consulte animações personalizadas no xamarin. Forms.

Relativo ao dimensionamento
O exemplo de código a seguir demonstra como usar o RelScaleTo método animar o Scale propriedade de um
Image :

await image.RelScaleTo (2, 2000);

Esse código é animado a Image instância pelo escalar verticalmente para duas vezes o tamanho mais de 2
segundos (2000 milissegundos). O RelScaleTo método obtém atual Scale valor da propriedade para o início da
animação e, em seguida, escalas desse valor para o valor mais seu primeiro argumento (2). Isso garante que cada
animação sempre será uma escala de 2 a partir da posição inicial.
Escala e rotação com âncoras
O AnchorX e AnchorY propriedades define o centro da escala ou rotação para a Rotation e Scale propriedades.
Portanto, seus valores também afetam a RotateTo e ScaleTo métodos.
Considerando um Image que foi colocado no Centro de um layout, o exemplo de código a seguir demonstra a
rotação a imagem em torno do centro do layout, definindo seu AnchorY propriedade:

image.AnchorY = (Math.Min (absoluteLayout.Width, absoluteLayout.Height) / 2) / image.Height;


await image.RotateTo (360, 2000);
Para girar o Image instância em torno do centro do layout, o AnchorX e AnchorY propriedades devem ser
definidas com valores que são relativa à largura e altura do Image . Neste exemplo, o centro do Image é definido
para ser no Centro de layout e, portanto, o padrão AnchorX valor de 0,5 não precisará ser alterada. No entanto, o
AnchorY propriedade será redefinida para ser um valor da parte superior do Image ao ponto central do layout.
Isso garante que o Image faz uma rotação completa de 360 graus em torno do ponto central do layout, conforme
mostrado nas capturas de tela seguir:

Conversão
O exemplo de código a seguir demonstra como usar o TranslateTo método animar o TranslationX e
TranslationY propriedades de um Image :

await image.TranslateTo (-100, -100, 1000);

Esse código é animado a Image instância, convertendo-lo horizontalmente e verticalmente mais de 1 segundo
(1000 milissegundos). O TranslateTo método simultaneamente traduz os pixels da imagem 100 para a esquerda
e para cima de 100 pixels. Isso ocorre porque o primeiro e segundo argumentos são os dois números negativos.
Fornecer números positivos convertem a imagem à direita e para baixo.
As capturas de tela a seguir mostram a tradução em andamento em cada plataforma:
NOTE
Se um elemento é inicialmente disposto fora da tela e, em seguida, convertido para a tela, após a tradução de entrada o
layout do elemento permanece fora da tela e o usuário não pode interagir com ele. Portanto, é recomendável que um modo
de exibição deve ser disposto em sua posição final e, em seguida, todas as exigidas traduções executadas.

Esmaecimento
O exemplo de código a seguir demonstra como usar o FadeTo método animar o Opacity propriedade de um
Image :

image.Opacity = 0;
await image.FadeTo (1, 4000);

Esse código é animado a Image instância pelo esmaecimento-lo em mais de 4 segundos (4000 milissegundos). O
FadeTo método obtém atual Opacity valor da propriedade para o início da animação e, em seguida, esmaece
desse valor para o seu primeiro argumento (1).
As capturas de tela a seguir mostram o esmaecimento em andamento em cada plataforma:
Animações compostas
Uma animação composta é uma combinação sequencial de animações e podem ser criada com o await operador,
conforme demonstrado no exemplo de código a seguir:

await image.TranslateTo (-100, 0, 1000); // Move image left


await image.TranslateTo (-100, -100, 1000); // Move image up
await image.TranslateTo (100, 100, 2000); // Move image diagonally down and right
await image.TranslateTo (0, 100, 1000); // Move image left
await image.TranslateTo (0, 0, 1000); // Move image up

Neste exemplo, o Image é convertido em 6 segundos (6000 milissegundos). A conversão do Image usa cinco
animações, com o await operador que indica que cada animação é executada sequencialmente. Portanto,
métodos de animação subsequente executadas depois que o método anterior foi concluída.

Animações de composição
Uma animação de composição é uma combinação de animações em que dois ou mais animações executados
simultaneamente. Animações de composição podem ser criadas pela mistura animações esperadas e não é
aguardada, conforme demonstrado no exemplo de código a seguir:

image.RotateTo (360, 4000);


await image.ScaleTo (2, 2000);
await image.ScaleTo (1, 2000);

Neste exemplo, o Image é dimensionado e girado simultaneamente mais de 4 segundos (4000 milissegundos). O
dimensionamento do Image usa duas animações sequenciais que ocorrem ao mesmo tempo que a rotação. O
RotateTo método é executado sem um await operador e retorna imediatamente, com o primeiro ScaleTo , em
seguida, a partir de animação. O await operador na primeira ScaleTo chamada de método atrasa a segunda
ScaleTo chamada de método até que a primeira ScaleTo chamada de método foi concluída. Neste momento a
RotateTo animação é metade forma concluída e o Image será girada 180 graus. Durante os últimos 2 segundos
(2000 milissegundos), a segunda ScaleTo animação e o RotateTo animação ambos concluir.
A execução simultânea de vários métodos assíncronos
O static Task.WhenAny e Task.WhenAll métodos são usados para executar vários métodos assíncronos
simultaneamente e, portanto, pode ser usados para criar animações de composição. Ambos os métodos retornam
um Task do objeto e aceitar uma coleção de métodos de retorno que cada um Task objeto. O Task.WhenAny
método é concluído quando qualquer método em sua coleção conclui a execução, conforme demonstrado no
exemplo de código a seguir:

await Task.WhenAny<bool>
(
image.RotateTo (360, 4000),
image.ScaleTo (2, 2000)
);
await image.ScaleTo (1, 2000);

Neste exemplo, o Task.WhenAny chamada de método contém duas tarefas. A primeira tarefa gira a imagem mais
de 4 segundos (4000 milissegundos), e a segunda tarefa redimensiona a imagem mais de 2 segundos (2000
milissegundos). Quando a segunda tarefa é concluída, o Task.WhenAny chamada de método é concluída. No
entanto, mesmo que o RotateTo método ainda está em execução, a segunda ScaleTo método pode começar.
O Task.WhenAll método é concluído quando tem concluído todos os métodos em sua coleção, conforme
demonstrado no exemplo de código a seguir:

// 10 minute animation
uint duration = 10 * 60 * 1000;

await Task.WhenAll (
image.RotateTo (307 * 360, duration),
image.RotateXTo (251 * 360, duration),
image.RotateYTo (199 * 360, duration)
);

Neste exemplo, o Task.WhenAll chamada de método contém três tarefas, cada uma delas executa mais de 10
minutos. Cada Task faz com que um número diferente de rotações de 360 graus – 307 rotações para RotateTo ,
251 rotações para RotateXTo e as 199 rotações para RotateYTo . Esses valores são números primos, portanto,
garantindo que as rotações não estão sincronizadas e, portanto, não resultará em padrões repetitivos.
As capturas de tela a seguir mostram as rotações vários em andamento em cada plataforma:
Cancelando a animações
Um aplicativo pode cancelar uma ou mais animações com uma chamada para o static
ViewExtensions.CancelAnimations método, conforme demonstrado no exemplo de código a seguir:

ViewExtensions.CancelAnimations (image);

Isso cancelará todas as animações que estão sendo executados no imediatamente a Image instância.

Resumo
Este artigo demonstrou criando e Cancelando animações usando o ViewExtensions classe. Essa classe fornece
métodos de extensão que podem ser usados para construir animações simples que giram, dimensionarem,
traduzam e fade VisualElement instâncias.

Links relacionados
Visão geral do suporte assíncrono
Animação básica (amostra)
ViewExtensions
Funções de easing no xamarin. Forms
12/04/2019 • 7 minutes to read

baixar o exemplo
Xamarin. Forms inclui uma classe de atenuação que permite que você especifique uma função de transferência
que controla como as animações aceleram ou diminuir como elas estão em execução. Este artigo demonstra
como utilizar as funções de easing predefinidas e como criar funções de easing personalizadas.
O Easing classe define um número de funções de easing que podem ser consumidos por animações:
O BounceIn função de easing bounces a animação no início.
O BounceOut função de easing bounces a animação no final.
O CubicIn função de easing lentamente acelera a animação.
O CubicInOut função de easing acelera a animação no início e desacelerada a animação no final.
O CubicOut função de easing rapidamente desacelerada a animação.
O Linear função de easing usa uma velocidade constante e é o padrão a função de easing.
O SinIn função de easing suavemente acelera a animação.
O SinInOut função de easing suavemente acelera a animação no início e desacelerada suavemente a animação
no final.
O SinOut função de easing suavemente desacelerada a animação.
O SpringIn função de easing faz com que a animação acelerar rapidamente até o final.
O SpringOut função de easing faz com que a animação de desacelerar rapidamente até o final.
O In e Out sufixos que indicam se o efeito fornecido pela função de easing é perceptível no início da animação,
no final, ou ambos.
Além disso, as funções de easing personalizadas podem ser criadas. Para obter mais informações, consulte
funções de Easing personalizada.

Consumindo uma função de Easing


Os métodos de extensão de animação na ViewExtensions classe permitem que uma função de easing a ser
especificado como o parâmetro de método final, conforme demonstrado no exemplo de código a seguir:

await image.TranslateTo(0, 200, 2000, Easing.BounceIn);


await image.ScaleTo(2, 2000, Easing.CubicIn);
await image.RotateTo(360, 2000, Easing.SinInOut);
await image.ScaleTo(1, 2000, Easing.CubicOut);
await image.TranslateTo(0, -200, 2000, Easing.BounceOut);

Especificando uma função de easing para uma animação, a velocidade da animação se torna não lineares e produz
o efeito fornecido pela função de easing. A omissão de uma função de easing durante a criação de uma animação
faz com que a animação usar o padrão Linear facilitando a função, que produz uma velocidade linear.
Para obter mais informações sobre como usar os métodos de extensão de animação na ViewExtensions da classe,
consulte animações simples. Funções de easing também podem ser consumidas pela Animation classe. Para obter
mais informações, consulte animações personalizadas.
Funções de Easing personalizado
Há três abordagens principais para a criação de uma função de easing personalizada:
1. Criar um método que usa um double argumento e retorna um double resultado.
2. Criará um Func<double, double> .
3. Especifica a função de easing como o argumento para o Easing construtor.
Em todos os três casos, a função de easing personalizada deve retornar 0 para um argumento de 0 e 1 para um
argumento de 1. No entanto, qualquer valor pode ser retornado entre os valores de argumento de 0 e 1. Cada
abordagem agora será discutida detalhadamente.
Método de Easing personalizado
Uma função de easing personalizada pode ser definida como um método que usa um double argumento e
retorna um double resultar, conforme demonstrado no exemplo de código a seguir:

await image.TranslateTo(0, 200, 2000, CustomEase);

double CustomEase (double t)


{
return t == 0 || t == 1 ? t : (int)(5 * t) / 5.0;
}

O CustomEase método truncará o valor de entrada para os valores 0, 0.2, 0,4, 0,6, 0,8 e 1. Portanto, o Image
instância é convertida em pequenos saltos, em vez de sem problemas.
Easing Func personalizado
Uma função de easing personalizada também pode ser definida como um Func<double, double> , conforme
demonstrado no exemplo de código a seguir:

Func<double, double> CustomEase = t => 9 * t * t * t - 13.5 * t * t + 5.5 * t;


await image.TranslateTo(0, 200, 2000, CustomEase));

O CustomEase Func representa uma função de easing começa rápidos e mais lento e inverte o curso e, em
seguida, reverte curso novamente para acelerar rapidamente até o final. Portanto, embora a movimentação geral
do Image instância é para baixo, ele também temporariamente inverte o curso no meio da animação.
Construtor de Easing personalizado
Uma função de easing personalizada também pode ser definida como o argumento para o Easing construtor,
conforme demonstrado no exemplo de código a seguir:

await image.TranslateTo (0, 200, 2000, new Easing (t => 1 - Math.Cos (10 * Math.PI * t) * Math.Exp (-5 * t)));

A função de easing personalizada é especificada como um argumento de função lambda para o Easing construtor
e usa o Math.Cos método para criar um efeito de soltar lento é amortecido pelo Math.Exp método. Portanto, o
Image instância é convertida para que ele apareça descartar ao seu local de repouso final.

Resumo
Este artigo demonstrou como utilizar as funções de easing predefinidas e como criar funções de easing
personalizadas. Xamarin. Forms inclui um Easing classe que permite que você especifique uma função de
transferência que controla como as animações acelerar ou diminuir como elas estão em execução.
Links relacionados
Visão geral do suporte assíncrono
Funções de easing (amostra)
Atenuação
ViewExtensions
Animações personalizadas no xamarin. Forms
12/04/2019 • 19 minutes to read

baixar o exemplo
A classe de animação é o bloco de construção de todas as animações de xamarin. Forms, com os métodos de
extensão na classe ViewExtensions criando um ou mais objetos de animação. Este artigo demonstra como usar a
classe de animação para criar e Cancelar animações, sincronizar várias animações e criar animações
personalizadas que animar propriedades que não estão animadas pelos métodos de animação existentes.
Um número de parâmetros deve ser especificado durante a criação de um Animation objeto, incluindo os valores
inicial e final da propriedade sendo animada e um retorno de chamada que altera o valor da propriedade. Um
Animation objeto também pode manter uma coleção de animações filho que podem ser executados e
sincronizadas. Para obter mais informações, consulte animações filho.
Executar uma animação criada com o Animation classe, que pode ou não incluir animações filho, é obtida
chamando o Commit método. Esse método Especifica a duração da animação e, entre outros itens, um retorno de
chamada que controla se deve repetir a animação.

Criação de uma animação


Ao criar uma Animation do objeto, normalmente, um mínimo de três parâmetros são necessários, conforme
demonstrado no exemplo de código a seguir:

var animation = new Animation (v => image.Scale = v, 1, 2);

Esse código define uma animação do Scale propriedade de uma Image instância de um valor de 1 para um
valor de 2. O valor animado, o que é derivado por xamarin. Forms, é passado ao retorno de chamada especificado
como o primeiro argumento, em que ele é usado para alterar o valor da Scale propriedade.
A animação é iniciada com uma chamada para o Commit método, conforme demonstrado no exemplo de código
a seguir:

animation.Commit (this, "SimpleAnimation", 16, 2000, Easing.Linear, (v, c) => image.Scale = 1, () => true);

Observe que o Commit método não retorna um Task objeto. Em vez disso, as notificações são fornecidas por
meio de métodos de retorno de chamada.
Os argumentos a seguir são especificados no Commit método:
O primeiro argumento (proprietário) identifica o proprietário da animação. Isso pode ser o elemento visual na
qual a animação é aplicada, ou outro elemento visual, como a página.
O segundo argumento (nome) identifica a animação com um nome. O nome é combinado com o proprietário
para identificar exclusivamente a animação. Essa identificação exclusiva, em seguida, pode ser usada para
determinar se a animação está em execução ( AnimationIsRunning ), ou para cancelá-la ( AbortAnimation ).
O terceiro argumento (taxa) indica o número de milissegundos entre cada chamada para o método de retorno
de chamada definido na Animation construtor
O quarto argumento ( comprimento) indica a duração da animação, em milissegundos.
O quinto argumento (atenuação) define a função de easing a ser usado na animação. Como alternativa, a
função de easing pode ser especificada como um argumento para o Animation construtor. Para obter mais
informações sobre funções de easing, consulte funções de Easing.
O sexto argumento (concluído) é um retorno de chamada que será executado quando a animação for
concluída. Esse retorno de chamada usa dois argumentos, com o primeiro argumento que indica um valor
final e o segundo argumento que está sendo uma bool que é definido como true se a animação foi
cancelada. Como alternativa, o concluída retorno de chamada pode ser especificado como um argumento para
o Animation construtor. No entanto, com uma única animação, se concluída retornos de chamada
especificados em ambos o Animation construtor e o Commit método, apenas o retorno de chamada
especificado no Commit método será executado.
O sétimo argumento (Repita) é um retorno de chamada que permite que a animação ser repetida. Ele é
chamado no final da animação e retornando true indica que a animação deve ser repetida.

O efeito geral é criar uma animação que aumenta a Scale propriedade de uma Image de 1 a 2, mais de 2
segundos (2000 milissegundos), usando o Linear função de easing. Cada vez que a animação for concluída, seu
Scale propriedade é redefinida como 1 e a animação se repete.

NOTE
Animações simultâneas, que são executados independentemente uns dos outros podem ser construídas com a criação de
um Animation do objeto para cada animação e, em seguida, chamar o Commit método em cada animação.

Animações filho
O Animation classe também dá suporte a animações filho, que envolve a criação de uma Animation objeto para
os quais outros Animation objetos são adicionados. Isso permite que uma série de animações a ser executado e
sincronizadas. O exemplo de código a seguir demonstra como criar e executar animações filho:

var parentAnimation = new Animation ();


var scaleUpAnimation = new Animation (v => image.Scale = v, 1, 2, Easing.SpringIn);
var rotateAnimation = new Animation (v => image.Rotation = v, 0, 360);
var scaleDownAnimation = new Animation (v => image.Scale = v, 2, 1, Easing.SpringOut);

parentAnimation.Add (0, 0.5, scaleUpAnimation);


parentAnimation.Add (0, 1, rotateAnimation);
parentAnimation.Add (0.5, 1, scaleDownAnimation);

parentAnimation.Commit (this, "ChildAnimations", 16, 4000, null, (v, c) => SetIsEnabledButtonState (true,
false));

Como alternativa, o exemplo de código pode ser gravado mais concisa, conforme demonstrado no exemplo de
código a seguir:

new Animation {
{ 0, 0.5, new Animation (v => image.Scale = v, 1, 2) },
{ 0, 1, new Animation (v => image.Rotation = v, 0, 360) },
{ 0.5, 1, new Animation (v => image.Scale = v, 2, 1) }
}.Commit (this, "ChildAnimations", 16, 4000, null, (v, c) => SetIsEnabledButtonState (true, false));

Nos dois exemplos de código, um pai Animation objeto é criado, no qual adicionais Animation objetos são
adicionados. Os dois primeiros argumentos para o Add método especifique quando deve começar e terminar a
animação de filho. Os valores de argumento devem ser entre 0 e 1 e representar o período relativo dentro da
animação pai que a animação filho especificado estará ativa. Portanto, no exemplo o scaleUpAnimation ficará ativo
para a primeira metade da animação, o scaleDownAnimation ficará ativo para a segunda metade da animação e o
rotateAnimation estará ativo durante todo o período.
O efeito geral é que a animação ocorre mais de 4 segundos (4000 milissegundos). O scaleUpAnimation anima a
Scale propriedade de 1 a 2, mais de 2 segundos. O scaleDownAnimation , em seguida, anima a Scale
propriedade de 2 para 1, mais de 2 segundos. Embora ambas as animações de escala estão ocorrendo, o
rotateAnimation anima a Rotation propriedade de 0 a 360, mais de 4 segundos. Observe que as animações de
escala também usam funções de easing. O SpringIn função de easing faz com que o Image reduzir inicialmente
antes de obter maior e o SpringOut função de easing faz com que o Image se torne menor do que seu tamanho
real até o final da animação completa.
Há várias diferenças entre um Animation objeto que usa animações filho e outro que não:
Ao usar animações filho, o concluída retorno de chamada em uma animação de filho indica quando o filho for
concluída e o concluída retorno de chamada passada para o Commit método indica quando o toda animação
foi concluída.
Ao usar animações filho, retornando true do Repita retorno de chamada a Commit método não fará com que
a animação ser repetida, mas a animação será continuarão sendo executados sem novos valores.
Ao incluir uma função de easing a Commit método e a função de easing retorna um valor maior que 1, a
animação será encerrada. Se a função de easing retorna um valor menor que 0, o valor será fixado como 0.
Para usar uma função de easing que retorna um valor menor que 0 ou maior que 1, ele deve ser especificado
em uma das animações filho, em vez de no Commit método.

O Animation classe também inclui WithConcurrent métodos que podem ser usados para adicionar animações
filho a um pai Animation objeto. No entanto, suas começar e concluir valores de argumento não são restritos
para 0 para 1, mas apenas essa parte da animação filho que corresponde a um intervalo de 0 a 1 estará ativa. Por
exemplo, se um WithConcurrent chamada de método define uma animação de filho que tem como alvo um
Scale propriedade de 1 a 6, mas com começar e concluir valores de -2 e 3, o começar valor de -2 corresponde a
um Scale valor de 1 e o concluir valor 3 corresponde a um Scale valor de 6. Porque valores fora do intervalo
de 0 e 1 não reproduzir nenhuma parte em uma animação, o Scale propriedade apenas será ser animada de 3 a
6.

Cancelando uma animação


Um aplicativo pode cancelar uma animação com uma chamada para o AbortAnimation método de extensão,
como demonstrado no exemplo de código a seguir:

this.AbortAnimation ("SimpleAnimation");

Observe que as animações são identificadas exclusivamente por uma combinação do proprietário de animação e
o nome da animação. Portanto, o proprietário e o nome especificado ao executar a animação deve ser
especificado para cancelar a animação. Portanto, o exemplo de código imediatamente cancelará a animação
chamada SimpleAnimation que pertence a página.

Criar uma animação personalizada


Os exemplos mostrados aqui até agora demonstraram animações igualmente pode ser obtidas com os métodos
de ViewExtensions classe. No entanto, a vantagem dos Animation classe é que ele tenha acesso para o método
de retorno de chamada, que é executado quando o valor animado é alterado. Isso permite que o retorno de
chamada implementar qualquer animação desejada. Por exemplo, o exemplo de código a seguir anima a
BackgroundColor propriedade de uma página definindo-a como Color valores criados pelo Color.FromHsla
método, com valores de matiz, variando de 0 a 1:
new Animation (callback: v => BackgroundColor = Color.FromHsla (v, 1, 0.5),
start: 0,
end: 1).Commit (this, "Animation", 16, 4000, Easing.Linear, (v, c) => BackgroundColor = Color.Default);

A animação resultante fornece a aparência de aprimorando o plano de fundo da página por meio das cores do
arco-íris.
Para obter mais exemplos de criação de animações complexas, incluindo uma animação de curva de Bézier,
consulte capítulo 22 dos criação de aplicativos móveis com xamarin. Forms.

Criando um método de extensão de animação personalizada


Os métodos de extensão na ViewExtensions classe animar uma propriedade de seu valor atual para um valor
especificado. Isso dificulta a criação, por exemplo, um ColorTo método de animação que pode ser usado para
animar uma cor de um valor para outro, porque:
As únicas Color propriedade definida pelo VisualElement classe é BackgroundColor , que nem sempre é o
desejado Color propriedade para animar.
Geralmente, o valor atual de um Color é de propriedade Color.Default , que não é uma cor real, e que não
pode ser usado em cálculos de interpolação.
A solução para esse problema é não ter o ColorTo método de um determinado destino Color propriedade. Em
vez disso, ele pode ser escrito com um método de retorno de chamada que transmite o interpolada Color valor
para o chamador. Além disso, o método será levar o início e término Color argumentos.
O ColorTo método pode ser implementado como um método de extensão que usa o Animate método na
AnimationExtensions classe para fornecer sua funcionalidade. Isso ocorre porque o Animate método pode ser
usado para propriedades de destino que não são do tipo double , conforme demonstrado no exemplo de código a
seguir:

public static class ViewExtensions


{
public static Task<bool> ColorTo(this VisualElement self, Color fromColor, Color toColor, Action<Color>
callback, uint length = 250, Easing easing = null)
{
Func<double, Color> transform = (t) =>
Color.FromRgba(fromColor.R + t * (toColor.R - fromColor.R),
fromColor.G + t * (toColor.G - fromColor.G),
fromColor.B + t * (toColor.B - fromColor.B),
fromColor.A + t * (toColor.A - fromColor.A));
return ColorAnimation(self, "ColorTo", transform, callback, length, easing);
}

public static void CancelAnimation(this VisualElement self)


{
self.AbortAnimation("ColorTo");
}

static Task<bool> ColorAnimation(VisualElement element, string name, Func<double, Color> transform,


Action<Color> callback, uint length, Easing easing)
{
easing = easing ?? Easing.Linear;
var taskCompletionSource = new TaskCompletionSource<bool>();

element.Animate<Color>(name, transform, callback, 16, length, easing, (v, c) =>


taskCompletionSource.SetResult(c));
return taskCompletionSource.Task;
}
}
O Animate método exige um transformar argumento, que é um método de retorno de chamada. A entrada para
esse retorno de chamada é sempre um double variando de 0 a 1. Portanto, o ColorTo método define sua própria
transformação Func que aceita um double variando de 0 a 1 e que retorna um Color valor correspondente a
esse valor. O Color valor é calculado pela interpolação a R , G , B , e A valores dos dois fornecidos Color
argumentos. O Color valor é então passado para o método de retorno de chamada para o aplicativo para uma
determinada propriedade.
Essa abordagem permite que o ColorTo método para animar qualquer Color propriedade, conforme
demonstrado no exemplo de código a seguir:

await Task.WhenAll(
label.ColorTo(Color.Red, Color.Blue, c => label.TextColor = c, 5000),
label.ColorTo(Color.Blue, Color.Red, c => label.BackgroundColor = c, 5000));
await this.ColorTo(Color.FromRgb(0, 0, 0), Color.FromRgb(255, 255, 255), c => BackgroundColor = c, 5000);
await boxView.ColorTo(Color.Blue, Color.Red, c => boxView.Color = c, 4000);

Neste exemplo de código, o ColorTo método anima a TextColor e BackgroundColor propriedades de um Label ,
a BackgroundColor propriedade de uma página e o Color propriedade de um BoxView .

Resumo
Este artigo demonstrou como usar o Animation classe para criar e Cancelar animações, sincronizar várias
animações e criar animações personalizadas que animar propriedades que não estão animadas pela animação
existente métodos. O Animation classe é o bloco de construção de todas as animações de xamarin. Forms.

Links relacionados
Animações personalizadas (amostra)
Animação
AnimationExtensions
Xamarin. Forms BoxView
12/04/2019 • 28 minutes to read

baixar o exemplo
BoxView renderiza um retângulo simples de uma largura especificada, altura e cor. Você pode usar BoxView para
decoração, gráficos rudimentares e para interação com o usuário por meio de toque.
Porque o xamarin. Forms não tem um sistema de elementos gráficos de vetor internos, o BoxView ajuda a
compensar. Alguns dos programas de exemplo descritos neste artigo usam BoxView para processamento de
gráficos. O BoxView podem ser dimensionados para se parecer com uma linha de uma largura específica e a
espessura e, em seguida, girado usando qualquer ângulo a Rotation propriedade.
Embora BoxView pode imitar o elementos gráficos simples, talvez você queira investigar usar SkiaSharp em
xamarin. Forms para requisitos de elementos gráficos mais sofisticados.
Este artigo discute os seguintes tópicos:
Definindo BoxView cor e tamanho – definir o BoxView propriedades.
Decorações de texto de renderização – usar um BoxView para linhas de renderização.
A listagem de cores com BoxView – exibir todas as cores do sistema em um ListView .
Reproduzir o jogo da vida útil pela criação de subclasses BoxView – implementar um mecanismo de
celular famoso.
Criação de um relógio Digital – simular uma exibição de matriz de pontos.
Criação de um relógio analógico – transformar e animar BoxView elementos.

Configuração BoxView cor e tamanho


Normalmente, você definirá as propriedades a seguir de BoxView :
Color Para definir sua cor.
CornerRadius Para definir seu raio de canto.
WidthRequest Para definir a largura do BoxView em unidades independentes de dispositivo.
HeightRequest Para definir a altura do BoxView .

O Color propriedade é do tipo Color ; a propriedade pode ser definida para qualquer Color valor, incluindo os
141 campos estáticos de somente leitura de chamado colors desde em ordem alfabética AliceBlue para
YellowGreen .

O CornerRadius propriedade é do tipo CornerRadius ; a propriedade pode ser definida como um único double
uniforme por valor de raio de canto, ou um CornerRadius estrutura definida por quatro double valores que são
aplicados a a parte superior esquerda, superior direita, parte inferior esquerda e inferior direita do BoxView .
O WidthRequest e HeightRequest propriedades desempenham uma função somente se o BoxView é irrestrita no
layout. Esse é o caso quando o contêiner de layout precisa saber o filho do tamanho, por exemplo, quando o
BoxView é um filho de uma célula de dimensionamento automático no Grid layout. Um BoxView também é
irrestrita quando seus HorizontalOptions e VerticalOptions propriedades são definidas como valores diferentes
de LayoutOptions.Fill . Se o BoxView irrestrita, mas o WidthRequest e HeightRequest não são definidas e, em
seguida, a largura ou altura são definidos como valores padrão de 40 unidades ou cerca de 1/4 polegadas em
dispositivos móveis.
O WidthRequest e HeightRequest propriedades são ignoradas se o BoxView é restrita no layout, nesse caso, o
contêiner de layout impõe seu próprio tamanho no BoxView .
Um BoxView pode ser restrito em uma dimensão e sem restrições no outro. Por exemplo, se o BoxView é um filho
de um vertical StackLayout , a dimensão vertical do BoxView é irrestrita e sua dimensão horizontal geralmente é
restrito. Mas há exceções para a dimensão horizontal: se o BoxView tem sua HorizontalOptions propriedade
definida como algo diferente de LayoutOptions.Fill , em seguida, a dimensão horizontal também é irrestrita.
Também é possível que o StackLayout em si para ter uma dimensão horizontal irrestrita, caso em que o BoxView
também será horizontalmente irrestrita.
O BasicBoxView exemplo exibe um one-polegadas-quadrado irrestrita BoxView no centro da sua página:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:BasicBoxView"
x:Class="BasicBoxView.MainPage">

<BoxView Color="CornflowerBlue"
CornerRadius="10"
WidthRequest="160"
HeightRequest="160"
VerticalOptions="Center"
HorizontalOptions="Center" />

</ContentPage>

Aqui está o resultado:

Se o VerticalOptions e HorizontalOptions propriedades são removidas do BoxView marca ou são definidas com
Fill , em seguida, a BoxView fica restrito pelo tamanho da página e se expande para preencher a página.
Um BoxView também pode ser um filho de um AbsoluteLayout . Nesse caso, o local e o tamanho da BoxView são
definidos usando o LayoutBounds propriedade associável anexada. O AbsoluteLayout é discutida no artigo
AbsoluteLayout.
Você verá exemplos de todos esses casos nos programas de exemplo a seguir.

Decorações de texto de renderização


Você pode usar o BoxView para adicionar alguns decorações simples em suas páginas na forma de linhas
horizontais e verticais. O TextDecoration demonstra isso. Todos os visuais do programa são definidos na
MainPage. XAML arquivo, que contém vários Label e BoxView elementos no StackLayout mostrado aqui:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:TextDecoration"
x:Class="TextDecoration.MainPage">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="0, 20, 0, 0" />
</OnPlatform>
</ContentPage.Padding>

<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="BoxView">
<Setter Property="Color" Value="Black" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>

<ScrollView Margin="15">
<StackLayout>

···

</StackLayout>
</ScrollView>
</ContentPage>

A marcação que segue todas são filhos do StackLayout . Essa marcação consiste em vários tipos de decorativos
BoxView elementos usados com o Label elemento:

O cabeçalho com estilo na parte superior da página é obtido com um AbsoluteLayout cujos filhos são os quatro
BoxView elementos e um Label , todos os de quais são atribuídas a locais específicos e tamanhos:
<AbsoluteLayout>
<BoxView AbsoluteLayout.LayoutBounds="0, 10, 200, 5" />
<BoxView AbsoluteLayout.LayoutBounds="0, 20, 200, 5" />
<BoxView AbsoluteLayout.LayoutBounds="10, 0, 5, 65" />
<BoxView AbsoluteLayout.LayoutBounds="20, 0, 5, 65" />
<Label Text="Stylish Header"
FontSize="24"
AbsoluteLayout.LayoutBounds="30, 25, AutoSize, AutoSize"/>
</AbsoluteLayout>

No arquivo XAML, o AbsoluteLayout é seguido por um Label com o texto formatado que descreve o
AbsoluteLayout .

Uma cadeia de caracteres de texto pode ser sublinhar colocando ambos os Label e BoxView em um StackLayout
que tem seu HorizontalOptions valor definido como algo diferente de Fill . A largura do StackLayout , em
seguida, é governada pela largura do Label , que então impõe essa largura no BoxView . O BoxView é atribuído
uma explícita de altura:

<StackLayout HorizontalOptions="Center">
<Label Text="Underlined Text"
FontSize="24" />
<BoxView HeightRequest="2" />
</StackLayout>

Você não pode usar essa técnica para sublinhar palavras individuais em mais cadeias de caracteres de texto ou um
parágrafo.
Também é possível usar um BoxView se pareça com uma marca HTML hr elemento (régua horizontal).
Simplesmente permitir que a largura do BoxView ser determinado por seu contêiner pai, que nesse caso é o
StackLayout :

<BoxView HeightRequest="3" />

Por fim, você pode desenhar uma linha vertical em um dos lados de um parágrafo de texto, colocando ambos os
BoxView e o Label na horizontal StackLayout . Nesse caso, a altura do BoxView é o mesmo que a altura da
StackLayout , que é controlado pela altura do Label :

<StackLayout Orientation="Horizontal">
<BoxView WidthRequest="4"
Margin="0, 0, 10, 0" />
<Label>

···

</Label>
</StackLayout>

A listagem de cores com BoxView


O BoxView é conveniente para a exibição de cores. Esse programa usa uma ListView para listar todos os campos
estáticos públicos somente leitura do xamarin. Forms Color estrutura:
O ListViewColors programa inclui uma classe chamada NamedColor . O construtor estático usa a reflexão para
acessar todos os campos do Color estruturar e criar um NamedColor objeto para cada uma delas. Eles são
armazenados no estático All propriedade:

public class NamedColor


{
// Instance members.
private NamedColor()
{
}

public string Name { private set; get; }

public string FriendlyName { private set; get; }

public Color Color { private set; get; }

public string RgbDisplay { private set; get; }

// Static members.
static NamedColor()
{
List<NamedColor> all = new List<NamedColor>();
StringBuilder stringBuilder = new StringBuilder();

// Loop through the public static fields of the Color structure.


foreach (FieldInfo fieldInfo in typeof(Color).GetRuntimeFields ())
{
if (fieldInfo.IsPublic &&
fieldInfo.IsStatic &&
fieldInfo.FieldType == typeof (Color))
{
// Convert the name to a friendly name.
string name = fieldInfo.Name;
stringBuilder.Clear();
int index = 0;

foreach (char ch in name)


{
if (index != 0 && Char.IsUpper(ch))
{
stringBuilder.Append(' ');
}
stringBuilder.Append(ch);
index++;
}
}

// Instantiate a NamedColor object.


Color color = (Color)fieldInfo.GetValue(null);

NamedColor namedColor = new NamedColor


{
Name = name,
FriendlyName = stringBuilder.ToString(),
Color = color,
RgbDisplay = String.Format("{0:X2}-{1:X2}-{2:X2}",
(int)(255 * color.R),
(int)(255 * color.G),
(int)(255 * color.B))
};

// Add it to the collection.


all.Add(namedColor);
}
}
all.TrimExcess();
All = all;
}

public static IList<NamedColor> All { private set; get; }


}

Os visuais do programa são descritos no arquivo XAML. O ItemsSource propriedade do ListView é definido
como estático NamedColor.All propriedade, o que significa que o ListView exibe todos os individuais NamedColor
objetos:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:ListViewColors"
x:Class="ListViewColors.MainPage">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="10, 20, 10, 0" />
<On Platform="Android, UWP" Value="10, 0" />
</OnPlatform>
</ContentPage.Padding>

<ListView SeparatorVisibility="None"
ItemsSource="{x:Static local:NamedColor.All}">
<ListView.RowHeight>
<OnPlatform x:TypeArguments="x:Int32">
<On Platform="iOS, Android" Value="80" />
<On Platform="UWP" Value="90" />
</OnPlatform>
</ListView.RowHeight>

<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ContentView Padding="5">
<Frame OutlineColor="Accent"
Padding="10">
<StackLayout Orientation="Horizontal">
<BoxView Color="{Binding Color}"
WidthRequest="50"
HeightRequest="50" />
<StackLayout>
<Label Text="{Binding FriendlyName}"
FontSize="22"
VerticalOptions="StartAndExpand" />
<Label Text="{Binding RgbDisplay, StringFormat='RGB = {0}'}"
FontSize="16"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</StackLayout>
</Frame>
</ContentView>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>

O NamedColor objetos são formatados pelo ViewCell objeto que é definido como o modelo de dados do
ListView . Esse modelo inclui uma BoxView cujos Color propriedade está associada a Color propriedade do
NamedColor objeto.

Jogar o jogo da vida pela criação de subclasses BoxView


O jogo de vida é um mecanismo de celular inventado por matemático John Conway e popularizada nas páginas
do Scientific American na década de 1970. Uma boa introdução é fornecida pelo artigo da Wikipedia jogo da vida
útil de Conway da.
O xamarin. Forms GameOfLife programa define uma classe chamada LifeCell que deriva de BoxView . Essa
classe encapsula a lógica de uma célula individual no jogo de vida:
class LifeCell : BoxView
{
bool isAlive;

public event EventHandler Tapped;

public LifeCell()
{
BackgroundColor = Color.White;

TapGestureRecognizer tapGesture = new TapGestureRecognizer();


tapGesture.Tapped += (sender, args) =>
{
Tapped?.Invoke(this, EventArgs.Empty);
};
GestureRecognizers.Add(tapGesture);
}

public int Col { set; get; }

public int Row { set; get; }

public bool IsAlive


{
set
{
if (isAlive != value)
{
isAlive = value;
BackgroundColor = isAlive ? Color.Black : Color.White;
}
}
get
{
return isAlive;
}
}
}

LifeCell adiciona três propriedades para BoxView : o Col e Row propriedades armazenam a posição da célula
dentro da grade e o IsAlive propriedade indica seu estado. O IsAlive também define uma propriedade de
Color propriedade do BoxView para preto, se a célula estiver ativo e em branco se a célula não está ativa.

LifeCell também instala um TapGestureRecognizer para permitir que o usuário alterne o estado de células
tocando-los. A classe converte a Tapped o reconhecedor de gestos em seu próprio evento Tapped evento.
O GameOfLife programa também inclui um LifeGrid classe que encapsula a maior parte da lógica do jogo, e
um MainPage classe que manipula os visuais do programa. Esses incluem uma sobreposição que descreve as
regras do jogo. Este é o programa em ação mostrando umas centenas LifeCell objetos na página:
Criação de um relógio Digital
O DotMatrixClock programa cria 210 BoxView elementos para simular os pontos de uma exibição de 5 por 7
matricial antigo. Você pode ler a hora no modo retrato ou paisagem, mas maior no cenário:

O arquivo XAML pouco mais de instanciar o AbsoluteLayout usado para o relógio:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DotMatrixClock"
x:Class="DotMatrixClock.MainPage"
Padding="10"
SizeChanged="OnPageSizeChanged">

<AbsoluteLayout x:Name="absoluteLayout"
VerticalOptions="Center" />
</ContentPage>

Todo o resto ocorre no arquivo code-behind. A lógica de exibição de matriz de pontos é bastante simplificada com
a definição de várias matrizes que descrevem os pontos correspondentes a cada um dos 10 dígitos e dois-pontos:
public partial class MainPage : ContentPage
{
// Total dots horizontally and vertically.
const int horzDots = 41;
const int vertDots = 7;

// 5 x 7 dot matrix patterns for 0 through 9.


static readonly int[, ,] numberPatterns = new int[10, 7, 5]
{
{
{ 0, 1, 1, 1, 0}, { 1, 0, 0, 0, 1}, { 1, 0, 0, 1, 1}, { 1, 0, 1, 0, 1},
{ 1, 1, 0, 0, 1}, { 1, 0, 0, 0, 1}, { 0, 1, 1, 1, 0}
},
{
{ 0, 0, 1, 0, 0}, { 0, 1, 1, 0, 0}, { 0, 0, 1, 0, 0}, { 0, 0, 1, 0, 0},
{ 0, 0, 1, 0, 0}, { 0, 0, 1, 0, 0}, { 0, 1, 1, 1, 0}
},
{
{ 0, 1, 1, 1, 0}, { 1, 0, 0, 0, 1}, { 0, 0, 0, 0, 1}, { 0, 0, 0, 1, 0},
{ 0, 0, 1, 0, 0}, { 0, 1, 0, 0, 0}, { 1, 1, 1, 1, 1}
},
{
{ 1, 1, 1, 1, 1}, { 0, 0, 0, 1, 0}, { 0, 0, 1, 0, 0}, { 0, 0, 0, 1, 0},
{ 0, 0, 0, 0, 1}, { 1, 0, 0, 0, 1}, { 0, 1, 1, 1, 0}
},
{
{ 0, 0, 0, 1, 0}, { 0, 0, 1, 1, 0}, { 0, 1, 0, 1, 0}, { 1, 0, 0, 1, 0},
{ 1, 1, 1, 1, 1}, { 0, 0, 0, 1, 0}, { 0, 0, 0, 1, 0}
},
{
{ 1, 1, 1, 1, 1}, { 1, 0, 0, 0, 0}, { 1, 1, 1, 1, 0}, { 0, 0, 0, 0, 1},
{ 0, 0, 0, 0, 1}, { 1, 0, 0, 0, 1}, { 0, 1, 1, 1, 0}
},
{
{ 0, 0, 1, 1, 0}, { 0, 1, 0, 0, 0}, { 1, 0, 0, 0, 0}, { 1, 1, 1, 1, 0},
{ 1, 0, 0, 0, 1}, { 1, 0, 0, 0, 1}, { 0, 1, 1, 1, 0}
},
{
{ 1, 1, 1, 1, 1}, { 0, 0, 0, 0, 1}, { 0, 0, 0, 1, 0}, { 0, 0, 1, 0, 0},
{ 0, 1, 0, 0, 0}, { 0, 1, 0, 0, 0}, { 0, 1, 0, 0, 0}
},
{
{ 0, 1, 1, 1, 0}, { 1, 0, 0, 0, 1}, { 1, 0, 0, 0, 1}, { 0, 1, 1, 1, 0},
{ 1, 0, 0, 0, 1}, { 1, 0, 0, 0, 1}, { 0, 1, 1, 1, 0}
},
{
{ 0, 1, 1, 1, 0}, { 1, 0, 0, 0, 1}, { 1, 0, 0, 0, 1}, { 0, 1, 1, 1, 1},
{ 0, 0, 0, 0, 1}, { 0, 0, 0, 1, 0}, { 0, 1, 1, 0, 0}
},
};

// Dot matrix pattern for a colon.


static readonly int[,] colonPattern = new int[7, 2]
{
{ 0, 0 }, { 1, 1 }, { 1, 1 }, { 0, 0 }, { 1, 1 }, { 1, 1 }, { 0, 0 }
};

// BoxView colors for on and off.


static readonly Color colorOn = Color.Red;
static readonly Color colorOff = new Color(0.5, 0.5, 0.5, 0.25);

// Box views for 6 digits, 7 rows, 5 columns.


BoxView[, ,] digitBoxViews = new BoxView[6, 7, 5];

···

}
Esses campos terminam com uma matriz tridimensional do BoxView elementos para armazenar os padrões de
ponto para os seis dígitos.
O construtor cria todos os as BoxView elementos para os dígitos e dois-pontos e também inicializa a Color
propriedade do BoxView elementos para os dois-pontos:

public partial class MainPage : ContentPage


{

···

public MainPage()
{
InitializeComponent();

// BoxView dot dimensions.


double height = 0.85 / vertDots;
double width = 0.85 / horzDots;

// Create and assemble the BoxViews.


double xIncrement = 1.0 / (horzDots - 1);
double yIncrement = 1.0 / (vertDots - 1);
double x = 0;

for (int digit = 0; digit < 6; digit++)


{
for (int col = 0; col < 5; col++)
{
double y = 0;

for (int row = 0; row < 7; row++)


{
// Create the digit BoxView and add to layout.
BoxView boxView = new BoxView();
digitBoxViews[digit, row, col] = boxView;
absoluteLayout.Children.Add(boxView,
new Rectangle(x, y, width, height),
AbsoluteLayoutFlags.All);
y += yIncrement;
}
x += xIncrement;
}
x += xIncrement;

// Colons between the hours, minutes, and seconds.


if (digit == 1 || digit == 3)
{
int colon = digit / 2;

for (int col = 0; col < 2; col++)


{
double y = 0;

for (int row = 0; row < 7; row++)


{
// Create the BoxView and set the color.
BoxView boxView = new BoxView
{
Color = colonPattern[row, col] == 1 ?
colorOn : colorOff
};
absoluteLayout.Children.Add(boxView,
new Rectangle(x, y, width, height),
AbsoluteLayoutFlags.All);
y += yIncrement;
}
x += xIncrement;
}
x += xIncrement;
}
}

// Set the timer and initialize with a manual call.


Device.StartTimer(TimeSpan.FromSeconds(1), OnTimer);
OnTimer();
}

···

Esse programa usa o posicionamento relativo e o recurso de dimensionamento de AbsoluteLayout . A largura e


altura de cada BoxView são definidas com valores fracionários, especificamente 85% 1 dividido pelo número de
pontos horizontais e verticais. As posições também são definidas como valores fracionários.
Porque todos os tamanhos e posições são relativos ao tamanho total da AbsoluteLayout , o SizeChanged
manipulador para a página precisa configurar um HeightRequest da AbsoluteLayout :

public partial class MainPage : ContentPage


{

···

void OnPageSizeChanged(object sender, EventArgs args)


{
// No chance a display will have an aspect ratio > 41:7
absoluteLayout.HeightRequest = vertDots * Width / horzDots;
}

···

A largura do AbsoluteLayout é definido automaticamente porque ele se estende até a largura total da página.
O código final no MainPage cores nos pontos de cada dígito e processa o retorno de chamada do temporizador de
classe. A definição das matrizes multidimensionais no início do arquivo code-behind ajuda a tornar essa lógica a
parte mais simples do programa:
public partial class MainPage : ContentPage
{

···

bool OnTimer()
{
DateTime dateTime = DateTime.Now;

// Convert 24-hour clock to 12-hour clock.


int hour = (dateTime.Hour + 11) % 12 + 1;

// Set the dot colors for each digit separately.


SetDotMatrix(0, hour / 10);
SetDotMatrix(1, hour % 10);
SetDotMatrix(2, dateTime.Minute / 10);
SetDotMatrix(3, dateTime.Minute % 10);
SetDotMatrix(4, dateTime.Second / 10);
SetDotMatrix(5, dateTime.Second % 10);
return true;
}

void SetDotMatrix(int index, int digit)


{
for (int row = 0; row < 7; row++)
for (int col = 0; col < 5; col++)
{
bool isOn = numberPatterns[digit, row, col] == 1;
Color color = isOn ? colorOn : colorOff;
digitBoxViews[index, row, col].Color = color;
}
}
}

Criação de um relógio analógico


Um relógio de matriz de pontos pode parecer estar uma aplicação óbvia BoxView , mas BoxView elementos
também são capazes de perceber um relógio analógico:

Todos os visuais nos BoxViewClock programa são filhos de um AbsoluteLayout . Esses elementos são
dimensionados usando o LayoutBounds propriedade anexada e girado usando o Rotation propriedade.
Os três BoxView elementos para os ponteiros do relógio são instanciados no arquivo XAML, mas não
posicionados ou em tamanho:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:BoxViewClock"
x:Class="BoxViewClock.MainPage">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="0, 20, 0, 0" />
</OnPlatform>
</ContentPage.Padding>

<AbsoluteLayout x:Name="absoluteLayout"
SizeChanged="OnAbsoluteLayoutSizeChanged">

<BoxView x:Name="hourHand"
Color="Black" />

<BoxView x:Name="minuteHand"
Color="Black" />

<BoxView x:Name="secondHand"
Color="Black" />
</AbsoluteLayout>
</ContentPage>

O construtor do arquivo code-behind instancia a 60 BoxView elementos para as marcas de escala em torno da
circunferência do relógio:

public partial class MainPage : ContentPage


{

···

BoxView[] tickMarks = new BoxView[60];

public MainPage()
{
InitializeComponent();

// Create the tick marks (to be sized and positioned later).


for (int i = 0; i < tickMarks.Length; i++)
{
tickMarks[i] = new BoxView { Color = Color.Black };
absoluteLayout.Children.Add(tickMarks[i]);
}

Device.StartTimer(TimeSpan.FromSeconds(1.0 / 60), OnTimerTick);


}

···

O dimensionamento e posicionamento de todos os BoxView elementos ocorre no SizeChanged manipulador para


o AbsoluteLayout . Uma pequena estrutura interna para a classe chamada HandParams descreve o tamanho de
cada um dos três ponteiros em relação ao tamanho total do relógio:
public partial class MainPage : ContentPage
{
// Structure for storing information about the three hands.
struct HandParams
{
public HandParams(double width, double height, double offset) : this()
{
Width = width;
Height = height;
Offset = offset;
}

public double Width { private set; get; } // fraction of radius


public double Height { private set; get; } // ditto
public double Offset { private set; get; } // relative to center pivot
}

static readonly HandParams secondParams = new HandParams(0.02, 1.1, 0.85);


static readonly HandParams minuteParams = new HandParams(0.05, 0.8, 0.9);
static readonly HandParams hourParams = new HandParams(0.125, 0.65, 0.9);

···

O SizeChanged manipulador determina o centro e um raio do AbsoluteLayout e, em seguida, posições e os


tamanhos de 60 BoxView elementos usados como marcas de escala. O for loop é concluído, definindo o
Rotation propriedade de cada uma dessas BoxView elementos. No final de SizeChanged manipulador, o
LayoutHand método é chamado para dimensionar e posicionar os três ponteiros do relógio:
public partial class MainPage : ContentPage
{

···

void OnAbsoluteLayoutSizeChanged(object sender, EventArgs args)


{
// Get the center and radius of the AbsoluteLayout.
Point center = new Point(absoluteLayout.Width / 2, absoluteLayout.Height / 2);
double radius = 0.45 * Math.Min(absoluteLayout.Width, absoluteLayout.Height);

// Position, size, and rotate the 60 tick marks.


for (int index = 0; index < tickMarks.Length; index++)
{
double size = radius / (index % 5 == 0 ? 15 : 30);
double radians = index * 2 * Math.PI / tickMarks.Length;
double x = center.X + radius * Math.Sin(radians) - size / 2;
double y = center.Y - radius * Math.Cos(radians) - size / 2;
AbsoluteLayout.SetLayoutBounds(tickMarks[index], new Rectangle(x, y, size, size));
tickMarks[index].Rotation = 180 * radians / Math.PI;
}

// Position and size the three hands.


LayoutHand(secondHand, secondParams, center, radius);
LayoutHand(minuteHand, minuteParams, center, radius);
LayoutHand(hourHand, hourParams, center, radius);
}

void LayoutHand(BoxView boxView, HandParams handParams, Point center, double radius)


{
double width = handParams.Width * radius;
double height = handParams.Height * radius;
double offset = handParams.Offset;

AbsoluteLayout.SetLayoutBounds(boxView,
new Rectangle(center.X - 0.5 * width,
center.Y - offset * height,
width, height));

// Set the AnchorY property for rotations.


boxView.AnchorY = handParams.Offset;
}

···

O LayoutHand método posições e os tamanhos cada mão para apontar diretamente até a posição de 12:00. No
final do método, o AnchorY estiver definida como uma posição correspondente para o centro do relógio. Isso
indica que o Centro de rotação.
Os ponteiros são girados na função de retorno de chamada de temporizador:
public partial class MainPage : ContentPage
{

···

bool OnTimerTick()
{
// Set rotation angles for hour and minute hands.
DateTime dateTime = DateTime.Now;
hourHand.Rotation = 30 * (dateTime.Hour % 12) + 0.5 * dateTime.Minute;
minuteHand.Rotation = 6 * dateTime.Minute + 0.1 * dateTime.Second;

// Do an animation for the second hand.


double t = dateTime.Millisecond / 1000.0;

if (t < 0.5)
{
t = 0.5 * Easing.SpringIn.Ease(t / 0.5);
}
else
{
t = 0.5 * (1 + Easing.SpringOut.Ease((t - 0.5) / 0.5));
}

secondHand.Rotation = 6 * (dateTime.Second + t);


return true;
}
}

A mão de segundo é tratada de maneira um pouco diferente: uma função de easing de animação é aplicada para
fazer com que o movimento pareça ser mecânico, em vez de suave. Em todas as marcas, a mão segundo efetua
pull de voltar um pouco e, em seguida, overshoots seu destino. Esse pequeno trecho de código adiciona muito o
realismo do movimento.

Conclusão
O BoxView pode parecer simples em primeiro lugar, mas como você viu, ele pode ser bastante versáteis e podem
quase reproduzir visuais que são normalmente possíveis somente com gráficos vetoriais. Para gráficos mais
sofisticados, consulte usar SkiaSharp em xamarin. Forms.

Links relacionados
BoxView básica (exemplo)
Decoração de texto (exemplo)
Caixa de listagem de cor (amostra)
Jogo da vida útil (amostra)
Matriz de pontos de relógio (amostra)
Relógio de BoxView (amostra)
BoxView
Botão de xamarin. Forms
12/04/2019 • 33 minutes to read

baixar o exemplo
O botão responde a um toque ou clique que direciona um aplicativo para executar uma tarefa específica.
O Button é o controle interativo mais fundamental em todas as do xamarin. Forms. O Button normalmente
exibe uma cadeia de caracteres de texto curto indicando um comando, mas também pode exibe uma imagem de
bitmap, ou uma combinação de texto e uma imagem. O usuário pressiona o Button com um dedo ou clica nele
com o mouse para iniciar esse comando.
A maioria dos tópicos discutidos a seguir corresponde às páginas na ButtonDemos exemplo.

Botão de manuseio de cliques


Button define uma Clicked evento que é acionado quando o usuário toca o Button com um ponteiro de
mouse ou o dedo. O evento é acionado quando o botão de dedo ou o mouse é liberado da superfície do Button .
O Button deve ter seu IsEnabled propriedade definida como true para que ele responda aos toques.
O básica de clique do botão página no ButtonDemos exemplo demonstra como criar uma instância de um
Button em XAML e o identificador de seu Clicked eventos. O BasicButtonClickPage.xaml arquivo contém
uma StackLayout tanto com um Label e um Button :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ButtonDemos.BasicButtonClickPage"
Title="Basic Button Click">
<StackLayout>

<Label x:Name="label"
Text="Click the Button below"
FontSize="Large"
VerticalOptions="CenterAndExpand"
HorizontalOptions="Center" />

<Button Text="Click to Rotate Text!"


VerticalOptions="CenterAndExpand"
HorizontalOptions="Center"
Clicked="OnButtonClicked" />

</StackLayout>
</ContentPage>

O Button tende a ocupar todo o espaço permitido para ele. Por exemplo, se você não definir a
HorizontalOptions propriedade de Button para algo diferente de Fill , o Button ocupa a largura total do seu
pai.
Por padrão, o Button é retangular, mas você pode atribuir os cantos arredondado de it, usando o CornerRadius
propriedade, conforme descrito abaixo na seção botão aparência .
O Text propriedade especifica o texto que aparece no Button . O Clicked evento é definido como um
manipulador de eventos chamado OnButtonClicked . Esse manipulador está localizado no arquivo code-behind,
BasicButtonClickPage.xaml.cs:
public partial class BasicButtonClickPage : ContentPage
{
public BasicButtonClickPage ()
{
InitializeComponent ();
}

async void OnButtonClicked(object sender, EventArgs args)


{
await label.RelRotateTo(360, 1000);
}
}

Quando o Button é tocado, o OnButtonClicked método é executado. O sender argumento é o Button objeto
responsável por esse evento. Você pode usar isso para acessar o Button objeto, ou para distinguir entre vários
Button objetos que compartilham o mesmo Clicked eventos.

Essa determinada Clicked manipulador chama uma função de animação que gira o Label 360 graus em 1000
milissegundos. Aqui está o programa em execução em dispositivos iOS e Android e como um aplicativo da
plataforma Universal do Windows (UWP ) na área de trabalho do Windows 10:

Observe que o OnButtonClicked método inclui o async modificador porque await é usado dentro do
manipulador de eventos. Um Clicked manipulador de eventos exige as async modificador somente se o corpo
do manipulador usa await .
Cada plataforma renderiza o Button em sua própria maneira específica. No botão aparência seção, você verá
como definir cores e fazer o Button borda visível para aparências mais personalizadas. Button implementa o
IFontElement interface, portanto, ela inclui FontFamily , FontSize , e FontAttributes propriedades.

Criando um botão no código


É comum para criar uma instância de um Button no XAML, mas você também pode criar um Button no código.
Isso pode ser conveniente quando seu aplicativo precisa para criar vários botões com base nos dados que é
enumeráveis com um foreach loop.
O código de clique de botão página demonstra como criar uma página que é funcionalmente equivalente à
básica de clique de botão página, mas inteiramente no C#:
public class CodeButtonClickPage : ContentPage
{
public CodeButtonClickPage ()
{
Title = "Code Button Click";

Label label = new Label


{
Text = "Click the Button below",
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.Center
};

Button button = new Button


{
Text = "Click to Rotate Text!",
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.Center
};
button.Clicked += async (sender, args) => await label.RelRotateTo(360, 1000);

Content = new StackLayout


{
Children =
{
label,
button
}
};
}
}

Tudo o que é feito no construtor da classe. Porque o Clicked manipulador é apenas uma instrução longa, ele
pode ser anexado ao evento muito simples:

button.Clicked += async (sender, args) => await label.RelRotateTo(360, 1000);

É claro, você também pode definir o manipulador de eventos como um método separado (assim como o
OnButtonClick método no básico de clique do botão) e anexar esse método para o evento:

button.Clicked += OnButtonClicked;

Desabilitação do botão
Às vezes, um aplicativo está em um estado específico em que um determinado Button clique não é uma
operação válida. Nesses casos, o Button deve ser desabilitado definindo seu IsEnabled propriedade false . O
exemplo clássico é um Entry controle de um nome de arquivo acompanhado por uma abertura de arquivo
Button : O Button deve ser habilitada apenas se algum texto foi digitado para o Entry . Você pode usar um
DataTrigger para essa tarefa, conforme mostrado na gatilhos de dados artigo.

Usando a interface de comando


É possível que um aplicativo para responder às Button toques sem tratamento a Clicked eventos. O Button
implementa um mecanismo de notificação alternativo chamado a comando ou comandando interface. Isso
consiste em duas propriedades:
Command do tipo ICommand , uma interface definida a System.Windows.Input namespace.
CommandParameter propriedade do tipo Object .

Essa abordagem é especialmente adequada em conexão com a vinculação de dados e especialmente quando a
implementação da arquitetura do Model-View -ViewModel (MVVM ). Esses tópicos são discutidos nos artigos
associação de dados, de associações de dados a MVVM, e MVVM.
Em um aplicativo MVVM, o ViewModel define propriedades do tipo ICommand conectados, em seguida, o XAML
Button elementos com associações de dados. Xamarin. Forms também define Command e Command<T> as classes
que implementam o ICommand de interface e auxiliar o ViewModel na definição de propriedades de tipo
ICommand .

Comandos é descrito mais detalhadamente no artigo a Interface de comando , mas o básica de botão de
comando página o ButtonDemos exemplo mostra a abordagem básica.
O CommandDemoViewModel classe é um ViewModel muito simple que define uma propriedade do tipo double
denominado Number e duas propriedades do tipo ICommand denominada MultiplyBy2Command e DivideBy2Command
:

class CommandDemoViewModel : INotifyPropertyChanged


{
double number = 1;

public event PropertyChangedEventHandler PropertyChanged;

public CommandDemoViewModel()
{
MultiplyBy2Command = new Command(() => Number *= 2);

DivideBy2Command = new Command(() => Number /= 2);


}

public double Number


{
set
{
if (number != value)
{
number = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Number"));
}
}
get
{
return number;
}
}

public ICommand MultiplyBy2Command { private set; get; }

public ICommand DivideBy2Command { private set; get; }


}

Os dois as propriedades são inicializadas no construtor da classe com dois objetos do tipo Command . O
ICommand
Command construtores incluem uma pequena função (chamado de execute argumento do construtor ) que dobra
ou reduz pela metade o Number propriedade.
O BasicButtonCommand.xaml arquivo define seu BindingContext a uma instância do CommandDemoViewModel .
O Label elemento e dois Button elementos contenham associações para as três propriedades em
CommandDemoViewModel :
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:ButtonDemos"
x:Class="ButtonDemos.BasicButtonCommandPage"
Title="Basic Button Command">

<ContentPage.BindingContext>
<local:CommandDemoViewModel />
</ContentPage.BindingContext>

<StackLayout>
<Label Text="{Binding Number, StringFormat='Value is now {0}'}"
FontSize="Large"
VerticalOptions="CenterAndExpand"
HorizontalOptions="Center" />

<Button Text="Multiply by 2"


VerticalOptions="CenterAndExpand"
HorizontalOptions="Center"
Command="{Binding MultiplyBy2Command}" />

<Button Text="Divide by 2"


VerticalOptions="CenterAndExpand"
HorizontalOptions="Center"
Command="{Binding DivideBy2Command}" />
</StackLayout>
</ContentPage>

Como os dois Button tocados elementos, os comandos são executados, e o número de alterações de valor:

A vantagem dessa abordagem em relação Clicked manipuladores é que toda a lógica que envolvem a
funcionalidade dessa página está localizada no ViewModel em vez de um arquivo code-behind, obtendo uma
melhor separação da interface do usuário da lógica de negócios.
Também é possível que o Command objetos para controlar a habilitação e desabilitação do Button elementos. Por
exemplo, suponha que você deseja limitar o intervalo de valores numéricos entre 210 e 2–10. Você pode adicionar
outra função para o construtor (chamado de canExecute argumento) que retorna true se o Button deve ser
habilitado. Aqui está a modificação para o CommandDemoViewModel construtor:
class CommandDemoViewModel : INotifyPropertyChanged
{
···
public CommandDemoViewModel()
{
MultiplyBy2Command = new Command(
execute: () =>
{
Number *= 2;
((Command)MultiplyBy2Command).ChangeCanExecute();
((Command)DivideBy2Command).ChangeCanExecute();
},
canExecute: () => Number < Math.Pow(2, 10));

DivideBy2Command = new Command(


execute: () =>
{
Number /= 2;
((Command)MultiplyBy2Command).ChangeCanExecute();
((Command)DivideBy2Command).ChangeCanExecute();
},
canExecute: () => Number > Math.Pow(2, -10));
}
···
}

As chamadas para o ChangeCanExecute método de Command são necessárias para que o Command método pode
chamar o canExecute método e determinar se o Button deve ser desabilitado ou não. Com essa alteração de
código, como o número de atingir o limite, o Button está desabilitado:

É possível que duas ou mais Button elementos a ser associado ao mesmo ICommand propriedade. O Button
elementos podem ser diferenciados com o CommandParameter propriedade do Button . Nesse caso, você desejará
usar o genérico Command<T> classe. O CommandParameter objeto é então passado como um argumento para o
execute e canExecute métodos. Essa técnica é mostrada em detalhes na comandos básicos seção os Interface
de comando artigo.
O ButtonDemos exemplo também usa essa técnica em seu MainPage classe. O MainPage. XAML arquivo
contém um Button para cada página de exemplo:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:ButtonDemos"
x:Class="ButtonDemos.MainPage"
Title="Button Demos">
<ScrollView>
<FlexLayout Direction="Column"
JustifyContent="SpaceEvenly"
AlignItems="Center">

<Button Text="Basic Button Click"


Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:BasicButtonClickPage}" />

<Button Text="Code Button Click"


Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:CodeButtonClickPage}" />

<Button Text="Basic Button Command"


Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:BasicButtonCommandPage}" />

<Button Text="Press and Release Button"


Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:PressAndReleaseButtonPage}" />

<Button Text="Button Appearance"


Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:ButtonAppearancePage}" />

<Button Text="Toggle Button Demo"


Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:ToggleButtonDemoPage}" />

<Button Text="Image Button Demo"


Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:ImageButtonDemoPage}" />

</FlexLayout>
</ScrollView>
</ContentPage>

Cada Buttontem sua Command propriedade associada a uma propriedade denominada NavigateCommand e o
CommandParameter é definido como um Type objeto correspondente a uma das classes de página no projeto.

Que NavigateCommand propriedade é do tipo ICommand e é definido no arquivo code-behind:

public partial class MainPage : ContentPage


{
public MainPage()
{
InitializeComponent();

NavigateCommand = new Command<Type>(async (Type pageType) =>


{
Page page = (Page)Activator.CreateInstance(pageType);
await Navigation.PushAsync(page);
});

BindingContext = this;
}

public ICommand NavigateCommand { private set; get; }


}
O construtor inicializa o NavigateCommand propriedade para um Command<Type> porque Type é o tipo do
CommandParameter objeto definido no arquivo XAML. Isso significa que o execute método tem um argumento do
tipo Type que corresponde a este CommandParameter objeto. A função cria uma instância de página e, em seguida,
navega até ela.
Observe que o construtor é concluído, definindo seu BindingContext a mesmo. Isso é necessário para as
propriedades no arquivo XAML para associar o NavigateCommand propriedade.

Pressionando e soltando o botão


Além de Clicked evento Button também define Pressed e Released eventos. O Pressed evento ocorre
quando um dedo pressiona em um Button , ou um botão do mouse é pressionado com o ponteiro posicionado
sobre o Button . O Released evento ocorre quando o botão de dedo ou o mouse é liberado. Em geral, uma
Clicked evento também é acionado ao mesmo tempo que o Released evento, mas se o ponteiro do mouse ou o
dedo desliza para fora a superfície do Button antes de serem liberadas, o Clicked não pode ocorrer um evento.
O Pressed e Released eventos não são usados com frequência, mas eles podem ser usados para finalidades
especiais, conforme demonstrado na pressione e solte o botão página. O arquivo XAML contém um Label e
uma Button com os manipuladores anexados para o Pressed e Released eventos:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ButtonDemos.PressAndReleaseButtonPage"
Title="Press and Release Button">
<StackLayout>

<Label x:Name="label"
Text="Press and hold the Button below"
FontSize="Large"
VerticalOptions="CenterAndExpand"
HorizontalOptions="Center" />

<Button Text="Press to Rotate Text!"


VerticalOptions="CenterAndExpand"
HorizontalOptions="Center"
Pressed="OnButtonPressed"
Released="OnButtonReleased" />

</StackLayout>
</ContentPage>

O arquivo code-behind anima a Label quando um Pressed evento ocorre, mas suspende a rotação quando um
Released evento ocorre:
public partial class PressAndReleaseButtonPage : ContentPage
{
bool animationInProgress = false;
Stopwatch stopwatch = new Stopwatch();

public PressAndReleaseButtonPage ()
{
InitializeComponent ();
}

void OnButtonPressed(object sender, EventArgs args)


{
stopwatch.Start();
animationInProgress = true;

Device.StartTimer(TimeSpan.FromMilliseconds(16), () =>
{
label.Rotation = 360 * (stopwatch.Elapsed.TotalSeconds % 1);

return animationInProgress;
});
}

void OnButtonReleased(object sender, EventArgs args)


{
animationInProgress = false;
stopwatch.Stop();
}
}

O resultado é que o Label apenas gira enquanto é de um dedo em contato com o Button e é interrompido
quando o dedo é liberado:

Esse tipo de comportamento tem aplicativos de jogos: Um dedo mantido um Button pode fazer um objeto de
tela em Mover em uma direção específica.

Aparência do botão
O Button herda ou define várias propriedades que afetam sua aparência:
TextColor é a cor do Button texto
BackgroundColor é a cor do plano de fundo para que o texto
BorderColor é a cor de uma área ao redor do Button
FontFamily a família de fontes para o texto é usada
FontSize é o tamanho do texto
FontAttributes Indica se o texto em negrito ou itálico
BorderWidth é a largura da borda
CornerRadius é o raio do canto das Button

NOTE
O Button classe também tem Margin e Padding propriedades que controlam o comportamento de layout a Button .
Para obter mais informações, consulte margem e preenchimento.

Os efeitos de seis dessas propriedades (exceto FontFamily e FontAttributes ) são demonstradas a aparência
botão página. Outra propriedade, Image , é discutida na seção usar bitmaps com o botão.
Todas as associações de dados e modos de exibição na aparência botão página são definidos no arquivo XAML:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:ButtonDemos"
x:Class="ButtonDemos.ButtonAppearancePage"
Title="Button Appearance">
<StackLayout>
<Button x:Name="button"
Text="Button"
VerticalOptions="CenterAndExpand"
HorizontalOptions="Center"
TextColor="{Binding Source={x:Reference textColorPicker},
Path=SelectedItem.Color}"
BackgroundColor="{Binding Source={x:Reference backgroundColorPicker},
Path=SelectedItem.Color}"
BorderColor="{Binding Source={x:Reference borderColorPicker},
Path=SelectedItem.Color}" />

<StackLayout BindingContext="{x:Reference button}"


Padding="10">

<Slider x:Name="fontSizeSlider"
Maximum="48"
Minimum="1"
Value="{Binding FontSize}" />

<Label Text="{Binding Source={x:Reference fontSizeSlider},


Path=Value,
StringFormat='FontSize = {0:F0}'}"
HorizontalTextAlignment="Center" />

<Slider x:Name="borderWidthSlider"
Minimum="-1"
Maximum="12"
Value="{Binding BorderWidth}" />

<Label Text="{Binding Source={x:Reference borderWidthSlider},


Path=Value,
StringFormat='BorderWidth = {0:F0}'}"
HorizontalTextAlignment="Center" />

<Slider x:Name="cornerRadiusSlider"
Minimum="-1"
Maximum="24"
Value="{Binding CornerRadius}" />

<Label Text="{Binding Source={x:Reference cornerRadiusSlider},


Path=Value,
Path=Value,
StringFormat='CornerRadius = {0:F0}'}"
HorizontalTextAlignment="Center" />

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>

<Grid.Resources>
<Style TargetType="Label">
<Setter Property="VerticalOptions" Value="Center" />
</Style>
</Grid.Resources>

<Label Text="Text Color:"


Grid.Row="0" Grid.Column="0" />

<Picker x:Name="textColorPicker"
ItemsSource="{Binding Source={x:Static local:NamedColor.All}}"
ItemDisplayBinding="{Binding FriendlyName}"
SelectedIndex="0"
Grid.Row="0" Grid.Column="1" />

<Label Text="Background Color:"


Grid.Row="1" Grid.Column="0" />

<Picker x:Name="backgroundColorPicker"
ItemsSource="{Binding Source={x:Static local:NamedColor.All}}"
ItemDisplayBinding="{Binding FriendlyName}"
SelectedIndex="0"
Grid.Row="1" Grid.Column="1" />

<Label Text="Border Color:"


Grid.Row="2" Grid.Column="0" />

<Picker x:Name="borderColorPicker"
ItemsSource="{Binding Source={x:Static local:NamedColor.All}}"
ItemDisplayBinding="{Binding FriendlyName}"
SelectedIndex="0"
Grid.Row="2" Grid.Column="1" />
</Grid>
</StackLayout>
</StackLayout>
</ContentPage>

O Button na parte superior da página tem suas três Color propriedades associadas a Picker elementos na
parte inferior da página. Os itens a Picker elementos são as cores do NamedColor incluído no projeto de classe.
Três Slider elementos contêm as vinculações bidirecionais para o FontSize , BorderWidth , e CornerRadius
propriedades do Button .
Esse programa permite que você experimente combinações de todas essas propriedades:
Para ver os borda, você precisará definir um
Button BorderColor para algo diferente de Default eo
BorderWidth como um valor positivo.
No iOS, você observará que as larguras de borda grande atrapalham a para o interior do Button e interferir com
a exibição do texto. Se você optar por usar um border com um iOS Button , você provavelmente vai querer
começar e terminar o Text propriedade com espaços para manter sua visibilidade.
Na UWP, selecionando uma CornerRadius que excede a metade da altura do Button gera uma exceção.

Estados visuais do botão


Button tem um Pressed VisualState que pode ser usado para iniciar uma alteração visual para o Button
quando pressionado pelo usuário, desde que ele está habilitado.
O exemplo XAML a seguir mostra como definir um estado visual para o Pressed estado:

<Button Text="Click me!"


...>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="Scale"
Value="1" />
</VisualState.Setters>
</VisualState>

<VisualState x:Name="Pressed">
<VisualState.Setters>
<Setter Property="Scale"
Value="0.8" />
</VisualState.Setters>
</VisualState>

</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Button>

O Pressed VisualState Especifica que, quando o Button for pressionado, seu Scale propriedade será alterada
de seu valor padrão de 1 para 0,8. O Normal VisualState Especifica que, quando o Button está em um estado
normal, seu Scale propriedade será definida como 1. Portanto, o efeito geral é que quando o Button é
pressionado, ele será escalada novamente para ser um pouco menores e quando o Button é lançado, ele será
escalada novamente ao seu tamanho padrão.
Para obter mais informações sobre estados visuais, consulte o Gerenciador de estado Visual xamarin. Forms.

Criando um botão de alternância


É possível que a subclasse Button para que ele funcione como um comutador ligado / desligado: Toque no botão
de uma vez para o botão de alternância no e toque novamente para ativá-lo.
O seguinte ToggleButton classe deriva Button e define um novo evento chamado Toggled e uma propriedade
booleana chamada IsToggled . Essas são as mesmas propriedades de dois definidas pelo xamarin. Forms Switch
:

class ToggleButton : Button


{
public event EventHandler<ToggledEventArgs> Toggled;

public static BindableProperty IsToggledProperty =


BindableProperty.Create("IsToggled", typeof(bool), typeof(ToggleButton), false,
propertyChanged: OnIsToggledChanged);

public ToggleButton()
{
Clicked += (sender, args) => IsToggled ^= true;
}

public bool IsToggled


{
set { SetValue(IsToggledProperty, value); }
get { return (bool)GetValue(IsToggledProperty); }
}

protected override void OnParentSet()


{
base.OnParentSet();
VisualStateManager.GoToState(this, "ToggledOff");
}

static void OnIsToggledChanged(BindableObject bindable, object oldValue, object newValue)


{
ToggleButton toggleButton = (ToggleButton)bindable;
bool isToggled = (bool)newValue;

// Fire event
toggleButton.Toggled?.Invoke(toggleButton, new ToggledEventArgs(isToggled));

// Set the visual state


VisualStateManager.GoToState(toggleButton, isToggled ? "ToggledOn" : "ToggledOff");
}
}

O ToggleButton construtor anexa um manipulador para o Clicked evento para que ele possa alterar o valor da
IsToggled propriedade. O OnIsToggledChanged método dispara o Toggled eventos.
A última linha do OnIsToggledChanged chamadas de método estático VisualStateManager.GoToState método com
o texto de duas cadeias de caracteres "ToggledOn" e "ToggledOff". Você pode ler sobre esse método e como seu
aplicativo pode responder a estados visuais no artigo o Gerenciador de estado Visual xamarin. Forms.
Porque ToggleButton faz a chamada para VisualStateManager.GoToState , a classe em si não precisa incluir
quaisquer instalações adicionais para alterar a aparência do botão com base em seu IsToggled estado. Ou seja, a
responsabilidade do XAML que hospeda o ToggleButton .
O demonstração do botão de alternância página contém duas instâncias do ToggleButton , inclusive a
marcação de Gerenciador de estado Visual que define os Text , BackgroundColor , e TextColor do botão de
acordo com o estado visual:

<?xml version="1.0" encoding="utf-8" ?>


<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:ButtonDemos"
x:Class="ButtonDemos.ToggleButtonDemoPage"
Title="Toggle Button Demo">

<ContentPage.Resources>
<Style TargetType="local:ToggleButton">
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
<Setter Property="HorizontalOptions" Value="Center" />
</Style>
</ContentPage.Resources>

<StackLayout Padding="10, 0">


<local:ToggleButton Toggled="OnItalicButtonToggled">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="ToggleStates">
<VisualState Name="ToggledOff">
<VisualState.Setters>
<Setter Property="Text" Value="Italic Off" />
<Setter Property="BackgroundColor" Value="#C0C0C0" />
<Setter Property="TextColor" Value="Black" />
</VisualState.Setters>
</VisualState>

<VisualState Name="ToggledOn">
<VisualState.Setters>
<Setter Property="Text" Value=" Italic On " />
<Setter Property="BackgroundColor" Value="#404040" />
<Setter Property="TextColor" Value="White" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</local:ToggleButton>

<local:ToggleButton Toggled="OnBoldButtonToggled">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="ToggleStates">
<VisualState Name="ToggledOff">
<VisualState.Setters>
<Setter Property="Text" Value="Bold Off" />
<Setter Property="BackgroundColor" Value="#C0C0C0" />
<Setter Property="TextColor" Value="Black" />
</VisualState.Setters>
</VisualState>

<VisualState Name="ToggledOn">
<VisualState.Setters>
<Setter Property="Text" Value=" Bold On " />
<Setter Property="BackgroundColor" Value="#404040" />
<Setter Property="TextColor" Value="White" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</local:ToggleButton>

<Label x:Name="label"
Text="Just a little passage of some sample text that can be formatted in italic or boldface by
toggling the two buttons."
FontSize="Large"
HorizontalTextAlignment="Center"
VerticalOptions="CenterAndExpand" />

</StackLayout>
</ContentPage>

O Toggledmanipuladores de eventos estão no arquivo code-behind. Eles são responsáveis por configuração o
FontAttributes propriedade do Label com base no estado dos botões:

public partial class ToggleButtonDemoPage : ContentPage


{
public ToggleButtonDemoPage ()
{
InitializeComponent ();
}

void OnItalicButtonToggled(object sender, ToggledEventArgs args)


{
if (args.Value)
{
label.FontAttributes |= FontAttributes.Italic;
}
else
{
label.FontAttributes &= ~FontAttributes.Italic;
}
}

void OnBoldButtonToggled(object sender, ToggledEventArgs args)


{
if (args.Value)
{
label.FontAttributes |= FontAttributes.Bold;
}
else
{
label.FontAttributes &= ~FontAttributes.Bold;
}
}
}

Aqui está o programa em execução no iOS, Android e UWP:

Usar bitmaps com botões


O Button classe define um Image que permite que você exiba uma imagem de bitmap na propriedade de
Button , sozinho ou em combinação com o texto. Você também pode especificar como o texto e imagem são
organizados.
O Image propriedade é do tipo FileImageSource , que significa que os bitmaps devem ser armazenados como
recursos nos projetos de plataforma individual e não no projeto da biblioteca .NET Standard.
Cada plataforma suportada pelo xamarin. Forms permite que as imagens sejam armazenados em vários
tamanhos para resoluções de pixel diferente do que o aplicativo pode ser executado em vários dispositivos. Esses
bitmaps de vários são nomeados ou armazenadas de tal forma que o sistema operacional pode escolher a melhor
correspondência para o dispositivo de vídeo do resolução de vídeo.
Para um bitmap em um Button , geralmente é o melhor tamanho entre unidades independentes de dispositivo
de 32 e 64, dependendo de quão grande você deseja que ele fique. As imagens usadas neste exemplo baseiam-se
um tamanho de 48 unidades independentes de dispositivo.
No projeto do iOS, o recursos pasta contém três tamanhos desta imagem:
Um bitmap de 48 pixels quadrado armazenado como /Resources/MonkeyFace.png
Um bitmap de 96 pixels quadrado armazenado como /Resource/MonkeyFace@2x.png
Um bitmap de 144 pixels quadrado armazenado como /Resource/MonkeyFace@3x.png
Todos os três bitmaps recebeu uma ação de compilação dos BundleResource.
Para o projeto Android, os bitmaps todos têm o mesmo nome, mas eles são armazenados em subpastas
diferentes do recursos pasta:
Um bitmap de 72 pixels quadrado armazenado como /Resources/drawable-hdpi/MonkeyFace.png
Um bitmap de 96 pixels quadrado armazenado como /Resources/drawable-xhdpi/MonkeyFace.png
Um bitmap de 144 pixels quadrado armazenado como /Resources/drawable-xxhdpi/MonkeyFace.png
Um bitmap de 192 pixels quadrado armazenado como /Resources/drawable-xxxhdpi/MonkeyFace.png
Eles receberam um ação de compilação dos AndroidResource.
No projeto UWP, os bitmaps podem ser armazenados em qualquer lugar no projeto, mas eles geralmente são
armazenados em uma pasta personalizada ou o ativos pasta existente. O projeto UWP contém esses bitmaps:
Um bitmap de 48 pixels quadrado armazenado como /Assets/MonkeyFace.scale-100.png
Um bitmap de 96 pixels quadrado armazenado como /Assets/MonkeyFace.scale-200.png
Um bitmap de 192 pixels quadrado armazenado como /Assets/MonkeyFace.scale-400.png
Eles foram fornecidos um ação de compilação dos conteúdo.
Você pode especificar como o Text e Image propriedades forem organizadas na Button usando o
ContentLayout propriedade Button . Essa propriedade é do tipo ButtonContentLayout , que é uma classe
incorporada no Button . O construtor tem dois argumentos:
Um membro do ImagePosition enumeração: Left , Top , Right , ou Bottom indicando como o bitmap
aparece em relação ao texto.
Um double valor para o espaçamento entre o bitmap e o texto.

Os padrões são Left e 10 unidades. Duas propriedades somente leitura do ButtonContentLayout nomeado
Position e Spacing forneça os valores dessas propriedades.

No código, você pode criar uma Button e defina o ContentLayout propriedade como este:
Button button = new Button
{
Text = "button text",
Image = new FileImageSource
{
File = "image filename"
},
ContentLayout = new Button.ButtonContentLayout(Button.ButtonContentLayout.ImagePosition.Right, 20)
};

No XAML, você precisa especificar somente o membro de enumeração ou o espaçamento ou ambos em


qualquer ordem separados por vírgulas:

<Button Text="button text"


Image="image filename"
ContentLayout="Right, 20" />

O imagem Button Demo página usa OnPlatform para especificar nomes de arquivo diferente para o iOS,
Android e UWP arquivos de bitmap. Se você quiser usar o mesmo nome de arquivo para cada plataforma e evite
o uso de OnPlatform , você precisa para armazenar os bitmaps UWP no diretório raiz do projeto.
A primeira Button no imagem Button Demo página conjuntos a Image propriedade, mas não o Text
propriedade:

<Button>
<Button.Image>
<OnPlatform x:TypeArguments="FileImageSource">
<On Platform="iOS, Android" Value="MonkeyFace.png" />
<On Platform="UWP" Value="Assets/MonkeyFace.png" />
</OnPlatform>
</Button.Image>
</Button>

Se os bitmaps UWP são armazenados no diretório raiz do projeto, essa marcação pode ser consideravelmente
simplificada:

<Button Image="MonkeyFace.png" />

Para evitar muita marcação repetitivas na ImageButtonDemo.xaml arquivo implícito Style também é
definido para configurar o Image propriedade. Isso Style é aplicada automaticamente a outros cinco Button
elementos. Aqui está o arquivo XAML completo:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ButtonDemos.ImageButtonDemoPage">

<FlexLayout Direction="Column"
JustifyContent="SpaceEvenly"
AlignItems="Center">

<FlexLayout.Resources>
<Style TargetType="Button">
<Setter Property="Image">
<OnPlatform x:TypeArguments="FileImageSource">
<On Platform="iOS, Android" Value="MonkeyFace.png" />
<On Platform="UWP" Value="Assets/MonkeyFace.png" />
</OnPlatform>
</Setter>
</Style>
</FlexLayout.Resources>

<Button>
<Button.Image>
<OnPlatform x:TypeArguments="FileImageSource">
<On Platform="iOS, Android" Value="MonkeyFace.png" />
<On Platform="UWP" Value="Assets/MonkeyFace.png" />
</OnPlatform>
</Button.Image>
</Button>

<Button Text="Default" />

<Button Text="Left - 10"


ContentLayout="Left, 10" />

<Button Text="Top - 10"


ContentLayout="Top, 10" />

<Button Text="Right - 20"


ContentLayout="Right, 20" />

<Button Text="Bottom - 20"


ContentLayout="Bottom, 20" />
</FlexLayout>
</ContentPage>

Os quatro final Button elementos fazem uso do ContentLayout propriedade para especificar uma posição e o
espaçamento entre o texto e o bitmap:
Agora você já viu as várias maneiras que você pode manipular Button eventos e altere o Button aparência.

Links relacionados
Exemplo de ButtonDemos
Botão de API
Xamarin. Forms CollectionView
12/04/2019 • 3 minutes to read

IMPORTANT
O CollectionView atualmente é uma visualização e não tem algumas das suas funcionalidades planejada. Além disso, a
API pode mudar conforme a implementação for concluída.

CollectionView é um modo de exibição para apresentar as listas de dados usando as especificações de layout
diferente. Tem como objetivo fornecer uma mais flexível e alternativa de alto desempenho para o ListView .
Enquanto o CollectionView e ListView APIs são semelhantes, existem algumas diferenças importantes:
CollectionView tem um modelo de layout flexível que permite que os dados a ser apresentado verticalmente
ou horizontalmente, em uma lista ou uma grade.
CollectionView não tem nenhum conceito de células. Em vez disso, um modelo de dados é usado para definir
a aparência de cada item de dados na lista.
CollectionView utiliza automaticamente a virtualização fornecida pelos controles nativos subjacentes.
CollectionView reduz a superfície de API do ListView . Muitas propriedades e eventos do ListView não
estão presentes no CollectionView .
CollectionView não inclui separadores internos.

CollectionView está disponível nas versões de pré-lançamento de 4.0 do xamarin. Forms. No entanto, ele é
atualmente experimental e só pode ser usado, adicionando a seguinte linha de código para seus AppDelegate
classe no iOS, ou para seus MainActivity classe no Android, antes de chamar Forms.Init :

Forms.SetFlags("CollectionView_Experimental");

NOTE
CollectionView só está disponível no iOS e Android.

Preencher CollectionView com dados


Um CollectionView é preenchido com dados, definindo seu ItemsSource propriedade para qualquer coleção que
implemente IEnumerable . A aparência de cada item na lista pode ser definida ao configurar o ItemTemplate
propriedade para um DataTemplate .

Especifique o layout de CollectionView


Por padrão, um CollectionView exibirá seus itens em uma lista vertical. No entanto, grades e listas verticais e
horizontais podem ser especificadas.
Definir o modo de seleção CollectionView
Por padrão, CollectionView seleção está desabilitada. No entanto, a seleção única e múltipla pode ser habilitada.

Exibir um EmptyView quando dados não estão disponíveis


No CollectionView , um modo de exibição vazio pode ser especificado que fornece comentários ao usuário
quando não há dados disponíveis para exibição. O modo de exibição vazio pode ser uma cadeia de caracteres,
uma exibição ou vários modos de exibição.

Rolar um item na exibição


Quando um dedo do usuário para iniciar uma rolagem, a posição final da rolagem pode ser controlada para que
os itens são totalmente exibidas. Além disso, CollectionView define dois ScrollTo métodos, que rolagem
programaticamente os itens na exibição. Uma das sobrecargas rola o item no índice especificado na exibição,
enquanto o outro rola o item especificado na exibição.
Preencher CollectionView de xamarin. Forms com
dados
12/04/2019 • 5 minutes to read

Baixar o exemplo

IMPORTANT
O CollectionView atualmente é uma visualização e não tem algumas das suas funcionalidades planejada. Além disso, a API
pode mudar conforme a implementação for concluída.

CollectionView Define as seguintes propriedades que definem os dados a ser exibido e sua aparência:
ItemsSource , do tipo IEnumerable , especifica a coleção de itens a serem exibidos, e tem um valor padrão de
null .
ItemTemplate, do tipo DataTemplate , especifica o modelo a ser aplicado a cada item na coleção de itens a
serem exibidos.
Essas propriedades têm o respaldo BindableProperty objetos, o que significa que as propriedades podem ser alvos
de vinculações de dados.

Preencher um CollectionView de dados


Um CollectionView é preenchido com dados, definindo seu ItemsSource propriedade para qualquer coleção que
implemente IEnumerable . Itens podem ser adicionados no XAML, inicializando o ItemsSource propriedade de
uma matriz de cadeias de caracteres:

<CollectionView>
<CollectionView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Baboon</x:String>
<x:String>Capuchin Monkey</x:String>
<x:String>Blue Monkey</x:String>
<x:String>Squirrel Monkey</x:String>
<x:String>Golden Lion Tamarin</x:String>
<x:String>Howler Monkey</x:String>
<x:String>Japanese Macaque</x:String>
</x:Array>
</CollectionView.ItemsSource>
</CollectionView>

NOTE
Observe que o elemento x:Array requer um atributo Type que indica o tipo dos itens na matriz.
O código C# equivalente é:

CollectionView collectionView = new CollectionView();


collectionView.ItemsSource = new string[]
{
"Baboon",
"Capuchin Monkey",
"Blue Monkey",
"Squirrel Monkey",
"Golden Lion Tamarin",
"Howler Monkey",
"Japanese Macaque"
};

IMPORTANT
Se o CollectionView é necessária para atualizada à medida que itens são adicionados, removidos ou alterados na coleção
subjacente, a coleção subjacente deve ser um IEnumerable coleção que envia a propriedade notificações de alteração, como
ObservableCollection .

Por padrão, CollectionView exibe itens em uma lista vertical, conforme mostrado nas capturas de tela seguir:

Para obter informações sobre como alterar o CollectionView layout, consulte especificar um Layout. Para obter
informações sobre como definir a aparência de cada item na CollectionView , consulte definem a aparência do
item.
Associação de dados
CollectionView pode ser preenchido com dados usando associação de dados para associar seu ItemsSource
propriedade para um IEnumerable coleção. No XAML, isso é feito com o Binding extensão de marcação:

<CollectionView ItemsSource="{Binding Monkeys}" />

O código C# equivalente é:

CollectionView collectionView = new CollectionView();


collectionView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys");

Neste exemplo, o ItemsSource associa dados de propriedade para o Monkeys propriedade do modelo de exibição
conectado.
NOTE
Associações compiladas podem ser habilitadas para melhorar o desempenho de associação de dados em aplicativos xamarin.
Forms. Para obter mais informações, consulte compilado associações.

Para obter mais informações sobre associação de dados, confira Associação de Dados do Xamarin.Forms.

Definir a aparência do item


A aparência de cada item na CollectionView pode ser definida ao configurar o CollectionView.ItemTemplate
propriedade para um DataTemplate :

<CollectionView ItemsSource="{Binding Monkeys}">


<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Image Grid.RowSpan="2"
Source="{Binding ImageUrl}"
Aspect="AspectFill"
HeightRequest="60"
WidthRequest="60" />
<Label Grid.Column="1"
Text="{Binding Name}"
FontAttributes="Bold" />
<Label Grid.Row="1"
Grid.Column="1"
Text="{Binding Location}"
FontAttributes="Italic"
VerticalOptions="End" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
...
</CollectionView>

O código C# equivalente é:
CollectionView collectionView = new CollectionView();
collectionView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys");

collectionView.ItemTemplate = new DataTemplate(() =>


{
Grid grid = new Grid { Padding = 10 };
grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });

Image image = new Image { Aspect = Aspect.AspectFill, HeightRequest = 60, WidthRequest = 60 };


image.SetBinding(Image.SourceProperty, "ImageUrl");

Label nameLabel = new Label { FontAttributes = FontAttributes.Bold };


nameLabel.SetBinding(Label.TextProperty, "Name");

Label locationLabel = new Label { FontAttributes = FontAttributes.Italic, VerticalOptions =


LayoutOptions.End };
locationLabel.SetBinding(Label.TextProperty, "Location");

Grid.SetRowSpan(image, 2);

grid.Children.Add(image);
grid.Children.Add(nameLabel, 1, 0);
grid.Children.Add(locationLabel, 1, 1);

return grid;
});

Os elementos especificados na DataTemplate definem a aparência de cada item na lista. No exemplo, o layout do
DataTemplate é gerenciada por um Grid . O Grid contém uma Image objeto e duas Label objetos, que todos se
associar a propriedades do Monkey classe:

public class Monkey


{
public string Name { get; set; }
public string Location { get; set; }
public string Details { get; set; }
public string ImageUrl { get; set; }
}

As capturas de tela a seguir mostram o resultado da modelagem de cada item na lista:


Para obter mais informações sobre modelos de dados, confira Modelos de dados do Xamarin.Forms.

Links relacionados
CollectionView (amostra)
Associação de dados do xamarin. Forms
Modelos de dados do xamarin. Forms
Especifique o Layout do xamarin. Forms
CollectionView
12/04/2019 • 11 minutes to read

Baixar o exemplo

IMPORTANT
O CollectionView atualmente é uma visualização e não tem algumas das suas funcionalidades planejada. Além disso, a
API pode mudar conforme a implementação for concluída.

CollectionView Define as seguintes propriedades que controlam o layout:


ItemsLayout , do tipo IItemsLayout , especifica o layout a ser usado.
ItemSizingStrategy , do tipo ItemSizingStrategy , especifica a estratégia de medida do item a ser usado.

Essas propriedades têm o respaldo BindableProperty objetos, o que significa que as propriedades podem ser
alvos de vinculações de dados.
Por padrão, um CollectionView exibirá seus itens em uma lista vertical. No entanto, qualquer um dos seguintes
layouts podem ser usados:
Lista vertical – uma lista de coluna única que cresce verticalmente conforme novos itens são adicionados.
Lista horizontal – uma lista de única linha cresce horizontalmente conforme novos itens são adicionados.
Grade vertical – uma grade de várias coluna que cresce verticalmente conforme novos itens são adicionados.
Grade horizontal – uma grade de várias linhas cresce horizontalmente conforme novos itens são adicionados.
Esses layouts podem ser especificados definindo a ItemsLayout propriedade para a classe que deriva de
ItemsLayout classe. Essa classe define as propriedades a seguir:

Orientation , do tipo ItemsLayoutOrientation , especifica a direção na qual o CollectionView se expande


conforme itens são adicionados.
SnapPointsAlignment , do tipo SnapPointsAlignment , especifica como os pontos de alinhamento são alinhados
com os itens.
SnapPointsType , do tipo SnapPointsType , especifica o comportamento de pontos de alinhamento durante a
rolagem.
Essas propriedades têm o respaldo BindableProperty objetos, o que significa que as propriedades podem ser
alvos de vinculações de dados. Para obter mais informações sobre pontos de alinhamento, consulte ajustar pontos
na rolar um Item na exibição guia.
O ItemsLayoutOrientation enumeração define os seguintes membros:
Vertical indica que o CollectionView será expandida verticalmente conforme os itens são adicionados.
Horizontal indica que o CollectionView expandirá horizontalmente conforme itens são adicionados.
O ListItemsLayout herda a ItemsLayout classe e define estático VerticalList e HorizontalList membros. Esses
membros podem ser usados para criar listas verticais ou horizontais, respectivamente. Como alternativa, uma
ListItemsLayout objeto pode ser criado, especificando um ItemsLayoutOrientation membro de enumeração
como um argumento.
O GridItemsLayout herda o ItemsLayout de classe e define um Span propriedade do tipo int , que representa o
número de colunas ou linhas a serem exibidas na grade. O valor padrão de Span propriedade é 1, e seu valor
deve sempre ser maior que ou igual a 1.

NOTE
CollectionView usa os mecanismos de layout nativo para executar o layout.

Lista vertical
Por padrão, CollectionViewexibirá seus itens em um layout da lista vertical. Portanto, não é necessário definir o
ItemsLayout propriedade para usar este layout:

<CollectionView ItemsSource="{Binding Monkeys}">


<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Image Grid.RowSpan="2"
Source="{Binding ImageUrl}"
Aspect="AspectFill"
HeightRequest="60"
WidthRequest="60" />
<Label Grid.Column="1"
Text="{Binding Name}"
FontAttributes="Bold" />
<Label Grid.Row="1"
Grid.Column="1"
Text="{Binding Location}"
FontAttributes="Italic"
VerticalOptions="End" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>

No entanto, para fins de integridade, uma CollectionView pode ser definido para exibir seus itens em uma lista
vertical definindo seu ItemsLayout a um estático ListItemsLayout.VerticalList membro:

<CollectionView ItemsSource="{Binding Monkeys}"


ItemsLayout="{x:Static ListItemsLayout.VerticalList}">
...
</CollectionView>

Como alternativa, isso também pode ser feito definindo a ItemsLayout propriedade para um objeto do
ListItemsLayout classe, especificando as Vertical ItemsLayoutOrientation membro de enumeração como um
argumento:

<CollectionView ItemsSource="{Binding Monkeys}">


<CollectionView.ItemsLayout>
<ListItemsLayout>
<x:Arguments>
<ItemsLayoutOrientation>Vertical</ItemsLayoutOrientation>
</x:Arguments>
</ListItemsLayout>
</CollectionView.ItemsLayout>
...
</CollectionView>

O código C# equivalente é:

CollectionView collectionView = new CollectionView


{
...
ItemsLayout = ListItemsLayout.VerticalList
};

Isso resulta em uma lista de coluna única que cresce verticalmente conforme novos itens são adicionados:

Lista horizontal
CollectionView pode exibir seus itens em uma lista horizontal, definindo sua ItemsLayout propriedade para
estático ListItemsLayout.HorizontalList membro:
<CollectionView ItemsSource="{Binding Monkeys}"
ItemsLayout="{x:Static ListItemsLayout.HorizontalList}">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="35" />
<RowDefinition Height="35" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70" />
<ColumnDefinition Width="140" />
</Grid.ColumnDefinitions>
<Image Grid.RowSpan="2"
Source="{Binding ImageUrl}"
Aspect="AspectFill"
HeightRequest="60"
WidthRequest="60" />
<Label Grid.Column="1"
Text="{Binding Name}"
FontAttributes="Bold"
LineBreakMode="TailTruncation" />
<Label Grid.Row="1"
Grid.Column="1"
Text="{Binding Location}"
LineBreakMode="TailTruncation"
FontAttributes="Italic"
VerticalOptions="End" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>

Como alternativa, isso também pode ser feito definindo a ItemsLayout propriedade para um ListItemsLayout do
objeto, especificando as Horizontal ItemsLayoutOrientation membro de enumeração como um argumento:

<CollectionView ItemsSource="{Binding Monkeys}">


<CollectionView.ItemsLayout>
<ListItemsLayout>
<x:Arguments>
<ItemsLayoutOrientation>Horizontal</ItemsLayoutOrientation>
</x:Arguments>
</ListItemsLayout>
</CollectionView.ItemsLayout>
...
</CollectionView>

O código C# equivalente é:

CollectionView collectionView = new CollectionView


{
...
ItemsLayout = ListItemsLayout.HorizontalList
};

Isso resulta em uma lista de única linha, que cresce horizontalmente conforme novos itens são adicionados:
Grade vertical
CollectionView pode exibir seus itens em uma grade vertical, definindo sua ItemsLayout propriedade para um
GridItemsLayout do objeto cuja Orientation estiver definida como Vertical :

<CollectionView ItemsSource="{Binding Monkeys}">


<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical"
Span="2" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="35" />
<RowDefinition Height="35" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70" />
<ColumnDefinition Width="80" />
</Grid.ColumnDefinitions>
<Image Grid.RowSpan="2"
Source="{Binding ImageUrl}"
Aspect="AspectFill"
HeightRequest="60"
WidthRequest="60" />
<Label Grid.Column="1"
Text="{Binding Name}"
FontAttributes="Bold"
LineBreakMode="TailTruncation" />
<Label Grid.Row="1"
Grid.Column="1"
Text="{Binding Location}"
LineBreakMode="TailTruncation"
FontAttributes="Italic"
VerticalOptions="End" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>

O código C# equivalente é:

CollectionView collectionView = new CollectionView


{
...
ItemsLayout = new GridItemsLayout(2, ItemsLayoutOrientation.Vertical)
};

Por padrão, um vertical GridItemsLayout exibirá itens em uma única coluna. No entanto, este exemplo define o
GridItemsLayout.Span propriedade como 2. Isso resulta em uma grade de duas colunas, cresce verticalmente
conforme novos itens são adicionados:
Grade horizontal
CollectionView pode exibir seus itens em uma grade horizontal, definindo sua ItemsLayout propriedade para um
GridItemsLayout do objeto cuja Orientation estiver definida como Horizontal :

<CollectionView ItemsSource="{Binding Monkeys}">


<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Horizontal"
Span="4" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="35" />
<RowDefinition Height="35" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70" />
<ColumnDefinition Width="140" />
</Grid.ColumnDefinitions>
<Image Grid.RowSpan="2"
Source="{Binding ImageUrl}"
Aspect="AspectFill"
HeightRequest="60"
WidthRequest="60" />
<Label Grid.Column="1"
Text="{Binding Name}"
FontAttributes="Bold"
LineBreakMode="TailTruncation" />
<Label Grid.Row="1"
Grid.Column="1"
Text="{Binding Location}"
LineBreakMode="TailTruncation"
FontAttributes="Italic"
VerticalOptions="End" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>

O código C# equivalente é:
CollectionView collectionView = new CollectionView
{
...
ItemsLayout = new GridItemsLayout(4, ItemsLayoutOrientation.Horizontal)
};

Por padrão, um horizontal GridItemsLayout exibirá itens em uma única linha. No entanto, este exemplo define o
GridItemsLayout.Span propriedade para 4. Isso resulta em uma grade de quatro linhas, que cresce
horizontalmente conforme novos itens são adicionados:

Layout da direita para esquerda


CollectionView pode definir o layout de seu conteúdo em uma direção de fluxo da direita para esquerda,
definindo sua FlowDirection propriedade RightToLeft . No entanto, o FlowDirection propriedade idealmente
deve ser definida em um layout de página ou raiz, que faz com que todos os elementos dentro da página ou o
layout de raiz, para responder a direção do fluxo:

<?xml version="1.0" encoding="UTF-8"?>


<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="CollectionViewDemos.Views.VerticalListFlowDirectionPage"
Title="Vertical list (RTL FlowDirection)"
FlowDirection="RightToLeft">
<StackLayout Margin="20">
<CollectionView ItemsSource="{Binding Monkeys}">
...
</CollectionView>
</StackLayout>
</ContentPage>

O padrão FlowDirection para um elemento com um pai é MatchParent . Portanto, o CollectionView herda a
FlowDirection valor da propriedade a StackLayout , que por sua vez herda o FlowDirection valor da propriedade
do ContentPage . Isso resulta no layout da direita para esquerda mostrado nas capturas de tela seguir:
Para obter mais informações sobre a direção do fluxo, consulte localização da direita para esquerda.

Dimensionamento do item
Por padrão, cada item em uma CollectionView é individualmente medido e dimensionado, desde que os
elementos de interface do usuário na DataTemplate não especificar tamanhos fixos. Esse comportamento, que
pode ser alterado, é especificado pelo CollectionView.ItemSizingStrategy valor da propriedade. Esse valor de
propriedade pode ser definido como um do ItemSizingStrategy membros de enumeração:
MeasureAllItems – cada item é medida individualmente. Este é o valor padrão.
MeasureFirstItem – somente o primeiro item é medido, com todos os itens subsequentes que está sendo
fornecidos do mesmo tamanho que o primeiro item.

IMPORTANT
O MeasureFirstItem estratégia de dimensionamento deve ser usado em situações em que o tamanho do item se destina
a ser uniforme em todos os itens e resultará em um melhor desempenho.

O exemplo de código a seguir mostra a configuração de ItemSizingStrategy propriedade:

<CollectionView ...
ItemSizingStrategy="MeasureFirstItem">
...
</CollectionView>

O código C# equivalente é:

CollectionView collectionView = new CollectionView


{
...
ItemSizingStrategy = ItemSizingStrategy.MeasureFirstItem
};

Links relacionados
CollectionView (amostra)
Localização da direita para esquerda
Rolar um Item na exibição
Definir o modo de seleção CollectionView
12/04/2019 • 8 minutes to read

Baixar o exemplo

IMPORTANT
O CollectionView atualmente é uma visualização e não tem algumas das suas funcionalidades planejada. Além disso, a API
pode mudar conforme a implementação for concluída.

CollectionView Define as seguintes propriedades que controlam a seleção de item:


SelectionMode , do tipo SelectionMode , o modo de seleção.
SelectedItem , do tipo object , o item selecionado na lista. Essa propriedade tem um null valor quando
nenhum item está selecionado.
SelectionChangedCommand , do tipo ICommand , que é executado quando o item selecionado é alterado.
SelectionChangedCommandParameter , do tipo object , que é o parâmetro que é passado para o
SelectionChangedCommand .

Todas essas propriedades têm o respaldo BindableProperty objetos, o que significa que as propriedades podem
ser alvos de vinculações de dados.
Por padrão, CollectionView seleção está desabilitada. No entanto, esse comportamento pode ser alterado
definindo a SelectionMode valor de propriedade a um do SelectionMode membros de enumeração:
None – indica que os itens não podem ser selecionados. Este é o valor padrão.
Single – indica que um único item pode ser selecionado, com o item selecionado que está sendo realçado.
Multiple – indica que vários itens podem ser selecionados, com os itens selecionados que está sendo
realçados.
CollectionView define uma SelectionChanged evento que é disparado quando o SelectedItem propriedade é
alterada, seja porque o usuário selecionar um item da lista, ou quando um aplicativo define a propriedade. O
SelectionChangedEventArgs objeto que acompanha o SelectionChanged evento tem duas propriedades, ambos do
tipo IReadOnlyList<object> :
PreviousSelection – a lista de itens que foram selecionados, antes que a seleção é alterada.
CurrentSelection – a lista de itens selecionados, após a alteração da seleção.

Seleção única
Quando o SelectionMode estiver definida como Single , um único item no CollectionView podem ser
selecionados. Quando um item é selecionado, o SelectedItem propriedade será definida como o valor do item
selecionado. Quando essa propriedade é alterada, o SelectionChangedCommand é executada (com o valor da
SelectionChangedCommandParameter que está sendo passado para o ICommand ) e o SelectionChanged evento é
acionado.
A exemplo XAML a seguir mostra um CollectionView que pode responder a seleção de item único:

<CollectionView ItemsSource="{Binding Monkeys}"


SelectionMode="Single"
SelectionChanged="OnCollectionViewSelectionChanged">
...
</CollectionView>

O código C# equivalente é:

CollectionView collectionView = new CollectionView


{
SelectionMode = SelectionMode.Single
};
collectionView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys");
collectionView.SelectionChanged += OnCollectionViewSelectionChanged;

Neste exemplo de código, o OnCollectionViewSelectionChanged manipulador de eventos é executado quando o


SelectionChanged evento é acionado, com o manipulador de eventos ao recuperar o item selecionado
anteriormente e o item selecionado atual:

void OnCollectionViewSelectionChanged(object sender, SelectionChangedEventArgs e)


{
string previous = (previousSelectedItems.FirstOrDefault() as Monkey)?.Name;
string current = (currentSelectedItems.FirstOrDefault() as Monkey)?.Name;
...
}

IMPORTANT
O SelectionChanged eventos podem ser acionados por alterações que ocorrem como resultado da alteração de
SelectionMode propriedade.

As capturas de tela a seguir mostram a seleção de item único em um CollectionView :

Pré-seleção
Quando o SelectionMode estiver definida como Single , um único item na CollectionView previamente
selecionadas, definindo o SelectedItem propriedade para o item. A exemplo XAML a seguir mostra um
CollectionView que pré-seleciona um único item:
<CollectionView ItemsSource="{Binding Monkeys}"
SelectionMode="Single"
SelectedItem="{Binding SelectedMonkey, Mode=TwoWay}">
...
</CollectionView>

O código C# equivalente é:

CollectionView collectionView = new CollectionView


{
SelectionMode = SelectionMode.Single
};
collectionView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys");
collectionView.SetBinding(SelectableItemsView.SelectedItemProperty, "SelectedMonkey", BindingMode.TwoWay);

O SelectedItem associa dados de propriedade para o SelectedMonkey propriedade do modelo de exibição


conectado, o que é do tipo Monkey . Um TwoWay associação é usada para que, se o usuário altera o item
selecionado, o valor da SelectedMonkey propriedade será definida para selecionado Monkey objeto. O
SelectedMonkey propriedade está definida na MonkeysViewModel classe e é definido como o quarto item do
Monkeys coleção:

public class MonkeysViewModel : INotifyPropertyChanged


{
...
public ObservableCollection<Monkey> Monkeys { get; private set; }

Monkey selectedMonkey;
public Monkey SelectedMonkey
{
get
{
return selectedMonkey;
}
set
{
if (selectedMonkey != value)
{
selectedMonkey = value;
}
}
}

public MonkeysViewModel()
{
...
selectedMonkey = Monkeys.Skip(3).FirstOrDefault();
}
...
}

Portanto, quando o CollectionView for exibida, o quarto item na lista é pré-selecionada:


Alterar a cor do item selecionado
CollectionView tem um Selected que pode ser usado para iniciar uma alteração visual para o item
VisualState
selecionado no CollectionView . Caso de uso de um comum para isso VisualState é alterar a cor do plano de
fundo do item selecionado, que é mostrado no exemplo XAML a seguir:

<ContentPage ...>
<ContentPage.Resources>
<Style TargetType="Grid">
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Selected">
<VisualState.Setters>
<Setter Property="BackgroundColor"
Value="LightSkyBlue" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
</ContentPage.Resources>
<StackLayout Margin="20">
<CollectionView ItemsSource="{Binding Monkeys}"
SelectionMode="Single">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10">
...
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</ContentPage>

IMPORTANT
O Style que contém o Selected VisualState deve ter uma TargetType valor da propriedade que é o tipo de
elemento raiz do DataTemplate , que é definido como o ItemTemplate valor da propriedade.

Neste exemplo, o Style.TargetType o valor da propriedade é definido como Grid porque o elemento raiz do
ItemTemplate é um Grid . O Selected VisualState Especifica que quando um item no CollectionView estiver
selecionada, o BackgroundColor do item será definido como LightSkyBlue :
[ ] (selection-images/single-selection-color-
large.png#lightbox " Lista vertical de CollectionView com uma cor personalizada de seleção única")
Para obter mais informações sobre estados visuais, consulte Gerenciador de estado Visual do xamarin. Forms.

Desabilitar seleção
CollectionView seleção é desabilitada por padrão. No entanto, se um CollectionView tem seleção habilitada, ele
pode ser desabilitado definindo o SelectionMode propriedade para None :

<CollectionView ...
SelectionMode="None" />

O código C# equivalente é:

CollectionView collectionView = new CollectionView


{
...
SelectionMode = SelectionMode.None
};

Quando o SelectionMode estiver definida como None , os itens na CollectionView não pode ser selecionado, o
SelectedItem propriedade permanecerá null e o SelectionChanged evento não será disparado.

NOTE
Quando um item foi selecionado e o SelectionMode propriedade é alterada de Single ao None , o SelectedItem
propriedade será definida como null e o SelectionChanged evento será acionado com um vazio CurrentSelection
propriedade.

Links relacionados
CollectionView (amostra)
Xamarin. Forms Visual State Manager
Exibir um EmptyView quando dados não estão
disponível
12/04/2019 • 9 minutes to read

Baixar o exemplo

IMPORTANT
O CollectionView atualmente é uma visualização e não tem algumas das suas funcionalidades planejada. Além disso, a API
pode mudar conforme a implementação for concluída.

CollectionView Define as propriedades a seguir que podem ser usadas para fornecer comentários do usuário
quando não há nenhum dado para exibir:
EmptyView , do tipo , a cadeia de caracteres, a associação ou o modo de exibição que será exibido
object
quando o ItemsSource é de propriedade null , ou quando a coleção especificada pelo ItemsSource é de
propriedade null ou está vazio. O valor padrão é null .
EmptyViewTemplate , do tipo DataTemplate , o modelo a ser usado para formatar especificado EmptyView . O
valor padrão é null .
Essas propriedades têm o respaldo BindableProperty objetos, o que significa que as propriedades podem ser alvos
de vinculações de dados.
Os cenários de uso principal para a configuração de EmptyView propriedade estiver exibindo comentários do
usuário quando uma operação de filtragem em um CollectionView produz sem dados e exibir comentários do
usuário, enquanto os dados estão sendo recuperados de um serviço web.

NOTE
O EmptyView propriedade pode ser definida como uma exibição que inclui conteúdo interativo, se necessário.

Para obter mais informações sobre modelos de dados, confira Modelos de dados do Xamarin.Forms.

Exibir uma cadeia de caracteres quando dados não estão disponíveis


O EmptyView propriedade pode ser definida como uma cadeia de caracteres, que será exibido quando o
ItemsSource é de propriedade null , ou quando a coleção especificada pelo ItemsSource é de propriedade null
ou está vazio. O XAML a seguir mostra um exemplo desse cenário:

<CollectionView ItemsSource="{Binding EmptyMonkeys}"


EmptyView="No items to display" />

O código C# equivalente é:
CollectionView collectionView = new CollectionView
{
EmptyView = "No items to display"
};
collectionView.SetBinding(ItemsView.ItemsSourceProperty, "EmptyMonkeys");

O resultado é que, como os dados associados a coleção é null , a cadeia de caracteres é definido como o
EmptyView valor da propriedade é exibido:

Exibir modos de exibição quando dados não estão disponíveis


O EmptyView propriedade pode ser definida como um modo de exibição, que será exibido quando o ItemsSource
é de propriedade null , ou quando a coleção especificada pelo ItemsSource é de propriedade null ou está vazio.
Isso pode ser uma única exibição ou uma exibição que contém vários modos de exibição filho. A exemplo XAML a
seguir mostra o EmptyView propriedade definida como uma exibição que contém vários modos de exibição filho:

<StackLayout Margin="20">
<SearchBar x:Name="searchBar"
SearchCommand="{Binding FilterCommand}"
SearchCommandParameter="{Binding Source={x:Reference searchBar}, Path=Text}"
Placeholder="Filter" />
<CollectionView ItemsSource="{Binding Monkeys}">
<CollectionView.ItemTemplate>
<DataTemplate>
...
</DataTemplate>
</CollectionView.ItemTemplate>
<CollectionView.EmptyView>
<StackLayout>
<Label Text="No results matched your filter."
Margin="10,25,10,10"
FontAttributes="Bold"
FontSize="18"
HorizontalOptions="Fill"
HorizontalTextAlignment="Center" />
<Label Text="Try a broader filter?"
FontAttributes="Italic"
FontSize="12"
HorizontalOptions="Fill"
HorizontalTextAlignment="Center" />
</StackLayout>
</CollectionView.EmptyView>
</CollectionView>
</StackLayout>

O código C# equivalente é:
SearchBar searchBar = new SearchBar { ... };
CollectionView collectionView = new CollectionView
{
EmptyView = new StackLayout
{
Children =
{
new Label { Text = "No results matched your filter.", ... },
new Label { Text = "Try a broader filter?", ... }
}
}
};
collectionView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys");

Quando o SearchBar executa o FilterCommand , a coleção exibida pelo CollectionView é filtrado para o termo de
pesquisa são armazenados no SearchBar.Text propriedade. Se a operação de filtragem não produz nenhum dado,
o StackLayout definido como o EmptyView valor da propriedade é exibido:

Exibir um tipo de modelo personalizado quando dados não estão


disponíveis
O EmptyView propriedade pode ser definida como um tipo personalizado, cujo modelo é exibido quando o
ItemsSource é de propriedade null , ou quando a coleção especificada pelo ItemsSource é de propriedade null
ou está vazio. O EmptyViewTemplate propriedade pode ser definida como uma DataTemplate que define a
aparência do EmptyView . O XAML a seguir mostra um exemplo desse cenário:
<StackLayout Margin="20">
<SearchBar x:Name="searchBar"
SearchCommand="{Binding FilterCommand}"
SearchCommandParameter="{Binding Source={x:Reference searchBar}, Path=Text}"
Placeholder="Filter" />
<CollectionView ItemsSource="{Binding Monkeys}">
<CollectionView.ItemTemplate>
<DataTemplate>
...
</DataTemplate>
</CollectionView.ItemTemplate>
<CollectionView.EmptyView>
<views:FilterData Filter="{Binding Source={x:Reference searchBar}, Path=Text}" />
</CollectionView.EmptyView>
<CollectionView.EmptyViewTemplate>
<DataTemplate>
<Label Text="{Binding Filter, StringFormat='Your filter term of {0} did not match any
records.'}"
Margin="10,25,10,10"
FontAttributes="Bold"
FontSize="18"
HorizontalOptions="Fill"
HorizontalTextAlignment="Center" />
</DataTemplate>
</CollectionView.EmptyViewTemplate>
</CollectionView>
</StackLayout>

O código C# equivalente é:

SearchBar searchBar = new SearchBar { ... };


CollectionView collectionView = new CollectionView
{
EmptyView = new FilterData { Filter = searchBar.Text },
EmptyViewTemplate = new DataTemplate(() =>
{
return new Label { ... };
})
};

O FilterData tipo define uma Filter propriedade e um correspondente BindableProperty :

public class FilterData : BindableObject


{
public static readonly BindableProperty FilterProperty = BindableProperty.Create(nameof(Filter),
typeof(string), typeof(FilterData), null);

public string Filter


{
get { return (string)GetValue(FilterProperty); }
set { SetValue(FilterProperty, value); }
}
}

O EmptyView estiver definida como uma FilterData objeto e o Filter associa dados de propriedade para o
SearchBar.Text propriedade. Quando o SearchBar executa o FilterCommand , a coleção exibida pelo
CollectionView é filtrado para o termo de pesquisa são armazenados no Filter propriedade. Se a operação de
filtragem não produz nenhum dado, o Label definidos no DataTemplate , que é definido como o
EmptyViewTemplate valor da propriedade, é exibida:
NOTE
Ao exibir um tipo de modelo personalizado quando dados não estiverem disponíveis, o EmptyViewTemplate propriedade
pode ser definida como uma exibição que contém vários modos de exibição filho.

Escolha um EmptyView em tempo de execução


Modos de exibição que serão exibidos como uma EmptyView quando os dados não estiverem disponíveis, pode ser
definida como ContentView objetos em um ResourceDictionary . O EmptyView propriedade, em seguida, pode ser
definida para um determinado ContentView , com base em alguma lógica de negócios, em tempo de execução. O
exemplo XAML a seguir mostra um exemplo desse cenário:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="CollectionViewDemos.Views.EmptyViewSwapPage"
Title="EmptyView (swap)">
<ContentPage.Resources>
<ContentView x:Key="BasicEmptyView">
<StackLayout>
<Label Text="No items to display."
Margin="10,25,10,10"
FontAttributes="Bold"
FontSize="18"
HorizontalOptions="Fill"
HorizontalTextAlignment="Center" />
</StackLayout>
</ContentView>
<ContentView x:Key="AdvancedEmptyView">
<StackLayout>
<Label Text="No results matched your filter."
Margin="10,25,10,10"
FontAttributes="Bold"
FontSize="18"
HorizontalOptions="Fill"
HorizontalTextAlignment="Center" />
<Label Text="Try a broader filter?"
FontAttributes="Italic"
FontSize="12"
HorizontalOptions="Fill"
HorizontalTextAlignment="Center" />
</StackLayout>
</ContentView>
</ContentPage.Resources>

<StackLayout Margin="20">
<SearchBar x:Name="searchBar"
SearchCommand="{Binding FilterCommand}"
SearchCommandParameter="{Binding Source={x:Reference searchBar}, Path=Text}"
Placeholder="Filter" />
<StackLayout Orientation="Horizontal">
<Label Text="Toggle EmptyViews" />
<Switch Toggled="OnEmptyViewSwitchToggled" />
</StackLayout>
<CollectionView x:Name="collectionView"
ItemsSource="{Binding Monkeys}">
<CollectionView.ItemTemplate>
<DataTemplate>
...
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</ContentPage>

Esse XAML define dois ContentView objetos no nível da página ResourceDictionary , com o Switch objeto
controlando quais ContentView objeto será definido como o EmptyView valor da propriedade. Quando o Switch é
alternado, o OnEmptyViewSwitchToggled manipulador de eventos executa o ToggleEmptyView método:

void ToggleEmptyView(bool isToggled)


{
collectionView.EmptyView = isToggled ? Resources["BasicEmptyView"] : Resources["AdvancedEmptyView"];
}

O ToggleEmptyView método define o EmptyView propriedade da collectionView objeto para um dos dois
ContentView objetos armazenados no ResourceDictionary , com base no valor da Switch.IsToggled propriedade.
Quando o SearchBar executa o FilterCommand , a coleção exibida pelo CollectionView é filtrado para o termo de
pesquisa são armazenados no SearchBar.Text propriedade. Se a operação de filtragem não produz nenhum dado,
o ContentView objeto definido como o EmptyView propriedade é exibida:

Para obter mais informações sobre dicionários de recursos, consulte dicionários de recursos do xamarin. Forms.

Links relacionados
CollectionView (amostra)
Modelos de dados do xamarin. Forms
Dicionários de recursos do xamarin. Forms
Rolar um Item na exibição
12/04/2019 • 9 minutes to read

Baixar o exemplo

IMPORTANT
O CollectionView atualmente é uma visualização e não tem algumas das suas funcionalidades planejada. Além disso, a
API pode mudar conforme a implementação for concluída.

CollectionView define dois ScrollTo métodos, que rolagem os itens na exibição. Uma das sobrecargas rola o
item no índice especificado na exibição, enquanto o outro rola o item especificado na exibição. Ambas as
sobrecargas têm argumentos adicionais que podem ser especificados para indicar a posição exata do item depois
que a rolagem for concluída e se deseja animar a rolagem.
CollectionView define uma ScrollToRequestedevento que é disparado quando uma da ScrollTo métodos é
invocado. O ScrollToRequestedEventArgs objeto que acompanha o ScrollToRequested evento tem muitas
propriedades, incluindo IsAnimated , Index , Item , e ScrollToPosition . Essas propriedades são definidas a partir
dos argumentos especificados no ScrollTo chamadas de método.
Quando um dedo do usuário para iniciar uma rolagem, a posição final da rolagem pode ser controlada para que
os itens são totalmente exibidas. Esse recurso é conhecido como encaixe, como itens de ajuste para posicionar
durante a rolagem é interrompido. Para obter mais informações, consulte ajustar pontos.

Rolar um item em um índice na exibição


A primeira sobrecarga do método rola o item no índice especificado na exibição. Considerando um
ScrollTo
CollectionView objeto chamado collectionView , o exemplo a seguir mostra como rolar o item no índice 12 no
modo de exibição:

collectionView.ScrollTo(12);

Rolar um item na exibição


O segundo sobrecarga do método rola o item especificado na exibição. Considerando um
ScrollTo
CollectionView objeto chamado collectionView , o exemplo a seguir mostra como rolar o item especificado no
modo de exibição:

MonkeysViewModel viewModel = BindingContext as MonkeysViewModel;


Monkey monkey = viewModel.Monkeys.FirstOrDefault(m => m.Name == "Proboscis Monkey");
collectionView.ScrollTo(monkey);

Posição de rolagem de controle


Ao rolar um item no modo de exibição, a posição exata do item após a rolagem pode ser especificada com o
position argumento do ScrollTo métodos. Esse argumento aceita uma ScrollToPosition membro de
enumeração.
MakeVisible
O ScrollToPosition.MakeVisible membro indica que o item deve ser rolado até que ele esteja visível no modo de
exibição:

collectionView.ScrollTo(monkey, position: ScrollToPosition.MakeVisible);

Esse código de exemplo resulta na rolagem mínima necessária para rolar o item na exibição:

NOTE
O ScrollToPosition.MakeVisible membro é usado por padrão, se o position argumento não for especificado ao
chamar o ScrollTo método.

Início
O ScrollToPosition.Start membro indica que o item deve ser rolado para o início do modo de exibição:

collectionView.ScrollTo(monkey, position: ScrollToPosition.Start);

Esse código de exemplo resulta no item que está sendo rolado para o início da exibição:
Centralizado
O ScrollToPosition.Center membro indica que o item deve ser rolado para o centro do modo de exibição:

collectionView.ScrollTo(monkey, position: ScrollToPosition.Center);

Esse código de exemplo resulta no item que está sendo rolado para o centro da exibição:

End
O ScrollToPosition.End membro indica que o item deve ser rolado até o final do modo de exibição:

collectionView.ScrollTo(monkey, position: ScrollToPosition.End);

Esse código de exemplo resulta no item que está sendo rolado até o final do modo de exibição:
Desativar a animação de rolagem
Uma animação de rolagem é exibida quando um item de rolagem no modo de exibição. No entanto, essa
animação pode ser desabilitada definindo a animate argumento do ScrollTo método false :

collectionView.ScrollTo(monkey, animate: false);

Pontas de encaixe
Quando um dedo do usuário para iniciar uma rolagem, a posição final da rolagem pode ser controlada para que
os itens são totalmente exibidas. Esse recurso é conhecido como encaixe, como itens de ajustar-se à posição
quando rolagem for interrompido e é controlada pelas seguintes propriedades do ItemsLayout classe:
SnapPointsType , do tipo SnapPointsType , especifica o comportamento de pontos de alinhamento durante a
rolagem.
SnapPointsAlignment , do tipo SnapPointsAlignment , especifica como os pontos de alinhamento são alinhados
com os itens.
Essas propriedades têm o respaldo BindableProperty objetos, o que significa que as propriedades podem ser
alvos de vinculações de dados.

NOTE
Quando o ajuste ocorre, ele ocorrerá na direção que produz a menor quantidade de movimento.

Tipo de pontas de encaixe


O SnapPointsType enumeração define os seguintes membros:
None indica que rolagem não se ajusta aos itens.
Mandatory indica que o conteúdo sempre se ajusta para o mais próximo snap aponta para onde rolagem
naturalmente pararia, ao longo da direção da inércia.
MandatorySingle indica o mesmo comportamento que Mandatory , mas rola apenas um item por vez.

Por padrão, o SnapPointsType estiver definida como SnapPointsType.None , que garante que a rolagem não se
ajusta itens, conforme mostrado nas capturas de tela seguir:
Ajustar-se pontos de alinhamento
O SnapPointsAlignment enumeração define Start , Center ,e End membros.

IMPORTANT
O valor da SnapPointsAlignment propriedade só é respeitada quando o SnapPointsType estiver definida como
Mandatory , ou MandatorySingle .

Início
O SnapPointsAlignment.Start membro indica que pontos de alinhamento são alinhados com a borda à esquerda
de itens.
Por padrão, o SnapPointsAlignment estiver definida como SnapPointsAlignment.Start . No entanto, para fins de
integridade, o exemplo XAML a seguir mostra como definir este membro de enumeração:

<CollectionView x:Name="collectionView"
ItemsSource="{Binding Monkeys}">
<CollectionView.ItemsLayout>
<ListItemsLayout SnapPointsType="MandatorySingle"
SnapPointsAlignment="Start">
<x:Arguments>
<ItemsLayoutOrientation>Vertical</ItemsLayoutOrientation>
</x:Arguments>
</ListItemsLayout>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
...
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>

O código C# equivalente é:
CollectionView collectionView = new CollectionView
{
ItemsLayout = new ListItemsLayout(ItemsLayoutOrientation.Vertical)
{
SnapPointsType = SnapPointsType.MandatorySingle,
SnapPointsAlignment = SnapPointsAlignment.Start
},
ItemTemplate = new DataTemplate(() =>
{
return null;
})
};

Quando um dedo do usuário para iniciar uma rolagem, o item superior será alinhado à parte superior do modo
de exibição:

Centralizado
O SnapPointsAlignment.Center membro indica que pontos de alinhamento são alinhados com a Central de itens.
O exemplo XAML a seguir mostra como definir este membro de enumeração:

<CollectionView x:Name="collectionView"
ItemsSource="{Binding Monkeys}">
<CollectionView.ItemsLayout>
<ListItemsLayout SnapPointsType="MandatorySingle"
SnapPointsAlignment="Center">
<x:Arguments>
<ItemsLayoutOrientation>Vertical</ItemsLayoutOrientation>
</x:Arguments>
</ListItemsLayout>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
...
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>

O código C# equivalente é:
CollectionView collectionView = new CollectionView
{
ItemsLayout = new ListItemsLayout(ItemsLayoutOrientation.Vertical)
{
SnapPointsType = SnapPointsType.MandatorySingle,
SnapPointsAlignment = SnapPointsAlignment.Center
},
ItemTemplate = new DataTemplate(() =>
{
return null;
})
};

Quando um dedo do usuário para iniciar uma rolagem, o item superior será centralizado na parte superior do
modo de exibição:

End
O SnapPointsAlignment.End membro indica que os pontos de alinhamento são alinhados com a borda direita de
itens. O exemplo XAML a seguir mostra como definir este membro de enumeração:

<CollectionView x:Name="collectionView"
ItemsSource="{Binding Monkeys}">
<CollectionView.ItemsLayout>
<ListItemsLayout SnapPointsType="MandatorySingle"
SnapPointsAlignment="End">
<x:Arguments>
<ItemsLayoutOrientation>Vertical</ItemsLayoutOrientation>
</x:Arguments>
</ListItemsLayout>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
...
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>

O código C# equivalente é:
CollectionView collectionView = new CollectionView
{
ItemsLayout = new ListItemsLayout(ItemsLayoutOrientation.Vertical)
{
SnapPointsType = SnapPointsType.MandatorySingle,
SnapPointsAlignment = SnapPointsAlignment.End
},
ItemTemplate = new DataTemplate(() =>
{
return null;
})
};

Quando um dedo do usuário para iniciar uma rolagem, o item na parte inferior será alinhado à parte inferior do
modo de exibição:

Links relacionados
CollectionView (amostra)
Cores no xamarin. Forms
12/04/2019 • 5 minutes to read

baixar o exemplo
Xamarin. Forms fornece uma classe flexível de cor de plataforma cruzada.
Este artigo apresenta as várias maneiras do Color classe pode ser usada no xamarin. Forms.
O Color classe fornece vários métodos para criar uma instância de cor
Chamado Colors -uma coleção de comuns cores nomeadas, incluindo Red , Green , e Blue .
FromHex -valor semelhante à sintaxe usada em HTML, por exemplo, "00FF00" cadeia de caracteres. Alfa é
opcionalmente pode ser especificado como o primeiro par de caracteres ("CC00FF00").
FromHsla -matiz, saturação e luminosidade double valores, com valor de alfa opcional (0.0-1.0).
FromRgb -vermelho, verde e azul int valores (0 a 255).
FromRgba -vermelho, verde, azul e alfa int valores (0 a 255).
FromUint -definir uma única double valor que representa argb.
Eis aqui algumas cores de exemplo, atribuídos para o BackgroundColor de alguns rótulos usando diferentes
variações da sintaxe permitido:

var red = new Label { Text = "Red", BackgroundColor = Color.Red };


var orange = new Label { Text = "Orange",BackgroundColor = Color.FromHex("FF6A00") };
var yellow = new Label { Text = "Yellow",BackgroundColor = Color.FromHsla(0.167, 1.0, 0.5, 1.0) };
var green = new Label { Text = "Green", BackgroundColor = Color.FromRgb (38, 127, 0) };
var blue = new Label { Text = "Blue", BackgroundColor = Color.FromRgba(0, 38, 255, 255) };
var indigo = new Label { Text = "Indigo",BackgroundColor = Color.FromRgb (0, 72, 255) };
var violet = new Label { Text = "Violet",BackgroundColor = Color.FromHsla(0.82, 1, 0.25, 1) };

var transparent = new Label { Text = "Transparent",BackgroundColor = Color.Transparent };


var @default = new Label { Text = "Default", BackgroundColor = Color.Default };
var accent = new Label { Text = "Accent", BackgroundColor = Color.Accent };

Essas cores são mostrados em cada plataforma abaixo. Observe a cor final - Accent -é uma cor blue-ish para iOS
e Android; esse valor é definido pelo xamarin. Forms.

Color.Default
Use o Default para definir um valor de cor para o padrão de plataforma (Noções básicas sobre que isso
representa uma cor subjacente diferente em cada plataforma para cada propriedade) (ou defina novamente uma).
Os desenvolvedores podem usar esse valor para definir um Color propriedade, mas deve não consultar essa
instância para obter seus valores RGB do componente (eles são todos definidos como -1).

Color.Transparent
Defina a cor para limpar.

Color.Accent
No iOS e Android desta instância é definida como uma cor contrastante que está visível na tela de fundo padrão,
mas não é o mesmo que a cor do texto padrão.

Métodos adicionais
Color instâncias incluem métodos adicionais que podem ser usados para criar novas cores:
AddLuminosity -retorna uma nova cor, modificando a luminosidade pelo delta fornecido.
WithHue -retorna uma nova cor, substituindo o hue com o valor fornecido.
WithLuminosity -retorna uma nova cor, substituindo a luminosidade com o valor fornecido.
WithSaturation -retorna uma nova cor, substituindo a saturação com o valor fornecido.
MultiplyAlpha -retorna uma nova cor, modificando o alfa, multiplicá-lo pelo valor alfa fornecido.

Conversões implícitas
Conversão implícita entre o Xamarin.Forms.Color e System.Drawing.Color tipos podem ser executados:

Xamarin.Forms.Color xfColor = Xamarin.Forms.Color.FromRgb(0, 72, 255);


System.Drawing.Color sdColor = System.Drawing.Color.FromArgb(38, 127, 0);

// Implicity convert from a Xamarin.Forms.Color to a System.Drawing.Color


System.Drawing.Color sdColor2 = xfColor;

// Implicitly convert from a System.Drawing.Color to a Xamarin.Forms.Color


Xamarin.Forms.Color xfColor2 = sdColor;

Device.RuntimePlatform
Este trecho de código usa o Device.RuntimePlatform propriedade para definir seletivamente a cor de um
ActivityIndicator :

ActivityIndicator activityIndicator = new ActivityIndicator


{
Color = Device.RuntimePlatform == Device.iOS ? Color.Black : Color.Default,
IsRunning = true
};

Usando do XAML
Cores também podem ser facilmente referenciadas em XAML usando os nomes de cor definidos ou as
representações hexa mostradas aqui:
<Label Text="Sea color" BackgroundColor="Aqua" />
<Label Text="RGB" BackgroundColor="#00FF00" />
<Label Text="Alpha plus RGB" BackgroundColor="#CC00FF00" />
<Label Text="Tiny RGB" BackgroundColor="#0F0" />
<Label Text="Tiny Alpha plus RGB" BackgroundColor="#C0F0" />

NOTE
Ao usar a compilação de XAML, nomes de cores diferenciam maiusculas de minúsculas e, portanto, podem ser escritos em
letras minúsculas. Para obter mais informações sobre a compilação de XAML, consulte compilação XAML.

Resumo
O xamarin. Forms Color classe é usada para criar referências de cores de reconhecimento de plataforma. Ele
pode ser usado no código compartilhado e XAML.

Links relacionados
ColorsSample
Seletor de associável (amostra)
Referência de Controles
12/04/2019 • 2 minutes to read

baixar o exemplo
Uma descrição de todos os elementos visuais usados para construir um aplicativo xamarin. Forms.
A interface visual de um aplicativo xamarin. Forms é construída de objetos que são mapeados para controles
nativos de cada plataforma de destino. Isso permite que aplicativos específicos da plataforma para iOS, Android e
plataforma Universal do Windows usar código xamarin. Forms contido em um .NET Standard library ou um
projeto compartilhado.
Os quatro grupos de controle principal usados para criar a interface do usuário de um aplicativo xamarin. Forms
são mostrados nesses quatro artigos:
Páginas
Layouts
Modos de exibição
Células
Geralmente, uma página do xamarin. Forms ocupa a tela inteira. A página normalmente contém um layout, que
contém exibições e possivelmente outros layouts. As células são componentes especializados usados na conexão
com TableView e ListView .
Nos quatro artigos sobre páginas, Layouts, exibições , e células, cada tipo de controle é descrito com links
para documentação da API, um artigo que descreve seu uso (se houver) e um ou mais programas de exemplo (se
existirem). Cada tipo de controle também é acompanhado de uma captura de tela mostrando uma página a partir
de FormsGallery exemplo dispositivos em execução no iOS, Android e UWP. Cada captura de tela abaixo estão
os links para o código-fonte para a página em C#, a página XAML equivalente e (quando apropriado) o arquivo
de code-behind do C# para a página XAML.

Links relacionados
Exemplo de xamarin. Forms FormsGallery
Documentação da API
Páginas do xamarin. Forms
12/04/2019 • 4 minutes to read

baixar o exemplo
Páginas do xamarin. Forms representam telas de aplicativos móveis de plataforma cruzada.
Todos os tipos de página que são descritos abaixo derivam da classe Page do Xamarin.Forms. Esses elementos
visuais ocupam toda a tela ou a maior parte dela. Um objeto Page representa um ViewController no iOS e um
Page na Plataforma Universal do Windows. No Android, cada página ocupa a tela como Activity , mas as
páginas Xamarin.Forms não são objetos Activity .

Pages (Páginas)
Xamarin. Forms dá suporte aos seguintes tipos de página:
ContentPage

ContentPage é o tipo mais simples e mais comum da


página. Defina a Content propriedade para um único
View objeto, que é geralmente um Layout como
StackLayout , Grid , ou ScrollView .

Documentação da API

O código C# para esta página / página XAML

MasterDetailPage
Um MasterDetailPage gerencia dois painéis de
informações. Defina as Master propriedade a uma página
em geral, mostrando uma lista ou menu. Defina as Detail
propriedade para uma página mostrando um item
selecionado da página mestra. O IsPresented propriedade
controla se a página mestra ou de detalhes está visível.

Documentação da API / guia / exemplo

O código C# para esta página / página XAML com de lógica

NavigationPage

O NavigationPage gerencia a navegação entre outras


páginas usando uma arquitetura baseada em pilha. Ao usar a
navegação de página em seu aplicativo, uma instância da
página inicial deve ser passada para o construtor de um
NavigationPage objeto.

Documentação da API / guia / exemplo 1, 2, e 3

O código C# para esta página / página XAML com código =


atrás

TabbedPage

TabbedPage deriva de abstrata MultiPage de classe e


permite a navegação entre filho usando guias de páginas.
Defina a Children propriedade a uma coleção de páginas
ou conjunto a ItemsSource propriedade a uma coleção de
objetos de dados e o ItemTemplate propriedade para um
DataTemplate que descreve como cada objeto deve ser
visualmente representado.

Documentação da API / guia / exemplo 1 e 2

O código C# para esta página / página XAML

CarouselPage
CarouselPage deriva de abstrata MultiPage de classe e
permite a navegação entre filho páginas por meio de passar
o dedo dedo. Defina a Children propriedade a uma
coleção de ContentPage objetos ou conjunto o
ItemsSource propriedade a uma coleção de objetos de
dados e o ItemTemplate propriedade como um
DataTemplate que descreve como cada objeto deve ser
visualmente representado.

Documentação da API / guia / exemplo 1 e 2

O código C# para esta página / página XAML

TemplatedPage

TemplatedPage Exibe o conteúdo de tela inteira com um


modelo de controle, e é a classe base para ContentPage .

Documentação da API / guia

Links relacionados
Exemplo de xamarin. Forms FormsGallery
Amostras do Xamarin.Forms
Documentação da API do Xamarin.Forms
Layouts do xamarin. Forms
12/04/2019 • 5 minutes to read

baixar o exemplo
Layouts do xamarin. Forms são usados para compor controles de interface do usuário em estruturas de visual.
O Layout e Layout<T> classes no xamarin. Forms são subtipos especializados de exibições que atuam como
contêineres para outros layouts e exibições. O Layout deriva de classe em si View . Um Layout derivativo
normalmente contém lógica para definir a posição e tamanho dos elementos filho em aplicativos xamarin.
Forms.

As classes que derivam de Layout podem ser divididos em duas categorias:

Layouts com conteúdo simples


Essas classes derivam Layout , que define Padding e IsClippedToBounds propriedades.
ContentView

ContentView contém um único filho que é definido com o


Content propriedade. O Content propriedade pode ser
definida como qualquer View derivativo, incluindo outros
Layout derivados. ContentView é usado principalmente
como um elemento estrutural e serve como uma classe base
para Frame .

Documentação da API

O código C# para esta página / página XAML


Quadro

O Frame classe deriva ContentView e exibe um quadro


retangular ao redor de seu filho. Frame tem um padrão
Padding valor de 20 e também define OutlineColor ,
CornerRadius , e HasShadow propriedades.

Documentação da API

O código C# para esta página / página XAML

ScrollView

ScrollView é capaz de rolagem seu conteúdo. Defina as


Content propriedade para uma exibição ou layout muito
grande para caber na tela. (O conteúdo de um ScrollView
costuma ser muito uma StackLayout .) Defina as
Orientation propriedade para indicar se a rolagem deve
ser vertical, horizontal, ou ambos.

Documentação da API / guia / exemplo

O código C# para esta página / página XAML

TemplatedView

TemplatedView Exibe o conteúdo com um modelo de


controle, e é a classe base para ContentView .

Documentação da API / guia

ContentPresenter
ContentPresenter é um Gerenciador de layout para
exibições com modelo, usado em uma ControlTemplate
para marcar onde o conteúdo que deve ser apresentada
aparece.

Documentação da API / guia

Layouts com vários filhos


Essas classes derivam Layout<View> .
StackLayout

StackLayout Posiciona os elementos filho em uma pilha


horizontal ou verticalmente com base nas Orientation
propriedade. O Spacing propriedade rege o espaçamento
entre os filhos e tem um valor padrão de 6.

Documentação da API / guia / exemplo

O código C# para esta página / página XAML

Grade

Grid Posiciona a seus elementos filho em uma grade de


linhas e colunas. Posição de um filho é indicada usando o
propriedades anexadas Row , Column , RowSpan , e
ColumnSpan .

Documentação da API / guia / exemplo

O código C# para esta página / página XAML

AbsoluteLayout
AbsoluteLayout Posiciona os elementos filho em locais
específicos em relação ao seu pai. Posição de um filho é
indicada usando o propriedades anexadas LayoutBounds e
LayoutFlags . Um AbsoluteLayout é útil para animar as
posições dos modos de exibição.

Documentação da API / guia / exemplo

O código C# para esta página / página XAML com de lógica

RelativeLayout

RelativeLayout Posiciona os elementos filho relativo a


RelativeLayout em si ou para seus irmãos. Posição de um
filho é indicada usando o propriedades anexadas que são
definidas como objetos do tipo Constraint e
BoundsConstraint .

Documentação da API / guia / exemplo

O código C# para esta página / página XAML

FlexLayout

FlexLayout se baseia na folha de estilos módulo de Layout


de caixa flexível, comumente conhecido como flex layout ou
flex caixa. FlexLayout define seis propriedades vinculáveis
e cinco propriedades anexadas associáveis que permitem que
os filhos para ser empilhadas ou empacotado com muitas
opções de alinhamento e orientação.

Documentação da API / guia / exemplo

O código C# para esta página / página XAML

Links relacionados
Exemplo de xamarin. Forms FormsGallery
Amostras do Xamarin.Forms
Documentação da API do Xamarin.Forms
Modos de exibição do xamarin. Forms
16/04/2019 • 13 minutes to read

baixar o exemplo
Modos de exibição do xamarin. Forms são os blocos de construção de interfaces de usuário móvel de
plataforma cruzada.
Modos de exibição são objetos de interface do usuário, como rótulos, botões e controles deslizantes que são
normalmente conhecidos como controles ou widgets em outros ambientes de programação gráficas. As
exibições compatíveis com o xamarin. Forms todos derivam de View classe. Eles podem ser divididos em várias
categorias:

Modos de exibição para apresentação


Rotular

Label Exibe as cadeias de caracteres de texto de linha


única ou blocos de várias linhas de texto, com formatação
constante ou variável. Defina a Text propriedade como
uma cadeia de caracteres de constante de formatação, ou
um conjunto a FormattedText propriedade para um
FormattedString objeto variável formatação.

Documentação da API / guia / exemplo

O código C# para esta página / página XAML

Image

Image Exibe um bitmap. Bitmaps podem ser baixados pela


Web, inseridos como recursos no projeto comum ou
projetos de plataforma ou criado usando um .NET Stream
objeto.

Documentação da API / guia / exemplo

O código C# para esta página / página XAML

BoxView
BoxView Exibe um retângulo sólido colorido pela Color
propriedade. BoxView tem uma solicitação de tamanho
padrão de 40 x 40. Para outros tamanhos, atribuir a
WidthRequest e HeightRequest propriedades.

Documentação da API / guia / exemplo 1, 2, 3, 4 , 5, e 6

O código C# para esta página / página XAML

WebView

WebView Exibe o conteúdo, HTML ou páginas da Web com


base em se a Source estiver definida como um
UriWebViewSource ou um HtmlWebViewSource objeto.

Documentação da API / guia / exemplo 1 e 2

O código C# para esta página / página XAML

OpenGLView

OpenGLView exibe gráficos OpenGL em projetos do iOS e


Android. Não há nenhum suporte para a plataforma
Universal do Windows. Os projetos do iOS e Android exigem
uma referência para o OpenTK 1.0 assembly ou o OpenTK
assembly versão 1.0.0.0. OpenGLView é mais fácil de usar
em um projeto compartilhado; Se usado em uma biblioteca
.NET Standard, uma dependência de serviço também será
necessária (conforme mostrado no código de exemplo).

Esse é o recurso de apenas gráficos que é incorporado ao


xamarin. Forms, mas um aplicativo xamarin. Forms também
pode renderizar elementos gráficos usando CocosSharp ,
SkiaSharp , ou UrhoSharp . O código C# para esta página / página XAML com de lógica

Documentação da API

Mapa
Map Exibe um mapa. O Xamarin.Forms.Maps pacote do
Nuget deve ser instalado. Android e plataforma Universal do
Windows exigem uma chave de autorização do mapa.

Documentação da API / guia / exemplo

O código C# para esta página / página XAML

Modos de exibição que iniciam comandos


Botão

Button é um objeto retangular que exibe o texto, e que é


disparado um Clicked eventos quando ele é pressionado.

Documentação da API / guia / exemplo

O código C# para esta página / página XAML com de lógica

ImageButton

ImageButton é o objeto um retangular que exibe uma


imagem e que dispara um Clicked eventos quando ele é
pressionado.

Guia / exemplo

O código C# para esta página / página XAML com de lógica

SearchBar
SearchBar Exibe uma área para o usuário digite uma
cadeia de caracteres de texto e um botão (ou uma tecla do
teclado) que sinaliza o aplicativo para realizar uma pesquisa.
O Text propriedade fornece acesso ao texto e o
SearchButtonPressed evento indica que o botão foi
pressionado.

Documentação da API

O código C# para esta página / página XAML com de lógica

Modos de exibição para definir valores


Controle deslizante

Slider permite que o usuário selecione uma double


valor de um intervalo contínuo especificado com o
Minimum e Maximum propriedades.

Documentação da API / guia / exemplo

O código C# para esta página / página XAML

Escalonador

Stepper permite que o usuário selecione uma double


valor de um intervalo de valores incrementais especificado
com o Minimum , Maximum , e Increment propriedades.

Documentação da API / guia / exemplo

O código C# para esta página / página XAML

Alternar
Switch assume a forma de uma chave liga/desliga para
permitir que o usuário selecione um valor booliano. O
IsToggled propriedade é o estado do comutador e o
Toggled evento é acionado quando o estado é alterado.

Documentação da API

O código C# para esta página / página XAML

DatePicker

DatePicker permite que o usuário selecione uma data com


o seletor de datas da plataforma. Definir um intervalo de
datas permitidos com o MinimumDate e MaximumDate
propriedades. O Date propriedade é a data selecionada e o
DateSelected evento é disparado quando essa
propriedade é alterado.

Documentação da API / guia / exemplo

O código C# para esta página / página XAML

TimePicker

TimePicker permite que o usuário selecione uma hora


com o seletor de tempo de plataforma. O Time
propriedade é o tempo selecionado. Um aplicativo pode
monitorar as alterações na Time propriedade ao instalar
um manipulador para o PropertyChanged eventos.

Documentação da API / guia / exemplo

O código C# para esta página / página XAML

Modos de exibição de edição de texto


Essas duas classes derivam a InputView classe, que define os Keyboard propriedade.
Entrada
Entry permite ao usuário inserir e editar uma única linha
de texto. O texto está disponível como a Text propriedade
e o TextChanged e Completed os eventos são disparados
quando as alterações de texto ou o usuário sinaliza a
conclusão, tocando a tecla enter.

Use uma Editor para inserir e editar várias linhas de texto.

Documentação da API / guia / exemplo

O código C# para esta página / página XAML

Editor

Editor permite ao usuário inserir e editar várias linhas de


texto. O texto está disponível como a Text propriedade e o
TextChanged e Completed os eventos são disparados
quando as alterações de texto ou o usuário sinaliza a
conclusão.

Use uma Entry modo de exibição para inserir e editar uma


única linha de texto.

Documentação da API / guia / exemplo

O código C# para esta página / página XAML

Modos de exibição para indicar a atividade


ActivityIndicator

ActivityIndicator usa uma animação para mostrar que o


aplicativo está envolvido em uma atividade demorada sem
fornecer nenhuma indicação de progresso. O IsRunning
propriedade controla a animação.

Se o progresso da atividade for conhecido, use uma


ProgressBar em vez disso.

Documentação da API

O código C# para esta página / página XAML

ProgressBar
ProgressBar usa uma animação para mostrar que o
aplicativo está em andamento através de uma atividade
demorada. Defina as Progress propriedade para valores
entre 0 e 1 para indicar o progresso.

Se o progresso da atividade não for conhecido, use uma


ActivityIndicator em vez disso.

Documentação da API

O código C# para esta página / página XAML com de lógica

Exibições que mostram coleções


CollectionView

CollectionView Exibe uma lista rolável de itens


selecionáveis de dados, usando as especificações de layout
diferente. Tem como objetivo fornecer uma mais flexível e
alternativa de alto desempenho para o ListView . Definir a
ItemsSource propriedade a uma coleção de objetos e
defina o ItemTemplate propriedade para um
DataTemplate objeto que descreve como os itens devem
ser formatados. O SelectionChanged evento sinaliza que
uma seleção foi feita, que está disponível como a
SelectedItem propriedade.

Guia / exemplo
O código C# para esta página / página XAML

ListView

ListView deriva ItemsView e exibe


uma lista rolável de itens de dados
podem ser selecionados. Definir a
ItemsSource propriedade a uma
coleção de objetos e defina o
ItemTemplate propriedade para um
DataTemplate objeto que descreve
como os itens são a ser formatado. O
ItemSelected evento sinaliza que
uma seleção foi feita, que está
disponível como a SelectedItem
propriedade. O código C# para esta página / página
XAML
Documentação da API / guia /
exemplo

Seletor
Picker Exibe um item selecionado em uma lista de cadeias
de caracteres de texto e permite selecionar esse item quando
o modo de exibição é tocado. Defina a Items propriedade
a uma lista de cadeias de caracteres ou o ItemsSource
propriedade a uma coleção de objetos. O
SelectedIndexChanged evento é disparado quando um
item é selecionado.

O Picker exibe a lista de itens somente quando ele é


selecionado. Use uma ListView ou TableView para obter
uma lista rolável que permanece na página.

Documentação da API / guia / exemplo O código C# para esta página / página XAML com de lógica

Modo de tabela

TableView Exibe uma lista de linhas do tipo Cell com


cabeçalhos opcionais e subcabeçalhos. Defina as Root
propriedade para um objeto do tipo TableRoot e adicione
TableSection objetos para que TableRoot . Cada
TableSection é uma coleção de Cell objetos.

Documentação da API / guia / exemplo

O código C# para esta página / página XAML

Links relacionados
Exemplo de xamarin. Forms FormsGallery
Amostras do Xamarin.Forms
Documentação da API do Xamarin.Forms
Células do xamarin. Forms
12/04/2019 • 2 minutes to read

baixar o exemplo
As células do xamarin. Forms podem ser adicionadas a ListViews e TableViews.
Um célula é um elemento especializado usado para itens em uma tabela e descreve como cada item em uma lista
deve ser renderizado. O Cell classe deriva Element , do qual VisualElement também deriva. Uma célula não é
propriamente um elemento visual. em vez disso, ele é um modelo para a criação de um elemento visual.
Cell é usado exclusivamente com ListView e TableView controles. Para saber como usar e personalizar
células, consulte o ListView e TableView documentação.

Células
Xamarin. Forms dá suporte aos seguintes tipos de célula:
TextCell

Um TextCell exibe uma ou duas cadeias de caracteres de


texto. Defina as Text propriedade e, opcionalmente, o
Detail propriedade para essas cadeias de caracteres de
texto.

Documentação da API / guia

O código C# para esta página / página XAML

ImageCell

O ImageCell exibe as mesmas informações que TextCell


, mas inclui um bitmap que podem ser definidas com o
Source propriedade.

Documentação da API / guia

O código C# para esta página / página XAML


SwitchCell

O SwitchCell contém o texto definido com o Text '


propriedade e ativar/desativar opção inicialmente é definida
com o valor booliano On propriedade. Lidar com o
OnChanged evento a ser notificado quando o On alterações
de propriedade.

Documentação da API / guia

O código C# para esta página / página XAML

EntryCell

O EntryCell define um Label propriedade que identifica


a célula e uma única linha de texto editável no Text
propriedade. Lidar com o Completed evento a ser notificado
quando o usuário tiver concluído a entrada de texto.

Documentação da API / guia

O código C# para esta página / página XAML

Links relacionados
Exemplo de xamarin. Forms FormsGallery
Amostras do Xamarin.Forms
Documentação da API do Xamarin.Forms
Xamarin. Forms DataSourceControl
12/04/2019 • 3 minutes to read

IMPORTANT
DataSourceControl requer uma xamarin. Forms tema referência ao renderizar.

Xamarin. Forms DataSourceControl foram lançados no Evolve 2016 e estão disponível como uma visualização
para que os clientes experimentar e fornecer comentários.
DataSourceControl fornece uma API para rápida e facilmente vincular uma fonte de dados para exibições
predefinidas. Itens de lista e páginas de detalhes renderização automaticamente os dados e podem ser
personalizadas usando temas.
Para ver como funciona a palestra de demonstração evoluem, confira a guia de Introdução.

Introdução
Fontes de dados e as páginas de dados associadas permitem que os desenvolvedores rapidamente e facilmente
consumir uma fonte de dados com suporte e renderizá-lo usando interno que o scaffolding de interface do usuário
pode ser personalizado com temas.
DataSourceControl é adicionados a um aplicativo xamarin. Forms, incluindo o Xamarin.Forms.Pages pacote do
Nuget.
Data Sources
A visualização tem algumas fontes de dados predefinidos disponíveis para uso:
JsonDataSource
AzureDataSource (separe Nuget)
AzureEasyTableDataSource (separe Nuget)
Consulte a guia de Introdução para obter um exemplo usando um JsonDataSource .
Páginas e controles
As seguintes páginas e controles estão incluídos para permitir a fácil associação às fontes de dados fornecido:
ListDataPage – consulte a Introdução ao exemplo.
DirectoryPage – uma lista com o agrupamento habilitado.
PersonDetailPage – um modo de exibição personalizado para um tipo de objeto específico (uma entrada de
contato) de item de dados únicos.
DataView – um modo de exibição para expor os dados da origem de uma forma genérica.
Widgets CardView – um com o estilo de exibição que contém uma imagem, o texto do título e o texto de
descrição.
HeroImage – um modo de exibição de renderização de imagem.
ListItem – um pré-criados em modo de exibição com um layout semelhante ao iOS nativo e itens de lista para
Android.
Consulte a referência de controles DataSourceControl para obter exemplos.
Nos bastidores
Uma fonte de dados do xamarin. Forms segue o IDataSource interface.
A infraestrutura do xamarin. Forms interage com uma fonte de dados por meio das seguintes propriedades:
Data – uma lista somente leitura de itens de dados que podem ser exibidos.
IsLoading – um valor booliano que indica se os dados são carregados e estão disponíveis para renderização.
[key] – um indexador para recuperar elementos.

Há dois métodos MaskKey e UnmaskKey que pode ser usado para ocultar (ou Mostrar) propriedades do item de
dados (ie. impedi que está sendo processado). A chave corresponde à uma propriedade nomeada no objeto de
item de dados.
Guia de Introdução DataSourceControl
18/04/2019 • 7 minutes to read

baixar o exemplo

IMPORTANT
DataSourceControl requer uma xamarin. Forms tema referência ao renderizar.

Para começar a criação de uma página simple controlado por dados usando a visualização DataSourceControl,
siga as etapas abaixo. Este usa demonstração um estilo de embutidos em código ("eventos") na visualização
compilações que só funciona com o formato JSON específico no código.

1. Adicionar pacotes NuGet


Adicione esses pacotes do Nuget aos seus projetos de biblioteca e o aplicativo xamarin. Forms .NET Standard:
Xamarin.Forms.Pages
Xamarin.Forms.Theme.Base
Uma implementação de tema (por exemplo, o Nuget Xamarin.Forms.Theme.Light)
2. Adicionar referência de tema
No App. XAML do arquivo, adicione um personalizado xmlns:mytheme do tema e verifique se o tema é mesclado
no dicionário de recursos do aplicativo:

<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:mytheme="clr-namespace:Xamarin.Forms.Themes;assembly=Xamarin.Forms.Theme.Light"
x:Class="DataPagesDemo.App">
<Application.Resources>
<ResourceDictionary MergedWith="mytheme:LightThemeResources" />
</Application.Resources>
</Application>

IMPORTANTE: Você também deve seguir as etapas a serem carregar assemblies de tema (abaixo) adicionando
um código clichê para o iOS AppDelegate e Android MainActivity . Isso será melhorado em uma versão de
visualização futura.

3. Adicionar uma página XAML


Adicionar uma nova página XAML para o aplicativo xamarin. Forms, e alterar a classe base partir ContentPage
para Xamarin.Forms.Pages.ListDataPage . Isso deve ser feito no c# e o XAML:
Arquivo c#

public partial class SessionDataPage : Xamarin.Forms.Pages.ListDataPage // was ContentPage


{
public SessionDataPage ()
{
InitializeComponent ();
}
}

Arquivo XAML
Além de alterar o elemento raiz ser <p:ListDataPage> o espaço para nome personalizado xmlns:p também deve
ser adicionado:

<?xml version="1.0" encoding="UTF-8"?>


<p:ListDataPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:p="clr-namespace:Xamarin.Forms.Pages;assembly=Xamarin.Forms.Pages"
x:Class="DataPagesDemo.SessionDataPage">

<ContentPage.Content></ContentPage.Content>

</p:ListDataPage>

Subclasse de aplicativo
Alterar o App construtor de classe, de modo que o MainPage é definido como um NavigationPage que contém o
novo SessionDataPage . Uma página da navegação deve ser usado.

MainPage = new NavigationPage (new SessionDataPage ());

3. Adicionar a fonte de dados


Excluir o Content elemento e substituí-lo com um p:ListDataPage.DataSource para preencher a página com os
dados. No exemplo a seguir um Json remoto o arquivo de dados está sendo carregado de uma URL.
Observação: a versão prévia requer um StyleClass atributo para fornecer indícios de renderização para a fonte
de dados. O StyleClass="Events" refere-se a um layout que é predefinido na visualização e contém estilos
embutidos em código para corresponder à fonte de dados JSON que está sendo usada.

<?xml version="1.0" encoding="UTF-8"?>


<p:ListDataPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:p="clr-namespace:Xamarin.Forms.Pages;assembly=Xamarin.Forms.Pages"
x:Class="DataPagesDemo.SessionDataPage"
Title="Sessions" StyleClass="Events">

<p:ListDataPage.DataSource>
<p:JsonDataSource Source="http://demo3143189.mockable.io/sessions" />
</p:ListDataPage.DataSource>

</p:ListDataPage>

Dados JSON
Um exemplo dos dados JSON com o fonte de demonstração é mostrado abaixo:

[{
"end": "2016-04-27T18:00:00Z",
"start": "2016-04-27T17:15:00Z",
"abstract": "The new Apple TV has been released, and YOU can be one of the first developers to write apps
for it. To make things even better, you can build these apps in C#! This session will introduce the basics of
how to create a tvOS app with Xamarin, including: differences between tvOS and iOS APIs, TV user interface
best practices, responding to user input, as well as the capabilities and limitations of building apps for a
television. Grab some popcorn—this is going to be good!",
"title": "As Seen On TV … Bringing C# to the Living Room",
"presenter": "Matthew Soucoup",
"biography": "Matthew is a Xamarin MVP and Certified Xamarin Developer from Madison, WI. He founded his
company Code Mill Technologies and started the Madison Mobile .Net Developers Group. Matt regularly speaks
on .Net and Xamarin development at user groups, code camps and conferences throughout the Midwest. Matt
gardens hot peppers, rides bikes, and loves Wisconsin micro-brews and cheese.",
"image": "http://i.imgur.com/ASj60DP.jpg",
"avatar": "http://i.imgur.com/ASj60DP.jpg",
"room": "Crick"
}]

4. Executar!
As etapas acima devem resultar em uma página de dados de trabalho:
Isso funciona porque o estilo pré-criados "Eventos" existe no pacote Nuget de tema de luz e tem os estilos
definidos que correspondem à fonte de dados (por exemplo. "title", "imagem", "apresentador").
"Eventos" StyleClass é criado para exibir o ListDataPage controle com um personalizado CardView controle
que é definido em Xamarin.Forms.Pages. O CardView controle tem três propriedades: ImageSource , Text , e
Detail . O tema está codificado para associar três campos os dados da fonte (do arquivo JSON ) para essas
propriedades para exibição.

5. Personalizar
O estilo herdado pode ser substituído especificando um modelo e usando associações de código-fonte de dados.
O XAML a seguir declara um modelo personalizado para cada linha usando o novo ListItemControl e
{p:DataSourceBinding} sintaxe que está incluído na Xamarin.Forms.Pages Nuget:

<p:ListDataPage.DefaultItemTemplate>
<DataTemplate>
<ViewCell>
<p:ListItemControl
Title="{p:DataSourceBinding title}"
Detail="{p:DataSourceBinding room}"
ImageSource="{p:DataSourceBinding image}"
DataSource="{Binding Value}"
HeightRequest="90"
>
</p:ListItemControl>
</ViewCell>
</DataTemplate>
</p:ListDataPage.DefaultItemTemplate>

Fornecendo uma DataTemplate esse código substitui o StyleClass e, em vez disso, usa o layout padrão para um
ListItemControl .
Os desenvolvedores que preferem o c# para o XAML pode criar dados de associações de origem muito (Lembre-
se de incluir um using Xamarin.Forms.Pages; instrução):

SetBinding (TitleProperty, new DataSourceBinding ("title"));

É um pouco mais trabalho para criar temas do zero (consulte a guia de temas), mas versões prévias futuras
tornará isso mais fácil de fazer.

Solução de problemas
Não foi possível carregar arquivo ou assembly
'Xamarin.Forms.Theme.Light' ou uma de suas dependências
Na versão de visualização, temas podem não ser capazes de carregar no tempo de execução. Adicione o código
mostrado abaixo nos projetos relevantes para corrigir esse erro.
iOS
No AppDelegate.cs adicione as seguintes linhas depois de LoadApplication

var x = typeof(Xamarin.Forms.Themes.DarkThemeResources);
x = typeof(Xamarin.Forms.Themes.LightThemeResources);
x = typeof(Xamarin.Forms.Themes.iOS.UnderlineEffect);

Android
No MainActivity.cs adicione as seguintes linhas depois de LoadApplication
var x = typeof(Xamarin.Forms.Themes.DarkThemeResources);
x = typeof(Xamarin.Forms.Themes.LightThemeResources);
x = typeof(Xamarin.Forms.Themes.Android.UnderlineEffect);

Links relacionados
Exemplo de DataPagesDemo
Referência de controles DataSourceControl
12/04/2019 • 7 minutes to read

IMPORTANT
DataSourceControl requer uma xamarin. Forms tema referência ao renderizar.

O xamarin. Forms DataSourceControl Nuget inclui uma série de controles que podem tirar proveito da ligação de
fonte de dados.
Para usar esses controles no XAML, verifique se o namespace foi incluído, por exemplo consulte o xmlns:pages
declaração abaixo:

<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:pages="clr-namespace:Xamarin.Forms.Pages;assembly=Xamarin.Forms.Pages"
x:Class="DataPagesDemo.Detail">

Os exemplos a seguir incluem DynamicResource referências que seriam preciso existir no dicionário de recursos do
projeto para trabalhar. Também é um exemplo de como criar um controle personalizado

Controles internos
HeroImage
ListItem
HeroImage
O HeroImage controle tem quatro propriedades:
Texto
Detalhe
ImageSource
Aspecto

<pages:HeroImage
ImageSource="{ DynamicResource HeroImageImage }"
Text="Keith Ballinger"
Detail="Xamarin"
/>

Android
iOS

ListItem
O ListItem o layout do controle é semelhante ao nativos de iOS e Android lista ou tabela de linhas, no entanto
ele também pode ser usado como um modo de exibição normal. No exemplo de código abaixo dele é mostrado
hospedado dentro de um StackLayout , mas também pode ser usado em controles de lista associado a dados
scolling.
Há cinco propriedades:
Título
Detalhe
ImageSource
PlaceholdImageSource
Aspecto

<StackLayout Spacing="0">
<pages:ListItemControl
Detail="Xamarin"
ImageSource="{ DynamicResource UserImage }"
Title="Miguel de Icaza"
PlaceholdImageSource="{ DynamicResource IconImage }"
/>

Essas capturas de tela mostram o ListItem em plataformas iOS e Android usando tanto a luz e escuridão temas:
Android

iOS

Exemplo de controle personalizado


O objetivo nesse personalizado CardView controle deve se parecer com os widgets CardView de Android nativo.
Ele contém três propriedades:
Texto
Detalhe
ImageSource
A meta é um controle personalizado que se parecerá com o código a seguir (Observe que um personalizado
xmlns:local é necessário que faz referência ao assembly atual):

<local:CardView
ImageSource="{ DynamicResource CardViewImage }"
Text="CardView Text"
Detail="CardView Detail"
/>

Deve se parecer com as capturas de tela abaixo usando cores correspondente a temas claro e escuro internos:
Android

iOS

Criando o widgets CardView personalizado


1. Subclasse de DataView
2. Definir a fonte, Layout e margens
3. Criar estilos para os filhos do controle
4. Criar o modelo de Layout de controle
5. Adicione os recursos específicos do tema
6. Defina o ControlTemplate para a classe de widgets CardView
7. Adicionar o controle a uma página
1. Subclasse de DataView
A subclasse c# de DataView define as propriedades vinculáveis para o controle.
public class CardView : DataView
{
public static readonly BindableProperty TextProperty =
BindableProperty.Create ("Text", typeof (string), typeof (CardView), null, BindingMode.TwoWay);

public string Text


{
get { return (string)GetValue (TextProperty); }
set { SetValue (TextProperty, value); }
}

public static readonly BindableProperty DetailProperty =


BindableProperty.Create ("Detail", typeof (string), typeof (CardView), null, BindingMode.TwoWay);

public string Detail


{
get { return (string)GetValue (DetailProperty); }
set { SetValue (DetailProperty, value); }
}

public static readonly BindableProperty ImageSourceProperty =


BindableProperty.Create ("ImageSource", typeof (ImageSource), typeof (CardView), null,
BindingMode.TwoWay);

public ImageSource ImageSource


{
get { return (ImageSource)GetValue (ImageSourceProperty); }
set { SetValue (ImageSourceProperty, value); }
}

public CardView()
{
}
}

2. Definir a fonte, Layout e margens


O designer de controle seria descobrir esses valores como parte do design de interface do usuário para o controle
personalizado. Em que as especificações de específico da plataforma são necessárias, o OnPlatform elemento é
usado.
Observe que alguns valores referem-se StaticResource s – eles serão definidos em etapa 5.
<!-- CARDVIEW FONT SIZES -->
<OnPlatform x:TypeArguments="x:Double" x:Key="CardViewTextFontSize">
<On Platform="iOS, Android" Value="15" />
</OnPlatform>

<OnPlatform x:TypeArguments="x:Double" x:Key="CardViewDetailFontSize">


<On Platform="iOS, Android" Value="13" />
</OnPlatform>

<OnPlatform x:TypeArguments="Color" x:Key="CardViewTextTextColor">


<On Platform="iOS" Value="{StaticResource iOSCardViewTextTextColor}" />
<On Platform="Android" Value="{StaticResource AndroidCardViewTextTextColor}" />
</OnPlatform>

<OnPlatform x:TypeArguments="Thickness" x:Key="CardViewTextlMargin">


<On Platform="iOS" Value="12,10,12,4" />
<On Platform="Android" Value="20,0,20,5" />
</OnPlatform>

<OnPlatform x:TypeArguments="Color" x:Key="CardViewDetailTextColor">


<On Platform="iOS" Value="{StaticResource iOSCardViewDetailTextColor}" />
<On Platform="Android" Value="{StaticResource AndroidCardViewDetailTextColor}" />
</OnPlatform>

<OnPlatform x:TypeArguments="Thickness" x:Key="CardViewDetailMargin">


<On Platform="iOS" Value="12,0,10,12" />
<On Platform="Android" Value="20,0,20,20" />
</OnPlatform>

<OnPlatform x:TypeArguments="Color" x:Key="CardViewBackgroundColor">


<On Platform="iOS" Value="{StaticResource iOSCardViewBackgroundColor}" />
<On Platform="Android" Value="{StaticResource AndroidCardViewBackgroundColor}" />
</OnPlatform>

<OnPlatform x:TypeArguments="x:Double" x:Key="CardViewShadowSize">


<On Platform="iOS" Value="2" />
<On Platform="Android" Value="5" />
</OnPlatform>

<OnPlatform x:TypeArguments="x:Double" x:Key="CardViewCornerRadius">


<On Platform="iOS" Value="0" />
<On Platform="Android" Value="4" />
</OnPlatform>

<OnPlatform x:TypeArguments="Color" x:Key="CardViewShadowColor">


<On Platform="iOS, Android" Value="#CDCDD1" />
</OnPlatform>

3. Criar estilos para os filhos do controle


Fazer referência a todos os elementos definidos prestes a criar os filhos que serão usados no controle
personalizado:
<!-- EXPLICIT STYLES (will be Classes) -->
<Style TargetType="Label" x:Key="CardViewTextStyle">
<Setter Property="FontSize" Value="{ StaticResource CardViewTextFontSize }" />
<Setter Property="TextColor" Value="{ StaticResource CardViewTextTextColor }" />
<Setter Property="HorizontalOptions" Value="Start" />
<Setter Property="Margin" Value="{ StaticResource CardViewTextlMargin }" />
<Setter Property="HorizontalTextAlignment" Value="Start" />
</Style>

<Style TargetType="Label" x:Key="CardViewDetailStyle">


<Setter Property="HorizontalTextAlignment" Value="Start" />
<Setter Property="TextColor" Value="{ StaticResource CardViewDetailTextColor }" />
<Setter Property="FontSize" Value="{ StaticResource CardViewDetailFontSize }" />
<Setter Property="HorizontalOptions" Value="Start" />
<Setter Property="Margin" Value="{ StaticResource CardViewDetailMargin }" />
</Style>

<Style TargetType="Image" x:Key="CardViewImageImageStyle">


<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="VerticalOptions" Value="Center" />
<Setter Property="WidthRequest" Value="220"/>
<Setter Property="HeightRequest" Value="165"/>
</Style>

4. Criar o modelo de Layout de controle


O design visual do controle personalizado for explicitamente declarado no modelo de controle, usando os recursos
definidos acima:

<!--- CARDVIEW -->


<ControlTemplate x:Key="CardViewControlControlTemplate">
<StackLayout
Spacing="0"
BackgroundColor="{ TemplateBinding BackgroundColor }"
>

<!-- CARDVIEW IMAGE -->


<Image
Source="{ TemplateBinding ImageSource }"
HorizontalOptions="FillAndExpand"
VerticalOptions="StartAndExpand"
Aspect="AspectFill"
Style="{ StaticResource CardViewImageImageStyle }"
/>

<!-- CARDVIEW TEXT -->


<Label
Text="{ TemplateBinding Text }"
LineBreakMode="WordWrap"
VerticalOptions="End"
Style="{ StaticResource CardViewTextStyle }"
/>

<!-- CARDVIEW DETAIL -->


<Label
Text="{ TemplateBinding Detail }"
LineBreakMode="WordWrap"
VerticalOptions="End"
Style="{ StaticResource CardViewDetailStyle }" />

</StackLayout>

</ControlTemplate>
5. Adicione os recursos específicos do tema
Como esse é um controle personalizado, adicione os recursos que correspondem o tema que você estiver usando
o dicionário de recursos:
Co r es de t em a c l ar o

<Color x:Key="iOSCardViewBackgroundColor">#FFFFFF</Color>
<Color x:Key="AndroidCardViewBackgroundColor">#FFFFFF</Color>

<Color x:Key="AndroidCardViewTextTextColor">#030303</Color>
<Color x:Key="iOSCardViewTextTextColor">#030303</Color>

<Color x:Key="AndroidCardViewDetailTextColor">#8F8E94</Color>
<Color x:Key="iOSCardViewDetailTextColor">#8F8E94</Color>

C o r e s d e t e m a e sc u r o

<!-- CARD VIEW COLORS -->


<Color x:Key="iOSCardViewBackgroundColor">#404040</Color>
<Color x:Key="AndroidCardViewBackgroundColor">#404040</Color>

<Color x:Key="AndroidCardViewTextTextColor">#FFFFFF</Color>
<Color x:Key="iOSCardViewTextTextColor">#FFFFFF</Color>

<Color x:Key="AndroidCardViewDetailTextColor">#B5B4B9</Color>
<Color x:Key="iOSCardViewDetailTextColor">#B5B4B9</Color>

6. Defina o ControlTemplate para a classe de widgets CardView


Por fim, verifique se a classe c# criada no etapa 1 usa o modelo de controle definido no etapa 4 usando um Style
Setter elemento

<Style TargetType="local:CardView">
<Setter Property="ControlTemplate" Value="{ StaticResource CardViewControlControlTemplate }" />
... some custom styling omitted
<Setter Property="BackgroundColor" Value="{ StaticResource CardViewBackgroundColor }" />
</Style>

7. Adicionar o controle a uma página


O CardView controle agora pode ser adicionado a uma página. O exemplo a seguir mostra que ele hospedado em
um StackLayout :

<StackLayout Spacing="0">
<local:CardView
Margin="12,6"
ImageSource="{ DynamicResource CardViewImage }"
Text="CardView Text"
Detail="CardView Detail"
/>
</StackLayout>
DatePicker do xamarin. Forms
12/04/2019 • 9 minutes to read

baixar o exemplo
Uma exibição do xamarin. Forms que permite que o usuário selecione uma data.
O xamarin. Forms DatePicker invoca o controle de seletor de data da plataforma e permite que o usuário
selecione uma data. DatePicker define oito propriedades:
MinimumDate do tipo DateTime , cujo padrão é o primeiro dia do ano de 1900.
MaximumDate do tipo DateTime , qual o padrão é o último dia do ano 2100.
Date do tipo DateTime , a data selecionada, cujo padrão é o valor DateTime.Today .
Format do tipo string , um padrão ou personalizado .NET formatação de cadeia de caracteres, que assume
como padrão "D", de longa data padrão.
TextColor do tipo Color , a cor usada para exibir a data selecionada, cujo padrão é Color.Default .
FontAttributes do tipo FontAttributes , cujo padrão é FontAtributes.None .
FontFamily do tipo string , cujo padrão é null .
FontSize do tipo double , cujo padrão é de -1,0.

O DatePicker dispara uma DateSelected evento quando o usuário seleciona uma data.

WARNING
Ao definir MinimumDate e MaximumDate , verifique se MinimumDate sempre é menor que ou igual a MaximumDate . Caso
contrário, DatePicker gerarão uma exceção.

Internamente, o DatePicker garante que Date entre MinimumDate e MaximumDate , inclusive. Se MinimumDate ou
MaximumDate é definido para que Date não está entre eles, DatePicker ajustará o valor de Date .

Todos os oito propriedades têm o respaldo BindableProperty objetos, o que significa que eles podem ser
estilizados e as propriedades podem ser alvos de vinculações de dados. O Date propriedade tem um modo de
associação padrão de BindingMode.TwoWay , que significa que ele pode ser um destino de associação de dados em
um aplicativo que usa o Model-View -ViewModel (MVVM ) arquitetura.

Inicializando as propriedades de data e hora


No código, você pode inicializar o MinimumDate , MaximumDate ,e Date propriedades para valores do tipo
DateTime :

DatePicker datePicker = new DatePicker


{
MinimumDate = new DateTime(2018, 1, 1),
MaximumDate = new DateTime(2018, 12, 31),
Date = new DateTime(2018, 6, 21)
};

Quando um valor é especificado no XAML, o analisador XAML usa a DateTime.Parse método com um
DateTime
CultureInfo.InvariantCulture argumento para converter a cadeia de caracteres para um DateTime valor. As datas
devem ser especificadas em um formato exato: dois dígitos meses, dias de dois dígitos e anos de quatro dígitos
separados por barras "/":

<DatePicker MinimumDate="01/01/2018"
MaximumDate="12/31/2018"
Date="06/21/2018" />

Se o BindingContext propriedade de DatePicker é definido como uma instância de um ViewModel que contém
as propriedades do tipo DateTime denominada MinDate , MaxDate , e SelectedDate (por exemplo), você pode
instanciar o DatePicker semelhante a esta :

<DatePicker MinimumDate="{Binding MinDate}"


MaximumDate="{Binding MaxDate}"
Date="{Binding SelectedDate}" />

Neste exemplo, todas as três propriedades são inicializadas para as propriedades correspondentes no ViewModel.
Porque o Date propriedade tem um modo de associação de TwoWay , qualquer nova data em que o usuário
selecionar é refletida automaticamente no ViewModel.
Se o DatePicker não contém uma associação em seu Date propriedade, um aplicativo deve anexar um
manipulador para o DateSelected evento a ser informado quando o usuário seleciona uma nova data.
Para obter informações sobre como definir propriedades de fonte, consulte fontes.

Layout e DatePicker
É possível usar uma opção de layout horizontal irrestrito, como Center , Start , ou End com DatePicker :

<DatePicker ···
HorizontalOptions="Center"
··· />

No entanto, isso não é recomendado. Dependendo da configuração de Format propriedade, selecionada datas
podem exigir que as larguras de exibição diferentes. Por exemplo, faz com que a cadeia de caracteres de formato
"D" DateTime exibir datas em um formato longo e "Quarta-feira, 12 de setembro de 2018" requer uma largura de
exibição maior que "Sexta-feira, 4 de maio de 2018". Dependendo da plataforma, essa diferença pode causar a
DateTime exibição para alterar a largura de layout, ou para a exibição a ser truncado.

TIP
É melhor usar o padrão HorizontalOptions configuração do Fill com DatePicker e não deve usar uma largura de
Auto ao colocar DatePicker em um Grid célula.

Selecionador de data em um aplicativo


O DaysBetweenDates exemplo inclui dois DatePicker exibições em sua página. Eles podem ser usados para
selecionar as duas datas, e o programa calcula o número de dias entre essas datas. O programa não altera as
configurações do MinimumDate e MaximumDate propriedades, portanto, as duas datas devem estar entre 1900 e
2100.
Aqui está o arquivo XAML:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DaysBetweenDates"
x:Class="DaysBetweenDates.MainPage">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="0, 20, 0, 0" />
</OnPlatform>
</ContentPage.Padding>

<StackLayout Margin="10">
<Label Text="Days Between Dates"
Style="{DynamicResource TitleStyle}"
Margin="0, 20"
HorizontalTextAlignment="Center" />

<Label Text="Start Date:" />

<DatePicker x:Name="startDatePicker"
Format="D"
Margin="30, 0, 0, 30"
DateSelected="OnDateSelected" />

<Label Text="End Date:" />

<DatePicker x:Name="endDatePicker"
MinimumDate="{Binding Source={x:Reference startDatePicker},
Path=Date}"
Format="D"
Margin="30, 0, 0, 30"
DateSelected="OnDateSelected" />

<StackLayout Orientation="Horizontal"
Margin="0, 0, 0, 30">
<Label Text="Include both days in total: "
VerticalOptions="Center" />
<Switch x:Name="includeSwitch"
Toggled="OnSwitchToggled" />
</StackLayout>

<Label x:Name="resultLabel"
FontAttributes="Bold"
HorizontalTextAlignment="Center" />

</StackLayout>
</ContentPage>

Cada DatePicker é atribuído um Format propriedade de "D" para um formato de data por extenso. Observe
também que o endDatePicker objeto possui uma associação que tem como alvo seus MinimumDate propriedade.
A origem da associação é selecionado Date propriedade do startDatePicker objeto. Isso garante que a data de
término é sempre posterior ou igual à data de início. Além dos dois DatePicker objetos, um Switch é rotulado
como "Incluir ambos os dias no total".
Os dois DatePicker modos de exibição têm manipuladores anexados para o DateSelected evento e o Switch
tem um manipulador anexado seu Toggled eventos. Esses manipuladores de eventos estão no arquivo code-
behind e disparam um novo cálculo dos dias entre as duas datas:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}

void OnDateSelected(object sender, DateChangedEventArgs args)


{
Recalculate();
}

void OnSwitchToggled(object sender, ToggledEventArgs args)


{
Recalculate();
}

void Recalculate()
{
TimeSpan timeSpan = endDatePicker.Date - startDatePicker.Date +
(includeSwitch.IsToggled ? TimeSpan.FromDays(1) : TimeSpan.Zero);

resultLabel.Text = String.Format("{0} day{1} between dates",


timeSpan.Days, timeSpan.Days == 1 ? "" : "s");
}
}

Quando o exemplo é primeiro executado, ambos DatePicker modos de exibição são inicializados a data de hoje.
Captura de tela a seguir mostra o programa em execução no iOS, Android e plataforma Universal do Windows:

Tocando em qualquer uma da DatePicker exibe invoca o selecionador de data de plataforma. As plataformas de
implementam esse seletor de data em duas maneiras diferentes, mas cada abordagem é familiar aos usuários da
plataforma:
TIP
No Android, o DatePicker caixa de diálogo pode ser personalizada substituindo o CreateDatePickerDialog método em
um renderizador personalizado. Isso permite, por exemplo, botões adicionais a serem adicionados à caixa de diálogo.

Depois de duas datas forem selecionadas, o aplicativo exibe o número de dias entre essas datas:

Links relacionados
Exemplo de DaysBetweenDates
API de DatePicker
Elementos gráficos de SkiaSharp em Xamarin.Forms
12/04/2019 • 5 minutes to read

baixar o exemplo
Usar SkiaSharp para gráficos 2D em seus aplicativos xamarin. Forms
SkiaSharp é um sistema de gráficos em 2D para .NET e c# com o engine gráficos Skia de código-fonte aberto que
é amplamente usado em produtos do Google. Você pode usar SkiaSharp em seus aplicativos xamarin. Forms para
desenhar o texto, bitmaps e gráficos vetoriais 2D. Consulte a desenho 2D guia para obter mais informações gerais
sobre a biblioteca de SkiaSharp e alguns outros tutoriais.
Este guia pressupõe que você esteja familiarizado com a programação do xamarin. Forms.

Webinar: SkiaSharp para xamarin. Forms

Etapas preliminares de SkiaSharp


SkiaSharp para xamarin. Forms é empacotado como um pacote do NuGet. Depois de criar uma solução xamarin.
Forms no Visual Studio ou Visual Studio para Mac, você pode usar o Gerenciador de pacotes do NuGet para
pesquisar o SkiaSharp.Views.Forms empacotar e adicioná-lo à sua solução. Se você marcar a referências seção
de cada projeto após a adição de SkiaSharp, você pode ver que várias SkiaSharp bibliotecas foram adicionadas
para cada um dos projetos na solução.
Se seu aplicativo xamarin. Forms tem como alvo iOS, use a página de propriedades do projeto para alterar o
destino de implantação mínimo para o iOS 8.0.
Em qualquer página do c# que usa SkiaSharp você desejará incluir uma using diretriz para a SkiaSharp
namespace, que abrange todos os de SkiaSharp classes, estruturas e enumerações que você usará em seus
elementos gráficos a programação. Você também pode uma using diretriz para a SkiaSharp.Views.Forms
namespace para as classes específicas para xamarin. Forms. Isso é um quantidade menor espaço para nome, com a
classe mais importantes sendo SKCanvasView . Essa classe deriva o xamarin. Forms View de classe e hospeda sua
saída de gráficos de SkiaSharp.

IMPORTANT
O SkiaSharp.Views.Forms namespace também contém um SKGLView classe que deriva de View mas utiliza o OpenGL
para renderização de gráficos. Para fins de simplicidade, este guia restringe-se ao SKCanvasView , mas o uso SKGLView em
vez disso, é bastante semelhante.

Noções básicas de desenho do SkiaSharp


Algumas das estimativas de gráficos mais simples, que você pode desenhar com SkiaSharp são retângulos, elipses
e círculos. Exibir esses números, você aprenderá sobre as coordenadas de SkiaSharp, tamanhos e cores. A exibição
de texto e bitmaps é mais complexa, mas esses artigos também introduzem essas técnicas.

Caminhos e linhas de SkiaSharp


Um caminho gráfico é uma série de linhas retas conectadas e curvas. Caminhos podem tracejados, preenchidos, ou
ambos. Este artigo abrange muitos aspectos do desenho de linha, incluindo o traço extremidades e uniões e
tracejada e as linhas pontilhadas, mas parar com pouca geometrias de curva.

Transformações de SkiaSharp
As transformações permitem que os objetos gráficos ser uniformemente traduzido, dimensionado, girados ou
inclinados. Este artigo também mostra como você pode usar uma matriz de transformação de 3 por 3 padrão para
criar transformações não afins e aplicar transformações aos caminhos.

Curvas e caminhos de SkiaSharp


A exploração dos caminhos continua com adicionando curvas a um objeto de caminho e explorar outros recursos
avançados de caminho. Você verá como você pode especificar um caminho inteiro em uma cadeia de caracteres de
texto conciso, como usar efeitos de caminho e como se aprofundar em elementos internos do caminho.

Bitmaps do SkiaSharp
Os bitmaps são matrizes retangulares de bits que correspondem aos pixels de um dispositivo de vídeo. Esta série
de artigos mostra como carregar, salvar, exibir, criar, desenhar em, animar e acessar os bits de SkiaSharp bitmaps.

Efeitos de SkiaSharp
Os efeitos são propriedades que alteram a exibição normal de elementos gráficos, incluindo gradientes linear e
circulares, lado a lado de bitmap, misturar modos de desfoque e outras pessoas.

Links relacionados
APIs de SkiaSharp
SkiaSharpFormsDemos (amostra)
SkiaSharp com xamarin. Forms Webinar (vídeo)
Imagens no xamarin. Forms
12/04/2019 • 23 minutes to read

baixar o exemplo
Imagens podem ser compartilhadas entre plataformas com o xamarin. Forms, podem ser carregados
especificamente para cada plataforma ou podem ser baixados para exibição.
Imagens são uma parte crucial da navegação do aplicativo, a usabilidade e a identidade visual. Aplicativos
xamarin. Forms precisam ser capaz de compartilhar imagens entre todas as plataformas, mas também pode
exibir imagens diferentes em cada plataforma.
Imagens específicas da plataforma também são necessárias para os ícones e telas de abertura; eles precisam ser
configurados em uma base por plataforma.

Exibindo imagens
Xamarin. Forms usa o Image modo de exibição para exibir imagens em uma página. Ele tem duas propriedades
importantes:
Source -An ImageSource instância, arquivo, Uri ou recurso, que define a imagem a ser exibida.
Aspect -Como dimensionar a imagem dentro dos limites que está sendo exibido dentro de (seja para
stretch, cortar ou letterbox).
ImageSource instâncias podem ser obtidas usando métodos estáticos para cada tipo de origem da imagem:
FromFile -Requer um nome de arquivo ou caminho do arquivo que pode ser resolvido em cada plataforma.
FromUri -Requer um objeto de Uri, por exemplo. new Uri("http://server.com/image.jpg") .
FromResource -Requer um identificador de recurso para um arquivo de imagem inserido no aplicativo ou
projeto de biblioteca .NET Standard, com um ação de Build: EmbeddedResource.
FromStream -Requer um fluxo que fornece dados de imagem.

O Aspect propriedade determina como a imagem será dimensionada para caber na área de exibição:
Fill -Alonga a imagem para a área de exibição de preencher completamente e exatamente. Isso pode
resultar na imagem que está sendo distorcida.
AspectFill -Recorta a imagem de modo que ele preencha a área de exibição, preservando o aspecto (ie.
nenhuma distorção).
AspectFit -E Letterbox a imagem (se necessário) para que a imagem inteira se adapta a área de exibição,
com espaço em branco adicionado para o de cima para baixo ou os lados, dependendo se a imagem é altas
ou largas.
Imagens podem ser carregadas de um arquivo local, um recurso incorporado, ou baixado. Além disso, os ícones
de fonte podem ser exibidos pela Image exibição, especificando os dados do ícone de fonte em um
FontImageSource objeto. Para obter mais informações, consulte exibir ícones de fonte na fontes guia.

Imagens locais
Arquivos de imagem podem ser adicionados a cada projeto de aplicativo e referenciados no código do xamarin.
Forms compartilhado. Esse método de distribuição de imagens é necessário quando as imagens são específicas
da plataforma, como ao usar resoluções diferentes em diferentes plataformas ou designs ligeiramente
diferentes.
Para usar uma única imagem em todos os aplicativos, o mesmo nome de arquivo deve ser usado em todas as
plataformas, e ele deve ser um nome de recurso válido do Android (ie. são permitidos apenas letras minúsculas,
números, sublinhado e o período de).
iOS – o preferencial a maneira de gerenciar e dar suporte a imagens desde que o iOS 9 é usar conjuntos de
imagem do catálogo de ativos, que deve conter todas as versões de uma imagem que são necessárias
para dar suporte a vários dispositivos e fatores de escala um aplicativo. Para obter mais informações,
consulte adicionar imagens a um conjunto de imagem de catálogo ativo.
Android -colocar imagens em de recursos/drawable diretório com ação de compilação:
AndroidResource. Versões de DPI alto e baixo de uma imagem também podem ser fornecidas
(adequadamente chamado recursos subdiretórios, como desenháveis ldpi, drawable-hdpie desenháveis
xhdpi).
Plataforma universal do Windows (UWP ) -Insira imagens no diretório de raiz do aplicativo com ação de
compilação: Content.

IMPORTANT
Antes do iOS 9, imagens normalmente foram colocadas na recursos pasta com ação de compilação: BundleResource.
No entanto, esse método de trabalhar com imagens em um aplicativo iOS foi substituído pela Apple. Para obter mais
informações, consulte tamanhos de imagem e nomes de arquivo.

Aderir a essas regras de nomenclatura de arquivo e o posicionamento permite que o XAML a seguir carregar e
exibir a imagem em todas as plataformas:

<Image Source="waterfront.jpg" />

O equivalente a C# código é o seguinte:

var image = new Image { Source = "waterfront.jpg" };

As capturas de tela a seguir mostram o resultado de exibição de uma imagem local em cada plataforma:

Para obter mais flexibilidade a Device.RuntimePlatform propriedade pode ser usada para selecionar um arquivo
de imagem diferente ou o caminho para algumas ou todas as plataformas, conforme mostrado neste exemplo
de código:
image.Source = Device.RuntimePlatform == Device.Android ? ImageSource.FromFile("waterfront.jpg") :
ImageSource.FromFile("Images/waterfront.jpg");

IMPORTANT
Para usar o mesmo nome de arquivo de imagem em todas as plataformas, o nome deve ser válido em todas as
plataformas. Desenháveis Android têm restrições de nomenclatura – são permitidos apenas letras minúsculas, números,
sublinhado e período – e para compatibilidade de plataforma cruzada isso deve ser seguido em todas as outras
plataformas também. O nome do arquivo de exemplo waterfront.png segue as regras, mas os exemplos de nomes de
arquivo inválidos incluem "água front.png", "WaterFront.png", "água front.png" e "wåterfront.png".

Resoluções nativas (Retina e com alto DPI )


iOS, Android e UWP incluem suporte para resoluções de imagem diferente, em que o sistema operacional
escolherá a imagem apropriada em tempo de execução com base nos recursos do dispositivo. Xamarin. Forms
usa APIs de plataformas nativas para carregar imagens locais, portanto, ele automaticamente dá suporte a
resoluções alternativas se os arquivos corretamente são chamados e localizados no projeto.
A maneira preferencial para gerenciar imagens, pois o iOS 9 é arrastar imagens para cada resolução necessária
para o conjunto de imagens do catálogo de ativos apropriado. Para obter mais informações, consulte adicionar
imagens a um conjunto de imagem de catálogo ativo.
Antes do iOS 9, versões de retina da imagem pode ser colocadas na recursos pasta - dois e três vezes a
resolução com um @2x ou @3xsufixos de nome de arquivo antes da extensão de arquivo (por exemplo.
myimage@2x.png). No entanto, esse método de trabalhar com imagens em um aplicativo iOS foi substituído
pela Apple. Para obter mais informações, consulte tamanhos de imagem e nomes de arquivo.
Imagens de resolução alternativo Android devem ser colocadas em diretórios especialmente denominada no
projeto do Android, conforme mostrado na seguinte captura de tela:

Nomes de arquivo de imagem UWP pode ser com o sufixo .scale-xxx antes da extensão de arquivo, onde
xxx é a porcentagem de dimensionamento aplicado ao ativo, por exemplo, myimage.scale 200.png. Imagens,
em seguida, podem ser chamadas para no código ou XAML sem o modificador de escala, por exemplo, apenas
myimage.png. A plataforma selecionará a escala mais próxima do ativo apropriado com base em DPI de atual
da tela.
Controles adicionais que exibem imagens
Alguns controles têm propriedades que exibem uma imagem, como:
Page -Qualquer tipo que deriva de página Page tem Icon e BackgroundImage propriedades, que podem
ser atribuídas a uma referência de arquivo local. Em determinadas circunstâncias, como quando um
NavigationPage está exibindo um ContentPage , o ícone será exibido se houver suporte pela plataforma.

IMPORTANT
No iOS, o Page.Icon não é possível popular a propriedade de uma imagem em um conjunto de imagens de
catálogo ativo. Em vez disso, carregar imagens de ícone para o Page.Icon propriedade a partir de recursos
pasta no projeto do iOS.

ToolbarItem – Tem um Icon propriedade que pode ser definida como uma referência de arquivo local.
ImageCell– Tem um ImageSource recuperados de propriedade que pode ser definida como uma
imagem de um arquivo local, um recurso inserido ou um URI.

Imagens inseridas
Imagens inseridas também são fornecidas com um aplicativo (como imagens locais), mas em vez de ter uma
cópia da imagem na estrutura de arquivos de cada aplicativo a imagem do arquivo é inserido no assembly como
um recurso. Esse método de distribuição de imagens é recomendado quando imagens idênticas são usadas em
cada plataforma e é especialmente adequado para a criação de componentes, como a imagem é fornecida com
o código.
Para inserir uma imagem em um projeto, clique com botão direito para adicionar novos itens e selecione a
imagem/s que você deseja adicionar. Por padrão a imagem terá ação de compilação: None; isso deve ser
definido como ação de compilação: EmbeddedResource.
Visual Studio
Visual Studio para Mac
O ação de compilação podem ser exibidos e alterados na propriedades janela para um arquivo.
Neste exemplo é a ID de recurso WorkingWithImages.beach.jpg. O IDE gerou esse padrão por meio da
concatenação de Namespace padrão para este projeto com o nome do arquivo, usando um ponto (.) entre
cada valor.
Se você colocar imagens inseridas em pastas dentro de seu projeto, os nomes das pastas também são
separados por pontos (.) na ID do recurso. Movendo o beach.jpg imagem em uma pasta chamada MyImages
resultaria em uma ID de recurso de WorkingWithImages.MyImages.beach.jpg
O código para carregar uma imagem inserida simplesmente passa o ID do recurso para o
ImageSource.FromResource método conforme mostrado abaixo:

var embeddedImage = new Image { Source = ImageSource.FromResource("WorkingWithImages.beach.jpg",


typeof(EmbeddedImages).GetTypeInfo().Assembly) };

NOTE
Para dar suporte à exibição de imagens inseridas no modo de versão na plataforma Universal do Windows, é necessário
usar a sobrecarga do ImageSource.FromResource que especifica o assembly de origem no qual pesquisar a imagem.

Atualmente não há nenhuma conversão implícita para identificadores de recurso. Em vez disso, você deve usar
ImageSource.FromResource ou new ResourceImageSource() para carregar imagens inseridas.
As capturas de tela a seguir mostram o resultado de exibição de uma imagem inserida em cada plataforma:

Usando XAML
Porque não há nenhum conversor de tipo interno do string para ResourceImageSource , esses tipos de imagens
de modo nativo não podem ser carregados pelo XAML. Em vez disso, uma extensão de marcação XAML
personalizada simple pode ser escrita para carregar imagens usando um ID do recurso especificado no XAML:

[ContentProperty (nameof(Source))]
public class ImageResourceExtension : IMarkupExtension
{
public string Source { get; set; }

public object ProvideValue (IServiceProvider serviceProvider)


{
if (Source == null)
{
return null;
}

// Do your translation lookup here, using whatever method you require


var imageSource = ImageSource.FromResource(Source,
typeof(ImageResourceExtension).GetTypeInfo().Assembly);

return imageSource;
}
}

NOTE
Para dar suporte à exibição de imagens inseridas no modo de versão na plataforma Universal do Windows, é necessário
usar a sobrecarga do ImageSource.FromResource que especifica o assembly de origem no qual pesquisar a imagem.

Para usar essa extensão de adicionar personalizado xmlns para XAML, usando os valores corretos de
namespace e assembly para o projeto. A origem da imagem, em seguida, pode ser definida usando esta sintaxe:
{local:ImageResource WorkingWithImages.beach.jpg} . Um exemplo XAML completo é mostrado abaixo:
<?xml version="1.0" encoding="UTF-8" ?>
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:WorkingWithImages;assembly=WorkingWithImages"
x:Class="WorkingWithImages.EmbeddedImagesXaml">
<StackLayout VerticalOptions="Center" HorizontalOptions="Center">
<!-- use a custom Markup Extension -->
<Image Source="{local:ImageResource WorkingWithImages.beach.jpg}" />
</StackLayout>
</ContentPage>

Imagens inseridas de solução de problemas


Depurando código
Porque, às vezes, é difícil entender por que um recurso de imagem em particular não está sendo carregado, o
seguinte código de depuração pode ser adicionado temporariamente a um aplicativo para ajudar a confirmar
que os recursos estão configurados corretamente. Ele terá como saída conhecidos todos os recursos
incorporados no assembly fornecido para o Console para ajudar a depurar problemas de carregamento de
recursos.

using System.Reflection;
// ...
// NOTE: use for debugging, not in released app code!
var assembly = typeof(EmbeddedImages).GetTypeInfo().Assembly;
foreach (var res in assembly.GetManifestResourceNames())
{
System.Diagnostics.Debug.WriteLine("found resource: " + res);
}

Imagens inseridas em outros projetos


Por padrão, o ImageSource.FromResource método procura apenas imagens no mesmo assembly que o código
chamar o ImageSource.FromResource método. Usando o código de depuração acima, você pode determinar quais
assemblies contêm um recurso específico, alterando a typeof() instrução para um Type conhecido para estar
em cada assembly.
No entanto, o assembly de origem que está sendo pesquisado para uma imagem inserida pode ser especificado
como um argumento para o ImageSource.FromResource método:

var imageSource = ImageSource.FromResource("filename.png", typeof(MyClass).GetTypeInfo().Assembly);

Download de imagens
Imagens podem ser baixadas automaticamente para a exibição, como mostra o XAML a seguir:

<?xml version="1.0" encoding="utf-8" ?>


<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="WorkingWithImages.DownloadImagesXaml">
<StackLayout VerticalOptions="Center" HorizontalOptions="Center">
<Label Text="Image UriSource Xaml" />
<Image Source="https://xamarin.com/content/images/pages/forms/example-app.png" />
<Label Text="example-app.png gets downloaded from xamarin.com" />
</StackLayout>
</ContentPage>

O equivalente a C# código é o seguinte:


var webImage = new Image { Source = ImageSource.FromUri(new
Uri("https://xamarin.com/content/images/pages/forms/example-app.png")) };

O ImageSource.FromUri método exige um Uri do objeto e retorna um novo UriImageSource que lê do Uri .
Também há uma conversão implícita de cadeias de caracteres do URI, portanto, o exemplo a seguir também
funcionará:

webImage.Source = "https://xamarin.com/content/images/pages/forms/example-app.png";

As capturas de tela a seguir mostram o resultado de exibição de uma imagem remota em cada plataforma:

Cache de imagem baixada


Um UriImageSource também dá suporte ao cache de imagens baixadas, configuradas por meio das seguintes
propriedades:
CachingEnabled – Se o cache está habilitado ( true por padrão).
CacheValidity -A TimeSpan que define por quanto tempo a imagem será armazenada localmente.

Armazenamento em cache é habilitado por padrão e armazenará a imagem localmente para 24 horas. Para
desabilitar o cache de uma imagem específica, instanciar a origem da imagem da seguinte maneira:

image.Source = new UriImageSource { CachingEnabled = false, Uri="http://server.com/image" };

Para definir um período de cache específica (por exemplo, 5 dias) instanciar a origem da imagem da seguinte
maneira:

webImage.Source = new UriImageSource


{
Uri = new Uri("https://xamarin.com/content/images/pages/forms/example-app.png"),
CachingEnabled = true,
CacheValidity = new TimeSpan(5,0,0,0)
};

Armazenamento em cache interno facilita muito dar suporte a cenários, como listas de imagens, onde você
pode definir (ou associar) uma imagem de rolagem em cada célula e permitir que o cache interno cuidar de
carregar novamente a imagem quando a célula é rolada novamente no modo de exibição.

Ícones e telas de abertura


Enquanto não relacionados para o Image exibição, os ícones de aplicativo e telas de abertura também são um
importante uso das imagens em projetos do xamarin. Forms.
Configurando ícones e telas de abertura para aplicativos xamarin. Forms é feita em cada um dos projetos de
aplicativo. Isso significa que gerar corretamente dimensionada de imagens para iOS, Android e UWP. Essas
imagens devem ser nomeadas e localizadas de acordo com os requisitos de cada das plataformas.

Ícones
Consulte a iOS trabalhando com imagens, Google iconografia, e diretrizes para ativos de bloco e ícone para
obter mais informações sobre como criar esses recursos de aplicativo.
Além disso, os ícones de fonte podem ser exibidos pela Image exibição, especificando os dados do ícone de
fonte em um FontImageSource objeto. Para obter mais informações, consulte exibir ícones de fonte na fontes
guia.

Telas de abertura
Somente aplicativos iOS e UWP exigem uma tela inicial (também chamada de uma imagem de tela ou padrão
de inicialização).
Consulte a documentação para iOS trabalhando com imagens e telas de abertura no Centro de
desenvolvimento do Windows.

Resumo
Xamarin. Forms oferece um número de diferentes maneiras de incluir imagens em um aplicativo de plataforma
cruzada, permitindo que para a mesma imagem a ser usado em plataformas ou para imagens específicas da
plataforma seja especificado. Imagens baixadas são automaticamente armazenadas em cache, automatizando
um cenário comum de codificação.
Imagens de tela de abertura e de ícone de aplicativo são a configuração e configurado como para aplicativos
não xamarin. Forms - sigam as mesmas orientações usada para aplicativos específicos da plataforma.

Links relacionados
WorkingWithImages (amostra)
iOS trabalhando com imagens
Iconografia Android
Diretrizes para ativos de bloco e ícone
Xamarin. Forms ImageButton
12/04/2019 • 11 minutes to read

baixar o exemplo
O ImageButton exibe uma imagem e responde a um toque ou clique que direciona um aplicativo para executar
uma tarefa específica.
O ImageButton exibir combina o Button modo de exibição e Image modo de exibição para criar um botão cujo
conteúdo é uma imagem. O usuário pressiona o ImageButton com um dedo ou clica nele com o mouse para
direcionar o aplicativo para executar uma tarefa específica. No entanto, ao contrário do Button modo de exibição,
o ImageButton exibição não tem nenhum conceito de texto e a aparência do texto.

NOTE
Enquanto o Button view define uma Image propriedade, que lhe permite exibir uma imagem no Button , esta
propriedade destina-se a ser usado ao exibir um ícone pequeno ao lado de Button texto.

Os exemplos de código neste guia são tirados de FormsGallery exemplo.

Definir a origem da imagem


ImageButton define um Source propriedade que deve ser definida como a imagem para exibir no botão com a
origem da imagem que está sendo um arquivo, um URI, um recurso ou um fluxo. Para obter mais informações
sobre como carregar imagens de origens diferentes, consulte imagens no xamarin. Forms.
O exemplo a seguir mostra como instanciar um ImageButton no XAML:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="FormsGallery.XamlExamples.ImageButtonDemoPage"
Title="ImageButton Demo">
<StackLayout>
<Label Text="ImageButton"
FontSize="50"
FontAttributes="Bold"
HorizontalOptions="Center" />

<ImageButton Source="XamarinLogo.png"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>

O Source propriedade especifica a imagem que aparece no ImageButton . Neste exemplo, ele é definido como um
arquivo local que será carregado a partir de cada projeto da plataforma, resultando em capturas de tela as seguir:
Por padrão, o ImageButton é retangular, mas você pode atribuir os cantos arredondado de it, usando o
CornerRadius propriedade. Para obter mais informações sobre ImageButton aparência, consulte ImageButton
aparência.
O exemplo a seguir mostra como criar uma página que é funcionalmente equivalente ao exemplo XAML anterior,
mas inteiramente no C#:

public class ImageButtonDemoPage : ContentPage


{
public ImageButtonDemoPage()
{
Label header = new Label
{
Text = "ImageButton",
FontSize = 50,
FontAttributes = FontAttributes.Bold,
HorizontalOptions = LayoutOptions.Center
};

ImageButton imageButton = new ImageButton


{
Source = "XamarinLogo.png",
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.CenterAndExpand
};

// Build the page.


Title = "ImageButton Demo";
Content = new StackLayout
{
Children = { header, imageButton }
};
}
}

Tratamento ImageButton clica


ImageButton define uma Clicked evento que é acionado quando o usuário toca o ImageButton com um ponteiro
de mouse ou o dedo. O evento é acionado quando o botão de dedo ou o mouse é liberado da superfície do
ImageButton . O ImageButton deve ter seu IsEnabled propriedade definida como true para responder aos
toques.
O exemplo a seguir mostra como instanciar uma ImageButton em XAML e o identificador da sua Clicked
eventos:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="FormsGallery.XamlExamples.ImageButtonDemoPage"
Title="ImageButton Demo">
<StackLayout>
<Label Text="ImageButton"
FontSize="50"
FontAttributes="Bold"
HorizontalOptions="Center" />

<ImageButton Source="XamarinLogo.png"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Clicked="OnImageButtonClicked" />

<Label x:Name="label"
Text="0 ImageButton clicks"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>

O Clicked evento é definido como um manipulador de eventos chamado OnImageButtonClicked que está
localizado no arquivo code-behind:

public partial class ImageButtonDemoPage : ContentPage


{
int clickTotal;

public ImageButtonDemoPage()
{
InitializeComponent();
}

void OnImageButtonClicked(object sender, EventArgs e)


{
clickTotal += 1;
label.Text = $"{clickTotal} ImageButton click{(clickTotal == 1 ? "" : "s")}";
}
}

Quando o ImageButton é tocado, o OnImageButtonClicked método é executado. O sender argumento é o


ImageButton responsável por esse evento. Você pode usar isso para acessar o ImageButton objeto, ou para
distinguir entre vários ImageButton objetos que compartilham o mesmo Clicked eventos.
Essa determinada Clicked manipulador incrementa um contador e exibe o valor do contador em um Label :
O exemplo a seguir mostra como criar uma página que é funcionalmente equivalente ao exemplo XAML anterior,
mas inteiramente no C#:
public class ImageButtonDemoPage : ContentPage
{
Label label;
int clickTotal = 0;

public ImageButtonDemoPage()
{
Label header = new Label
{
Text = "ImageButton",
FontSize = 50,
FontAttributes = FontAttributes.Bold,
HorizontalOptions = LayoutOptions.Center
};

ImageButton imageButton = new ImageButton


{
Source = "XamarinLogo.png",
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.CenterAndExpand
};
imageButton.Clicked += OnImageButtonClicked;

label = new Label


{
Text = "0 ImageButton clicks",
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.CenterAndExpand
};

// Build the page.


Title = "ImageButton Demo";
Content = new StackLayout
{
Children =
{
header,
imageButton,
label
}
};
}

void OnImageButtonClicked(object sender, EventArgs e)


{
clickTotal += 1;
label.Text = $"{clickTotal} ImageButton click{(clickTotal == 1 ? "" : "s")}";
}
}

Desabilitando o ImageButton
Às vezes, um aplicativo está em um estado específico em que um determinado ImageButton clique não é uma
operação válida. Nesses casos, o ImageButton deve ser desabilitado definindo seu IsEnabled propriedade false .

Usando a interface de comando


É possível que um aplicativo para responder às ImageButton toques sem tratamento a Clicked eventos. O
ImageButton implementa um mecanismo de notificação alternativo chamado a comando ou comandando
interface. Isso consiste em duas propriedades:
Command do tipo ICommand , uma interface definida a System.Windows.Input namespace.
CommandParameter propriedade do tipo Object .
Essa abordagem é adequada em conexão com a vinculação de dados e especialmente quando a implementação
da arquitetura do Model-View -ViewModel (MVVM ).
Para obter mais informações sobre como usar a interface de comando, consulte usando a interface de comando
na botão guia.

Pressionando e soltando o ImageButton


Além de Clicked evento ImageButton também define Pressed e Released eventos. O Pressed evento ocorre
quando um dedo pressiona em um ImageButton , ou um botão do mouse é pressionado com o ponteiro
posicionado sobre o ImageButton . O Released evento ocorre quando o botão de dedo ou o mouse é liberado. Em
geral, o Clicked evento também é acionado ao mesmo tempo que o Released evento, mas se o ponteiro do
mouse ou o dedo desliza para fora a superfície do ImageButton antes de serem liberadas, o Clicked não pode
ocorrer um evento.
Para obter mais informações sobre esses eventos, consulte pressionando e soltando o botão na botão guia.

Aparência ImageButton
Além das propriedades que ImageButton herda a View classe, ImageButton também define várias propriedades
que afetam sua aparência:
Aspect é como a imagem será dimensionada para caber na área de exibição.
BorderColor é a cor de uma área ao redor de ImageButton .
BorderWidth é a largura da borda.
CornerRadius é o raio do canto do ImageButton .

O Aspect propriedade pode ser definida para um dos membros de Aspect enumeração:
Fill -Alonga a imagem para preencher completamente e exatamente o ImageButton . Isso pode resultar na
imagem que está sendo distorcida.
AspectFill -Corta a imagem de modo que ele preencha o ImageButton , preservando a taxa de proporção.
AspectFit -e Letterbox a imagem (se necessário) para que a imagem inteira se adapta a ImageButton , com
espaço em branco adicionado para o de cima para baixo ou lados dependendo se a imagem é altas ou largas.
Isso é o valor padrão de Aspect enumeração.

NOTE
O ImageButton classe também tem Margin e Padding as propriedades que controlam o comportamento de layout a
ImageButton . Para obter mais informações, consulte margem e preenchimento.

Estados visuais ImageButton


ImageButton tem um Pressed VisualState que pode ser usado para iniciar uma alteração visual para o
ImageButton quando pressionado pelo usuário, desde que ele está habilitado.
O exemplo XAML a seguir mostra como definir um estado visual para o Pressed estado:
<ImageButton Source="XamarinLogo.png"
...>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="Scale"
Value="1" />
</VisualState.Setters>
</VisualState>

<VisualState x:Name="Pressed">
<VisualState.Setters>
<Setter Property="Scale"
Value="0.8" />
</VisualState.Setters>
</VisualState>

</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</ImageButton>

O Pressed VisualState Especifica que, quando o ImageButton é pressionado, seu Scale propriedade será
alterada do valor padrão de 1 para 0,8. O Normal VisualState Especifica que, quando o ImageButton está em um
estado normal, seu Scale propriedade será definida como 1. Portanto, o efeito geral é que quando o
ImageButton é pressionado, ele será escalada novamente para ser um pouco menores e quando o ImageButton é
lançado, ele será escalada novamente ao seu tamanho padrão.
Para obter mais informações sobre estados visuais, consulte o Gerenciador de estado Visual xamarin. Forms.

Links relacionados
Exemplo de FormsGallery
Layouts no Xamarin.Forms
12/04/2019 • 16 minutes to read

baixar o exemplo
Xamarin.Forms tem vários layouts e recursos para organizar o conteúdo na tela.

Layouts do Xamarin.Forms, por Xamarin University


Cada controle de layout é descrito abaixo, bem como detalhes sobre como lidar com alterações de orientação de
tela:
StackLayout – usada para organizar exibições linearmente, horizontal ou verticalmente. Modos de exibição
em um StackLayout podem ser alinhados ao centro, esquerda ou direita do layout.
AbsoluteLayout – usada para organizar os modos de exibição, definindo as coordenadas & tamanho em
termos de valores absolutos ou taxas. AbsoluteLayout pode ser usado para a camada de modos de exibição,
bem como ancorá-los para a esquerda, direita ou centralizado.
RelativeLayout – usada para organizar os modos de exibição, definindo as restrições em relação a dimensões
e a posição de seu pai.
Grade – usada para organizar exibições em uma grade. Linhas e colunas podem ser especificadas em termos
de valores absolutos ou taxas.
FlexLayout – usada para organizar os modos de exibição horizontal ou verticalmente com quebra automática.
ScrollView – usada para fornecer a rolagem quando uma exibição pode não caber completamente dentro dos
limites da tela.
LayoutOptions – definir o alinhamento e expansão para uma exibição, relativo ao seu pai.
Entrada de transparência – Especifica se um elemento recebe entrada.
Margem e preenchimento – demonstra como controlar o comportamento de layout quando um elemento é
renderizado na interface do usuário.
Orientação do dispositivo – explica como manipular as alterações de orientação do dispositivo.
Layout em dispositivos tablet e área de trabalho – mostra como otimizar para telas maiores em cada
plataforma.
Layouts associáveis – habilitar as classes de layout gerar seu conteúdo por associação a uma coleção de itens.
Criar um Layout personalizado – explica como criar uma classe de layout personalizado.
Compactação de layout – remove especificado o layout da árvore visual em uma tentativa de melhorar o
desempenho de renderização da página.
Controles de plataforma também podem ser usados diretamente no Xamarin.Forms layouts com incorporação
nativa (novo no Xamarin.Forms 2.2), e você pode criar layouts personalizados para atender às necessidades
específicas.
O gráfico a seguir visualiza os controles de layout:
Escolher o Layout Certo
Os layouts que você escolher para seu aplicativo podem ajudar ou prejudicar como você está criando um
aplicativo Xamarin.Forms atraente e utilizável. Dedicar algum tempo para considerar como funciona cada layout
pode ajudá-lo a escrever código de interface do usuário mais limpo e escalonável. Uma tela pode ter uma
combinação de layouts diferentes para alcançar um design específico.
StackLayout
O StackLayout é usado para exibir os modos de exibição ao longo de uma linha horizontal ou vertical. Posição e
tamanho do layout são determinados com base em um modo de exibição HeightRequest , WidthRequest ,
HorizontalOptions e VerticalOptions . StackLayout geralmente é usado como o layout de base, organizando
outros layouts na tela.
Para obter um exemplo de quando o StackLayout seria uma boa opção, considere um aplicativo que precisa para
exibir um botão e um rótulo, com o rótulo alinhado à esquerda e o botão alinhado à direita.

<StackLayout Orientation="Horizontal">
<Label HorizontalOptions="StartAndExpand" Text="Label" />
<Button HorizontalOptions="End" Text="Button" />
</StackLayout>

FlexLayout
O FlexLayout é semelhante ao StackLayout em que ele exibe os modos de exibição filho horizontal ou
verticalmente:

<FlexLayout Direction="Column"
AlignItems="Center"
JustifyContent="SpaceEvenly">

<Label Text="FlexLayout in Action" />


<Button Text="Button" />
<Label Text="Another Label" />
</FlexLayout>

No entanto, se houver muitos filhos para caber em uma única linha ou coluna, FlexLayout também é capaz de
encapsular essas exibições. FlexLayout se baseia no módulo de Layout de caixa flexível CSS e tem muitas das
mesmas opções internas para posicionar e alinhar seus filhos.
AbsoluteLayout
O AbsoluteLayout é usado para exibir os modos de exibição, com tamanho e posição que está sendo especificado
como valores explícitos ou relativo ao tamanho do layout. Diferentemente StackLayout e Grid , AbsoluteLayout
permite que o filho exibições se sobrepõem. Diferentemente RelativeLayout , AbsoluteLayout não permite que
você colocar elementos fora da tela.
Para obter um exemplo de quando AbsoluteLayout seria uma boa opção, considere um aplicativo que precisa para
apresentar as coleções de objetos como pilhas. Isso é geralmente visto ao apresentar álbuns de fotos ou músicas.
O código a seguir fornece a aparência de uma pilha, com elementos girados para dica sobre o conteúdo da pilha:
No XAML:

<AbsoluteLayout Padding="15">
<Image AbsoluteLayout.LayoutFlags="PositionProportional" AbsoluteLayout.LayoutBounds="0.5, 0, 100, 100"
Rotation="30"
Source="bottom.png" />
<Image AbsoluteLayout.LayoutFlags="PositionProportional" AbsoluteLayout.LayoutBounds="0.5, 0, 100, 100"
Rotation="60"
Source="middle.png" />
<Image AbsoluteLayout.LayoutFlags="PositionProportional" AbsoluteLayout.LayoutBounds="0.5, 0, 100, 100"
Source="cover.png" />
</AbsoluteLayout>

Observe os seguintes aspectos de código acima:


Cada Image é exibida na mesma posição (no meio do espaço horizontal)
O Padding será considerado pelo AbsoluteLayout , ao contrário RelativeLayout , que vão ignorá-la.
AbsoluteLayout.LayoutFlags Especifica como os limites de layout serão interpretados. Nesse caso,
PositionProportional , significa que as coordenadas será uma proporção do tamanho do layout, enquanto o
tamanho será interpretado como um tamanho de explícito.
AbsoluteLayout.Layoutbounds Especifica a posição horizontal, vertical posição, largura e altura nessa ordem.

RelativeLayout
O RelativeLayout é usado para exibir os modos de exibição, com tamanho e posição especificada como valores
relativos aos valores de layout ou de outro modo de exibição. Não é necessário correspondê-lo corresponde o
valor no modo de exibição relacionado valores relativos. Por exemplo, é possível definir um modo de exibição
Width propriedade seja proporcional para outra exibição X propriedade.

RelativeLayout pode ser usado para criar interfaces do usuário que são dimensionados proporcionalmente de
tamanhos de dispositivo. O XAML a seguir implementa um design com as caixas nos cantos mais altas, com um
flagpole com sinalizador no Centro de:

<RelativeLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">


<BoxView Color="Blue" HeightRequest="50" WidthRequest="50"
RelativeLayout.XConstraint= "{ConstraintExpression Type=RelativeToParent, Property=Width, Factor = 0}"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor = 0}" />
<BoxView Color="Red" HeightRequest="50" WidthRequest="50"
RelativeLayout.XConstraint= "{ConstraintExpression Type=RelativeToParent, Property=Width, Factor = .9}"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor = 0}" />
<BoxView Color="Gray" WidthRequest="15" x:Name="pole"
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height,
Factor=.75}"
RelativeLayout.XConstraint= "{ConstraintExpression Type=RelativeToParent, Property=Width, Factor = .45}"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor = .25}"
/>
<BoxView Color="Green"
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=.10,
Constant=10}"
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent,Property=Width, Factor=.2,
Constant=20}"
RelativeLayout.XConstraint= "{ConstraintExpression Type=RelativeToView, ElementName=pole, Property=X,
Constant=15}"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToView, ElementName=pole, Property=Y,
Constant=0}" />
</RelativeLayout>

Observe os seguintes aspectos de código acima:


Tamanhos e posições são especificados como restrições.
O flagpole é chamado para que o sinalizador (verde da caixa) posição pode ser definida em relação a flagpole.
As expressões de restrição tem Factor e Constant propriedades, que podem ser usadas para definir os
tamanhos e posições como múltiplos (ou frações) das propriedades de outros objetos, além de uma constante.
Constantes podem ser negativos.
Grade
O Grid é usado para exibir elementos em linhas e colunas. Observe que a grade não é uma tabela, para que ele
não tem o conceito de células, linhas de cabeçalho e rodapé ou bordas entre linhas e colunas. Em geral, a grade
não é adequado para exibir dados tabulares. Para esse uso, considere uma ListView ou modo de tabela.
Para obter um exemplo de quando um Grid é o layout da direita para usar, considere uma entrada numérica para
uma calculadora. Uma entrada numérica para uma calculadora pode consistir em quatro linhas e três colunas,
cada um com um botão. O código a seguir implementa esse design:

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>

<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Text="1" Grid.Row="0" Grid.Column="0" />
<Button Text="2" Grid.Row="0" Grid.Column="1" />
<Button Text="3" Grid.Row="0" Grid.Column="2" />
<Button Text="4" Grid.Row="1" Grid.Column="0" />
<Button Text="5" Grid.Row="1" Grid.Column="1" />
<Button Text="6" Grid.Row="1" Grid.Column="2" />
<Button Text="7" Grid.Row="2" Grid.Column="0" />
<Button Text="8" Grid.Row="2" Grid.Column="1" />
<Button Text="9" Grid.Row="2" Grid.Column="2" />
<Button Text="0" Grid.Row="3" Grid.Column="1" />
<Button Text="&lt;-" Grid.Row="3" Grid.Column="2" />
</Grid>

Observe os seguintes aspectos de código acima:


Grades e colunas são especificadas explicitamente, não é inferido do conteúdo.
Height e Width valores podem ser definidos como estrelas, o que significa que a grade definirá esses valores
para preencher o espaço disponível.
Posição de cada botão é especificada por Grid.Row & Grid.Column propriedades.
LayoutOptions
O LayoutOptions estrutura pode ser usada para definir o alinhamento e expansão para uma exibição, relativo ao
seu pai.
Margem e preenchimento
O Margin e Padding propriedades controlam o comportamento de layout quando um elemento é renderizado na
interface do usuário.
Entrada de transparência
Cada elemento tem um InputTransparent propriedade que é usada para definir se o elemento recebe entrada.
Seu valor padrão é false , garantindo que o elemento recebe entrada.
Quando essa propriedade é definida em uma classe de contêiner, como uma classe de layout, as transferências de
seu valor para os elementos filho. Portanto, definir a InputTransparent propriedade true em um layout de classe
resultará em elementos do layout do não recebendo entrada.
Orientação do dispositivo
Xamarin. Forms e seus layouts internos são capazes de lidar com alterações na orientação do dispositivo.
Considere quais orientações seu aplicativo dará suporte, bem como você fará uso de espaço fornecido nos modos
retrato e paisagem.
Layout para aplicativos de Tablet e área de trabalho
iOS, Android e plataforma Universal do Windows todas as maiores tamanhos de tela de suporte em dispositivos
do tablet (bem como laptops e desktops para Windows). Xamarin. Forms permite que você otimize seu aplicativo
para telas maiores, como detectar o tipo de dispositivo e a ajustar o layout de página ou usando uma página
totalmente diferente completamente para telas maiores.
Layouts associáveis
O BindableLayout classe permite que qualquer classe de layout que deriva de Layout<T> classe para gerar seu
conteúdo por associação a uma coleção de itens, com a opção de definir a aparência de cada item com um
DataTemplate .

Criar um layout personalizado


Xamarin. Forms define quatro classes de layout - StackLayout , AbsoluteLayout , RelativeLayout , e Grid , e cada
organiza seus filhos de uma maneira diferente. No entanto, às vezes, seu necessário para organizar o conteúdo da
página usando um layout não fornecidos pelo xamarin. Forms. Este artigo explica como escrever uma classe de
layout personalizado e demonstra uma orientação diferencia WrapLayout classe que organiza seus filhos
horizontalmente pela página e, em seguida, ajusta a exibição dos filhos subsequentes em linhas adicionais.
Compactação de Layout
Compactação de layout remove os layouts especificados da árvore visual em uma tentativa de melhorar o
desempenho de renderização da página. O benefício de desempenho que isso oferece varia dependendo da
complexidade de uma página, da versão do sistema operacional que está sendo usado e do dispositivo no qual o
aplicativo está sendo executado. No entanto, os maiores ganhos de desempenho serão observados em versões
mais antigas.

Fazendo sua escolha


Lembre-se de que na maioria dos casos, mais de uma opção de layout pode ser usada para implementar o design
desejado. Quando há várias opções válidas, considere a abordagem que será a maneira mais fácil para a sua
situação. A maioria dos projetos não podem ser realizados com apenas um layout, portanto nest layouts como
necessário para criar designs mais complexos.

Links relacionados
Diretrizes de Interface humana da Apple
Site de Design do Android
Layout (amostra)
Exemplo de BusinessTumble (amostra)
StackLayout do xamarin. Forms
12/04/2019 • 7 minutes to read

baixar o exemplo
StackLayout Organiza os modos de exibição em uma linha unidimensional ("pilha"), horizontal ou verticalmente.
Exibições em um StackLayout pode ser dimensionado com base no espaço no layout usando as opções de
layout. Posicionamento é determinada pela ordem de modos de exibição foram adicionados para o layout e as
opções de layout dos modos de exibição.

Finalidade
StackLayout é menos complexo do que outros modos de exibição. Interfaces de lineares simples podem ser
criadas simplesmente adicionando modos de exibição para um StackLayout e mais complexas interfaces criadas,
aninhando-los.

Uso e comportamento
Espaçamento
Por padrão, StackLayout será adicionada uma margem de 6px entre modos de exibição. Isso pode ser controlado
ou definido como não ter nenhuma margem, definindo o Spacing propriedade StackLayout. O exemplo a seguir
demonstra como definir o espaçamento e o efeito de opções de espaçamento diferentes:
No XAML:

<?xml version="1.0" encoding="UTF-8"?>


<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="LayoutSamples.StackLayoutDemo"
Title="StackLayout Demo">
<ContentPage.Content>
<StackLayout Spacing="10" x:Name="layout">
<Button Text="StackLayout" VerticalOptions="Start"
HorizontalOptions="FillAndExpand" />
<BoxView Color="Yellow" VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand" />
<BoxView Color="Green" VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand" />
<BoxView HeightRequest="75" Color="Blue" VerticalOptions="End"
HorizontalOptions="FillAndExpand" />
</StackLayout>
</ContentPage.Content>
</ContentPage>

No C#:
public class StackLayoutCode : ContentPage
{
public StackLayoutCode ()
{
var layout = new StackLayout ();
var button = new Button { Text = "StackLayout", VerticalOptions = LayoutOptions.Start,
HorizontalOptions = LayoutOptions.FillAndExpand };
var yellowBox = new BoxView { Color = Color.Yellow, VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand };
var greenBox = new BoxView { Color = Color.Green, VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand };
var blueBox = new BoxView { Color = Color.Blue, VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand, HeightRequest = 75 };

layout.Children.Add(button);
layout.Children.Add(yellowBox);
layout.Children.Add(greenBox);
layout.Children.Add(blueBox);
layout.Spacing = 10;
Content = layout;
}
}

Espaçamento = 0:

Espaçamento de dez:
Dimensionamento
O tamanho de uma exibição em um StackLayout depende das solicitações de altura e largura e as opções de
layout. StackLayout irá impor o preenchimento. O seguinte LayoutOption s fará com que os modos de exibição
ocupar o espaço disponível do layout:
CenterAndExpand – centraliza a exibição no layout e expande para ocupar tanto espaço quanto o layout será
dê a ele.
EndAndExpand – coloca o modo de exibição no final do layout (inferior ou limite à direita) e se expande para
ocupar tanto espaço quanto o layout será dê a ele.
FillAndExpand – coloca o modo de exibição para que ele não tem nenhum preenchimento e ocupa espaço
quanto o layout será dê a ele.
StartAndExpand – coloca o modo de exibição no início do layout e ocupa tanto espaço quanto fornecerá o
pai.
Para obter mais informações, consulte expansão.
Posicionamento
Modos de exibição em um StackLayout podem ser posicionados e dimensionados usando LayoutOptions . Cada
modo de exibição pode ser dada VerticalOptions e HorizontalOptions , definindo como os modos de exibição irá
se posicionar em relação ao layout. O seguinte predefinidos LayoutOptions estão disponíveis:
Centro – centraliza a exibição no layout.
Término – coloca o modo de exibição no final do layout (inferior ou limite à direita).
Preencher – coloca o modo de exibição para que ele não tem nenhum preenchimento.
Inicie – coloca o modo de exibição no início do layout.
O código a seguir demonstra as opções de layout de configuração:
No XAML:

<?xml version="1.0" encoding="UTF-8"?>


<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="LayoutSamples.StackLayoutDemo"
Title="StackLayout Demo">
<ContentPage.Content>
<StackLayout x:Name="layout">
<Button VerticalOptions="Start"
HorizontalOptions="FillAndExpand" />
<BoxView VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand" />
<BoxView VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand" />
<BoxView HeightRequest="75" VerticalOptions="End"
HorizontalOptions="FillAndExpand" />
</StackLayout>
</ContentPage.Content>
</ContentPage>

No C#:

public class StackLayoutCode : ContentPage


{
public StackLayoutCode ()
{
var layout = new StackLayout ();
var button = new Button { VerticalOptions = LayoutOptions.Start,
HorizontalOptions = LayoutOptions.FillAndExpand };
var oneBox = new BoxView { VerticalOptions = LayoutOptions.FillAndExpand, HorizontalOptions =
LayoutOptions.FillAndExpand };
var twoBox = new BoxView { VerticalOptions = LayoutOptions.FillAndExpand, HorizontalOptions =
LayoutOptions.FillAndExpand };
var threeBox = new BoxView { VerticalOptions = LayoutOptions.FillAndExpand, HorizontalOptions =
LayoutOptions.FillAndExpand };

layout.Children.Add(button);
layout.Children.Add(oneBox);
layout.Children.Add(twoBox);
layout.Children.Add(threeBox);
Content = layout;
}
}

Para obter mais informações, consulte alinhamento.

Explorando um Layout complexo


Cada um dos layouts têm vantagens e desvantagens para a criação de layouts específicos. Em toda esta série de
artigos de layout, um aplicativo de exemplo foi criado com o mesmo layout de página implementado usando três
layouts diferentes.
Considere o seguinte XAML:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="TheBusinessTumble.StackLayoutPage"
BackgroundColor="Maroon"
Title="StackLayouts">
<ContentPage.Content>
<ScrollView>
<StackLayout Spacing="0" Padding="0" BackgroundColor="Maroon">
<BoxView HorizontalOptions="FillAndExpand" HeightRequest="100"
VerticalOptions="Start" Color="Gray" />
<Button BorderRadius="30" HeightRequest="60" WidthRequest="60"
BackgroundColor="Red" HorizontalOptions="Center" VerticalOptions="Start" />
<StackLayout HeightRequest="100" VerticalOptions="Start" HorizontalOptions="FillAndExpand"
Spacing="20" BackgroundColor="Maroon">
<Label Text="User Name" FontSize="28" HorizontalOptions="Center"
VerticalOptions="Center" FontAttributes="Bold" />
<Entry Text="Bio + Hashtags" TextColor="White"
BackgroundColor="Maroon" HorizontalOptions="FillAndExpand" VerticalOptions="CenterAndExpand" />
</StackLayout>
<StackLayout Orientation="Horizontal" HeightRequest="50" BackgroundColor="White" Padding="5">
<StackLayout Spacing="0" BackgroundColor="White" Orientation="Horizontal"
HorizontalOptions="Start">
<BoxView BackgroundColor="Black" WidthRequest="40" HeightRequest="40"
HorizontalOptions="StartAndExpand" VerticalOptions="Center" />
<Label FontSize="14" TextColor="Black" Text="Accent Color" HorizontalOptions="StartAndExpand"
VerticalOptions="Center" />
</StackLayout>
<StackLayout Spacing="0" BackgroundColor="White" Orientation="Horizontal"
HorizontalOptions="EndAndExpand">
<BoxView BackgroundColor="Maroon" WidthRequest="40" HeightRequest="40" HorizontalOptions="Start"
VerticalOptions="Center" />
<Label FontSize="14" TextColor="Black" Text="Primary Color" HorizontalOptions="StartAndExpand"
VerticalOptions="Center" />
</StackLayout>
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label FontSize="14" Text="Age:" TextColor="White" HorizontalOptions="Start"
VerticalOptions="Center" WidthRequest="100" />
<Entry HorizontalOptions="FillAndExpand" Text="35" TextColor="White" BackgroundColor="Maroon" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label FontSize="14" Text="Interests:" TextColor="White"
HorizontalOptions="Start" VerticalOptions="Center" WidthRequest="100" />
<Entry HorizontalOptions="FillAndExpand" Text="Xamarin.Forms" TextColor="White"
BackgroundColor="Maroon" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label FontSize="14" Text="Ask me about:" TextColor="White"
HorizontalOptions="Start" VerticalOptions="Center" WidthRequest="100"/>
<Entry HorizontalOptions="FillAndExpand" Text="Xamarin, C#, .NET, Mono..." TextColor="White"
BackgroundColor="Maroon" />
</StackLayout>
</StackLayout>
</ScrollView>
</ContentPage.Content>
</ContentPage>

O código acima resulta no layout a seguir:


Observe que StackLayouts s forem aninhadas, pois em alguns casos layouts de aninhamento pode ser mais fácil
do que apresentar todos os elementos do layout do mesmo. Observe também que, porque StackLayout não dá
suporte itens sobrepostos, a página não tem algumas iguarias o layout encontrados nas páginas para os outros
layouts.

Links relacionados
LayoutOptions
Layout (amostra)
Exemplo de BusinessTumble (amostra)
Xamarin. Forms AbsoluteLayout
12/04/2019 • 12 minutes to read

baixar o exemplo
AbsoluteLayout posiciona e dimensiona proporcional ao seu próprio tamanho e posição ou por valores
absolutos de elementos filho. Modos de exibição filho podem ser posicionado e dimensionados usando
proporcionais valores ou valores estáticos e proporcional e valores estáticos podem ser combinados.

Este artigo abordará:


Finalidade – usos comuns do AbsoluteLayout .
Uso – como usar AbsoluteLayout para alcançar o design desejado.
Layouts proporcionais – entender valores como proporcionais funcionem em um AbsoluteLayout .
Especificando valores – entender como proporcional e os valores absolutos são especificadas.
Valores proporcionais – entender valores como proporcionais funcione.
Valores absolutos – entender como funcionam os valores absolutos.

Finalidade
Por causa do modelo de posicionamento de AbsoluteLayout , o layout torna relativamente fácil para posicionar
elementos para que fiquem com qualquer lado do layout ou centralizado. Com proporcionais tamanhos e
posições, elementos em um AbsoluteLayout pode ser dimensionado automaticamente para qualquer tamanho
de exibição. Para itens em que apenas a posição, mas não o tamanho deve ser dimensionado, os valores
absolutos e proporcionais podem ser combinados.
AbsoluteLayout pode ser usado em qualquer lugar em que precisa ser posicionado em uma exibição de
elementos e é especialmente útil ao alinhar os elementos para bordas.

Uso
Layouts proporcionais
AbsoluteLayout tem um modelo de âncora exclusivo, no qual a âncora do elemento é posicionada em relação ao
seu elemento como o elemento é posicionado em relação ao layout quando posicionamento proporcional é
usado. Quando o posicionamento absoluto é usado, a âncora é em (0,0) dentro da exibição. Isso tem duas
consequências importantes:
Elementos não podem ser posicionados fora da tela usando valores proporcionais.
Elementos podem ser posicionados de forma confiável ao longo de qualquer lado do layout ou no centro,
independentemente do tamanho do layout ou dispositivo.
AbsoluteLayout , como RelativeLayout , é capaz de posicionar elementos para que eles se sobrepõem.
Observe, na captura de tela abaixo, a âncora da caixa é um ponto branco. Observe a relação entre a âncora e a
caixa enquanto se movimentam pelo layout:
Especificando valores
Modos de exibição dentro de um AbsoluteLayout são posicionados usando quatro valores:
X – a posição de x (horizontal) da âncora da exibição
Y – a posição y (vertical) da âncora da exibição
Largura – a largura da exibição
Altura – a altura da exibição
Cada um desses valores pode ser definida como uma proporcional valor ou uma absoluto valor.
Valores são especificados como uma combinação de limites e um sinalizador. LayoutBounds é um Rectangle
consiste em quatro valores: x , y , width , height .
AbsoluteLayoutFlags
AbsoluteLayoutFlags Especifica como os valores serão interpretados e tem as seguintes opções predefinidas:

None – interpreta todos os valores como absolutos. Isso é o valor padrão se nenhum sinalizador de layout
forem especificados.
Todos os – interpreta todos os valores como proporcional.
WidthProportional – interpreta o Width valor como proporcional e todos os outros valores como
absolutos.
HeightProportional – interpreta apenas o valor altura como proporcional com todos os outros valores
absolutos.
XProportional – interpreta o X valor como proporcional, ao tratar todos os outros valores como absolutos.
YProportional – interpreta o Y valor como proporcional, ao tratar todos os outros valores como absolutos.
PositionProportional – interpreta o X e Y valores conforme proporcional, enquanto os valores de
tamanho são interpretados como absolutos.
SizeProportional – interpreta o Width e Height valores conforme proporcional, enquanto os valores de
posição são absolutos.
No XAML, limites e os sinalizadores são definidos como parte da definição de modos de exibição no layout,
usando o AbsoluteLayout.LayoutBounds propriedade. Limites são definidos como uma lista separada por vírgulas
de valores, X , Y , Width , e Height , nessa ordem. Sinalizadores também são especificados na declaração de
modos de exibição no layout usando o AbsoluteLayout.LayoutFlags propriedade. Observe que os sinalizadores
podem ser combinados em XAML usando uma lista separada por vírgulas. Considere o exemplo a seguir:

<?xml version="1.0" encoding="UTF-8"?>


<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="LayoutSamples.AbsoluteLayoutExploration"
Title="Absolute Layout Exploration">
<ContentPage.Content>
<AbsoluteLayout>
<Label Text="I'm centered on iPhone 4 but no other device"
AbsoluteLayout.LayoutBounds="115,150,100,100" LineBreakMode="WordWrap" />
<Label Text="I'm bottom center on every device."
AbsoluteLayout.LayoutBounds=".5,1,.5,.1" AbsoluteLayout.LayoutFlags="All"
LineBreakMode="WordWrap" />
<BoxView Color="Olive" AbsoluteLayout.LayoutBounds="1,.5, 25, 100"
AbsoluteLayout.LayoutFlags="PositionProportional" />
<BoxView Color="Red" AbsoluteLayout.LayoutBounds="0,.5,25,100"
AbsoluteLayout.LayoutFlags="PositionProportional" />
<BoxView Color="Blue" AbsoluteLayout.LayoutBounds=".5,0,100,25"
AbsoluteLayout.LayoutFlags="PositionProportional" />
</AbsoluteLayout>
</ContentPage.Content>
</ContentPage>

Observe o seguinte:
No centro do rótulo é posicionado usando valores de tamanho e posição absolutas. Por causa disso,
aparentemente centralizada no iPhone 4S e inferior, mas não centralizado em dispositivos maiores.
O texto na parte inferior do layout é posicionado usando valores de tamanho e posição proporcionais. Ele
sempre será exibido na parte inferior central do layout, mas seu tamanho aumentará com tamanhos maiores
de layout.
Três coloridas BoxView s são posicionados nas bordas superior, esquerdas e direita da tela usando a posição
proporcional e o tamanho absoluto.
O exemplo a seguir alcança o mesmo layout em c#:

public class AbsoluteLayoutExplorationCode : ContentPage


{
public AbsoluteLayoutExplorationCode ()
{
Title = "Absolute Layout Exploration - Code";
var layout = new AbsoluteLayout();

var centerLabel = new Label {


Text = "I'm centered on iPhone 4 but no other device.",
LineBreakMode = LineBreakMode.WordWrap};

AbsoluteLayout.SetLayoutBounds (centerLabel, new Rectangle (115, 159, 100, 100));


// No need to set layout flags, absolute positioning is the default

var bottomLabel = new Label { Text = "I'm bottom center on every device.", LineBreakMode =
LineBreakMode.WordWrap };
AbsoluteLayout.SetLayoutBounds (bottomLabel, new Rectangle (.5, 1, .5, .1));
AbsoluteLayout.SetLayoutFlags (bottomLabel, AbsoluteLayoutFlags.All);

var rightBox = new BoxView{ Color = Color.Olive };


AbsoluteLayout.SetLayoutBounds (rightBox, new Rectangle (1, .5, 25, 100));
AbsoluteLayout.SetLayoutFlags (rightBox, AbsoluteLayoutFlags.PositionProportional);

var leftBox = new BoxView{ Color = Color.Red };


AbsoluteLayout.SetLayoutBounds (leftBox, new Rectangle (0, .5, 25, 100));
AbsoluteLayout.SetLayoutFlags (leftBox, AbsoluteLayoutFlags.PositionProportional);

var topBox = new BoxView{ Color = Color.Blue };


AbsoluteLayout.SetLayoutBounds (topBox, new Rectangle (.5, 0, 100, 25));
AbsoluteLayout.SetLayoutFlags (topBox, AbsoluteLayoutFlags.PositionProportional);

layout.Children.Add (bottomLabel);
layout.Children.Add (centerLabel);
layout.Children.Add (rightBox);
layout.Children.Add (leftBox);
layout.Children.Add (topBox);

Content = layout;
}
}

Valores proporcionais
Valores proporcionais definem uma relação entre um layout e um modo de exibição. Essa relação define a
posição de um modo de exibição de filho ou valor de escala como uma proporção do valor correspondente do
layout pai. Esses valores são expressos como double s com valores entre 0 e 1.
Proporcionais valores são usados para exibições de tamanho no layout e posição. Portanto, quando a largura do
modo de exibição é definida como uma proporção, o valor de largura resultante é a proporção multiplicada pela
AbsoluteLayout da largura. Por exemplo, com um AbsoluteLayout da largura 500 e uma exibição definida para
ter uma largura proporcional de.5, a largura renderizada da exibição serão 250 (500 x.5 n
Para usar valores proporcionais, defina LayoutBounds usando (x, y) proporções e tamanhos proporcionais, em
seguida, defina LayoutFlags para All .
No XAML:

<Label Text="I'm bottom center on every device."


AbsoluteLayout.LayoutBounds=".5,1,.5,.1" AbsoluteLayout.LayoutFlags="All" />

No C#:

var label = new Label {Text = "I'm bottom center on every device."};
AbsoluteLayout.SetLayoutBounds(label, new Rectangle(.5,1,.5,.1));
AbsoluteLayout.SetLayoutFlags(label, AbsoluteLayoutFlags.All);

Valores absolutos
Valores absolutos definir explicitamente onde os modos de exibição devem ser posicionados no layout. Ao
contrário de valores proporcionais, os valores absolutos são capazes de posicionar e dimensionar uma exibição
que não se ajustar dentro dos limites do layout.
Usando os valores absolutos para posicionamento pode ser perigoso quando o tamanho do layout não é
conhecido. Ao usar posições absolutas, um elemento no centro da tela em um tamanho poderia ser deslocado
em qualquer outro tamanho. É importante testar seu aplicativo em vários tamanhos de tela de seus dispositivos
com suporte.
Para usar valores de layout absoluto, defina LayoutBounds usando (x, y) as coordenadas e tamanhos explícitos,
em seguida, defina LayoutFlags para None .
No XAML:

<Label Text="I'm centered on iPhone 4 but no other device."


AbsoluteLayout.LayoutBounds="115,150,100,100" />

No C#:

var label = new Label {Text = "I'm centered on iPhone 4 but no other device."};
AbsoluteLayout.SetLayoutBounds(label, new Rectangle(115,150,100,100));

Explorando um Layout complexo


Cada um dos layouts têm vantagens e desvantagens para a criação de layouts específicos. Em toda esta série de
artigos de layout, um aplicativo de exemplo foi criado com o mesmo layout de página implementado usando três
layouts diferentes.
Considere o seguinte XAML:

<?xml version="1.0" encoding="UTF-8"?>


<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="TheBusinessTumble.AbsoluteLayoutPage"
Title="AbsoluteLayout">
<ContentPage.ToolbarItems>
<ToolbarItem Text="Save" />
</ContentPage.ToolbarItems>
<ContentPage.Content>
<ScrollView>
<AbsoluteLayout BackgroundColor="Maroon">
<AbsoluteLayout BackgroundColor="Maroon">
<BoxView BackgroundColor="Gray" AbsoluteLayout.LayoutBounds="0
0,1,100" AbsoluteLayout.LayoutFlags="XProportional,YProportional,WidthProportional" />
<Button BackgroundColor="Maroon"
AbsoluteLayout.LayoutBounds=".5,55,70,70" AbsoluteLayout.LayoutFlags="XProportional"
BorderRadius="35" />
<Button BackgroundColor="Red" AbsoluteLayout.LayoutBounds=".5
60,60,60" AbsoluteLayout.LayoutFlags="XProportional" BorderRadius="30" />
<Label Text="User Name" FontAttributes="Bold" FontSize="26"
TextColor="Black" HorizontalTextAlignment="Center"
AbsoluteLayout.LayoutBounds=".5,140,1,40" AbsoluteLayout.LayoutFlags="XProportional,WidthProportional" />
<Entry Text="Bio + Hashtags" TextColor="White"
BackgroundColor="Maroon" AbsoluteLayout.LayoutBounds=".5,180,1,40"
AbsoluteLayout.LayoutFlags="XProportional,WidthProportional" />
<AbsoluteLayout BackgroundColor="White"
AbsoluteLayout.LayoutBounds="0, 220, 1, 50"
AbsoluteLayout.LayoutFlags="XProportional,WidthProportional">
<AbsoluteLayout AbsoluteLayout.LayoutBounds="0,0,.5,1"
AbsoluteLayout.LayoutFlags="WidthProportional,HeightProportional">
<Button BackgroundColor="Black" BorderRadius="20"
AbsoluteLayout.LayoutBounds="5,.5,40,40"
AbsoluteLayout.LayoutFlags="YProportional" />
<Label Text="Accent Color" TextColor="Black"
AbsoluteLayout.LayoutBounds="50,.55,1,25"
AbsoluteLayout.LayoutFlags="YProportional,WidthProportional" />
</AbsoluteLayout>
<AbsoluteLayout AbsoluteLayout.LayoutBounds="1,0,.5,1"
AbsoluteLayout.LayoutFlags="WidthProportional,HeightProportional,XProportional">
<Button BackgroundColor="Maroon" BorderRadius="20"
AbsoluteLayout.LayoutBounds="5,.5,40,40"
AbsoluteLayout.LayoutFlags="YProportional" />
<Label Text="Primary Color" TextColor="Black"
AbsoluteLayout.LayoutBounds="50,.55,1,25"
AbsoluteLayout.LayoutFlags="YProportional,WidthProportional" />
</AbsoluteLayout>
</AbsoluteLayout>
<AbsoluteLayout AbsoluteLayout.LayoutBounds="0,270,1,50"
AbsoluteLayout.LayoutFlags="WidthProportional" Padding="5,0,0,0">
<Label Text="Age:" TextColor="White"
AbsoluteLayout.LayoutBounds="0,25,.25,50"
AbsoluteLayout.LayoutFlags="WidthProportional" />
<Entry Text="35" TextColor="White" BackgroundColor="Maroon"
AbsoluteLayout.LayoutBounds="1,10,.75,50"
AbsoluteLayout.LayoutFlags="XProportional,WidthProportional" />
</AbsoluteLayout>
<AbsoluteLayout AbsoluteLayout.LayoutBounds="0,320,1,50"
AbsoluteLayout.LayoutFlags="WidthProportional" Padding="5,0,0,0">
<Label Text="Interests:" TextColor="White"
AbsoluteLayout.LayoutBounds="0,25,.25,50"
AbsoluteLayout.LayoutFlags="WidthProportional" />
<Entry Text="Xamarin.Forms" TextColor="White"
BackgroundColor="Maroon" AbsoluteLayout.LayoutBounds="1,10,.75,50"
AbsoluteLayout.LayoutFlags="XProportional,WidthProportional" />
</AbsoluteLayout>
<AbsoluteLayout AbsoluteLayout.LayoutBounds="0,370,1,50"
AbsoluteLayout.LayoutFlags="WidthProportional" Padding="5,0,0,0">
<Label Text="Ask me about:" TextColor="White"
AbsoluteLayout.LayoutBounds="0,25,.25,50"
AbsoluteLayout.LayoutFlags="WidthProportional" />
<Entry Text="Xamarin, C#, .NET, Mono" TextColor="White"
BackgroundColor="Maroon" AbsoluteLayout.LayoutBounds="1,10,.75,50"
AbsoluteLayout.LayoutFlags="XProportional,WidthProportional" />
</AbsoluteLayout>
</AbsoluteLayout>
</ScrollView>
</ContentPage.Content>
</ContentPage>
O código acima resulta no layout a seguir:

Observe que AbsoluteLayout s forem aninhadas, pois em alguns casos layouts de aninhamento pode ser mais
fácil do que apresentar todos os elementos do layout do mesmo.

Links relacionados
Criação de aplicativos móveis com xamarin. Forms, capítulo 14
AbsoluteLayout
Layout (amostra)
Exemplo de BusinessTumble (amostra)
Xamarin. Forms RelativeLayout
12/04/2019 • 8 minutes to read

baixar o exemplo
RelativeLayout é usado para a posição e modos de exibição de tamanho em relação a propriedades das
exibições de layout ou irmão. Diferentemente AbsoluteLayout , RelativeLayout não tem o conceito da âncora de
movimentação e não tem recursos para posicionar elementos em relação a margem inferior ou direita do layout.
RelativeLayout oferece suporte a elementos de posicionamento fora de seus próprios limites.

Finalidade
RelativeLayoutpode ser usado para posicionar os modos de exibição na tela em relação ao layout geral ou a
outros modos de exibição.

Uso
Noções básicas sobre restrições
Posicionar e dimensionar um modo de exibição dentro de um RelativeLayout é feito com restrições. Uma
expressão de restrição pode incluir as seguintes informações:
Tipo de – se a restrição é relativo ao pai ou para outro modo.
Propriedade – qual propriedade a ser usado como base para a restrição.
Fator – o fator a ser aplicado ao valor da propriedade.
Constante – o valor a ser usado como um deslocamento do valor.
ElementName – o nome da exibição que a restrição é relativo.
No XAML, as restrições são expressos como ConstraintExpression s. Considere o exemplo a seguir:

<BoxView Color="Green" WidthRequest="50" HeightRequest="50"


RelativeLayout.XConstraint =
"{ConstraintExpression Type=RelativeToParent,
Property=Width,
Factor=0.5,
Constant=-100}"
RelativeLayout.YConstraint =
"{ConstraintExpression Type=RelativeToParent,
Property=Height,
Factor=0.5,
Constant=-100}" />

No C#, as restrições são expressas de forma diferente, usando funções em vez de expressões na exibição.
Restrições são especificadas como argumentos para o layout Add método:

layout.Children.Add(box, Constraint.RelativeToParent((parent) =>


{
return (.5 * parent.Width) - 100;
}),
Constraint.RelativeToParent((parent) =>
{
return (.5 * parent.Height) - 100;
}),
Constraint.Constant(50), Constraint.Constant(50));

Observe os seguintes aspectos do layout acima:


O x e y restrições são especificadas com suas próprias restrições.
No C#, as restrições relativas são definidas como funções. Conceitos, como Factor não estiverem lá, mas
pode ser implementado manualmente.
A caixa x coordenada é definida como a metade da largura do pai, -100.
A caixa y coordenada é definida como a metade da altura do pai, -100.

NOTE
Por causa da maneira que as restrições são definidas, é possível fazer os layouts mais complexos no C# que podem ser
especificados com XAML.

Os dois exemplos acima definem restrições como RelativeToParent – ou seja, seus valores são em relação ao
elemento pai. Também é possível definir restrições como relativos a outra exibição. Isso permite que os layouts
mais intuitivos (para o desenvolvedor) e pode deixar a intenção do seu código de layout mais aparente.
Considere um layout em que um elemento deve ser menor do que o outro de 20 pixels. Se ambos os elementos
são definidos com valores constantes, menor poderia ter seus Y restrição definida como uma constante que é
maior que 20 pixels, o Y restrição do maior elemento. Essa abordagem deixa a desejar se o elemento superior é
posicionado usando uma proporção, para que o tamanho de pixel não é conhecido. Nesse caso, restringir o
elemento com base na posição do elemento para outro é mais robusta:

<RelativeLayout>
<BoxView Color="Red" x:Name="redBox"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent,
Property=Height,Factor=.15,Constant=0}"
RelativeLayout.WidthConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Width,Factor=1,Constant=0}"
RelativeLayout.HeightConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Height,Factor=.8,Constant=0}" />
<BoxView Color="Blue"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToView,
ElementName=redBox,Property=Y,Factor=1,Constant=20}"
RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToView,
ElementName=redBox,Property=X,Factor=1,Constant=20}"
RelativeLayout.WidthConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Width,Factor=.5,Constant=0}"
RelativeLayout.HeightConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Height,Factor=.5,Constant=0}" />
</RelativeLayout>

Para realizar o mesmo layout no C#:

layout.Children.Add (redBox, Constraint.RelativeToParent ((parent) => {


return parent.X;
}), Constraint.RelativeToParent ((parent) => {
return parent.Y * .15;
}), Constraint.RelativeToParent((parent) => {
return parent.Width;
}), Constraint.RelativeToParent((parent) => {
return parent.Height * .8;
}));
layout.Children.Add (blueBox, Constraint.RelativeToView (redBox, (Parent, sibling) => {
return sibling.X + 20;
}), Constraint.RelativeToView (blueBox, (parent, sibling) => {
return sibling.Y + 20;
}), Constraint.RelativeToParent((parent) => {
return parent.Width * .5;
}), Constraint.RelativeToParent((parent) => {
return parent.Height * .5;
}));

Isso produz a seguinte saída, com a posição da caixa azul determinada relativo para a posição da caixa vermelha:
Dimensionamento
Modos de exibição apresentados pelo RelativeLayout tem duas opções para especificar seu tamanho:
HeightRequest & WidthRequest
RelativeLayout.WidthConstraint & RelativeLayout.HeightConstraint

HeightRequest e WidthRequest especificam a altura desejada e a largura da exibição, mas pode ser substituída
pelos layouts conforme necessário. WidthConstraint e HeightConstraint dá suporte à definição a altura e largura
como um valor em relação a propriedades de layout ou outra exibição, ou como um valor constante.

Explorando um Layout complexo


Cada um dos layouts têm vantagens e desvantagens para a criação de layouts específicos. Em toda esta série de
artigos de layout, um aplicativo de exemplo foi criado com o mesmo layout de página implementado usando três
layouts diferentes.
Considere o seguinte XAML:

<?xml version="1.0" encoding="UTF-8"?>


<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="TheBusinessTumble.RelativeLayoutPage"
BackgroundColor="Maroon"
Title="RelativeLayout">
<ContentPage.Content>
<ScrollView>
<RelativeLayout>
<BoxView Color="Gray" HeightRequest="100"
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width,
Factor=1}" />
<Button BorderRadius="35" x:Name="imageCircleBack"
BackgroundColor="Maroon" HeightRequest="70" WidthRequest="70" RelativeLayout.XConstraint="
BackgroundColor="Maroon" HeightRequest="70" WidthRequest="70" RelativeLayout.XConstraint="
{ConstraintExpression Type=RelativeToParent,Property=Width, Factor=.5, Constant = -35}"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Factor=0, Property=Y, Constant=70}"
/>
<Button BorderRadius="30" BackgroundColor="Red" HeightRequest="60"
WidthRequest="60" RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToView,
ElementName=imageCircleBack, Property=X, Factor=1,Constant=5}" RelativeLayout.YConstraint="
{ConstraintExpression Type=RelativeToParent, Factor=0, Property=Y, Constant=75}" />
<Label Text="User Name" FontAttributes="Bold" FontSize="26"
HorizontalTextAlignment="Center" RelativeLayout.YConstraint="{ConstraintExpression
Type=RelativeToParent, Property=Y, Factor=0, Constant=140}" RelativeLayout.WidthConstraint="
{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=1}" />
<Entry Text="Bio + Hashtags" TextColor="White" BackgroundColor="Maroon"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Y, Factor=0,
Constant=180}" RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width,
Factor=1}" />
<RelativeLayout BackgroundColor="White" RelativeLayout.YConstraint="
{ConstraintExpression Type=RelativeToParent, Property=Y, Factor=0, Constant=220}"
HeightRequest="60" RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent,
Property=Width, Factor=1}" >
<BoxView BackgroundColor="Black" WidthRequest="50"
HeightRequest="50" RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent,
Property=Y, Factor=0, Constant=5}" RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent,
Property=X, Factor=0, Constant=5}" />
<BoxView BackgroundColor="Maroon" WidthRequest="50"
HeightRequest="50" RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent,
Property=Y, Factor=0, Constant=5}" RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent,
Property=Width, Factor=0.5, Constant=}" />
<Label FontSize="14" TextColor="Black" Text="Accent Color"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Y,
Factor=0, Constant=20}" RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent, Property=X,
Factor=0, Constant=60}" />
<Label FontSize="14" TextColor="Black" Text="Primary Color"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Y,
Factor=0, Constant=20}" RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent,
Property=Width, Factor=0.5, Constant=55}" />
</RelativeLayout>
<RelativeLayout Padding="5,0,0,0">
<Label FontSize="14" Text="Age:" TextColor="White"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height,
Factor=0,Constant=305}"
RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width,
Factor=0, Constant=10}"
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent,
Property=Width,Factor=.25,Constant=0}"
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height,
Factor=0,Constant=50}" />
<Entry Text="35" TextColor="White" BackgroundColor="Maroon"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height,
Factor=0,Constant=280}"
RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width,
Factor=0.3, Constant=0}"
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent,
Property=Width,Factor=0.75,Constant=0}"
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height,
Factor=0,Constant=50}" />
</RelativeLayout>
<RelativeLayout Padding="5,0,0,0">
<Label FontSize="14" Text="Interests:" TextColor="White"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height,
Factor=0,Constant=345}"
RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width,
Factor=0, Constant=10}"
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent,
Property=Width,Factor=.25,Constant=0}"
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height,
Factor=0,Constant=50}" />
<Entry Text="Xamarin.Forms" TextColor="White" BackgroundColor="Maroon"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height,
Factor=0,Constant=320}"
RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width,
Factor=0.3, Constant=0}"
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent,
Property=Width,Factor=0.75,Constant=0}"
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height,
Factor=0,Constant=50}" />
</RelativeLayout>
<RelativeLayout Padding="5,0,0,0">
<Label FontSize="14" Text="Ask me about:" TextColor="White"
LineBreakMode="WordWrap"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height,
Factor=0,Constant=395}"
RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width,
Factor=0, Constant=10}"
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent,
Property=Width,Factor=.25,Constant=0}"
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height,
Factor=0,Constant=50}" />
<Entry Text="Xamarin, C#, .NET, Mono" TextColor="White"
BackgroundColor="Maroon"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height,
Factor=0,Constant=370}"
RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width,
Factor=0.3, Constant=0}"
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent,
Property=Width,Factor=0.75,Constant=0}"
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height,
Factor=0,Constant=50}" />
</RelativeLayout>
</RelativeLayout>
</ScrollView>
</ContentPage.Content>
</ContentPage>

O código acima resulta no layout a seguir:


Observe que RelativeLayouts s forem aninhadas, pois em alguns casos layouts de aninhamento pode ser mais
fácil do que apresentar todos os elementos do layout do mesmo. Além disso, observe que alguns elementos são
RelativeToView , pois o que permite layout mais fácil e intuitivo quando as relações entre os modos de exibição
de guia de posicionamento.

Links relacionados
Layout (amostra)
Exemplo de BusinessTumble (amostra)
Grade de xamarin. Forms
12/04/2019 • 15 minutes to read

baixar o exemplo
Grid dá suporte à organização exibições em linhas e colunas. Linhas e colunas podem ser definidas para ter
tamanhos proporcionais ou tamanhos absolutos. O Grid layout não deve ser confundido com tabelas
tradicionais e não se destina a apresentar dados tabulares. Grid não tem o conceito de linha, coluna ou célula de
formatação. Ao contrário das tabelas HTML, Grid destina-se puramente para dispor o conteúdo.

Este artigo abordará:


Finalidade – usos comuns do Grid .
Uso – como usar Grid para alcançar o design desejado.
Linhas e colunas – especificar linhas e colunas para o Grid .
Colocação de modos de exibição – adicionar modos de exibição para a grade em linhas e colunas
específicas.
Espaçamento – configurar os espaços entre linhas e colunas.
Spans – configurar elementos para abranger várias linhas ou colunas.
Finalidade
Grid pode ser usado para organizar os modos de exibição em uma grade. Isso é útil em um número de casos:
Organizando botões em um aplicativo de Calculadora
Organizando botões/escolhas em uma grade, como o iOS ou Android telas iniciais
Organizando os modos de exibição para que eles sejam de tamanho igual em uma dimensão (como em
algumas barras de ferramentas)

Uso
Ao contrário das tabelas tradicionais, Grid não deduz o número e os tamanhos de linhas e colunas do conteúdo.
Em vez disso, Grid tem RowDefinitions e ColumnDefinitions coleções. Eles mantêm as definições de quantas
linhas e colunas serão dispostas. As exibições são adicionadas à Grid com a linha especificada e os índices de
coluna, que identificam quais linhas e colunas de um modo de exibição deve ser colocado em.
Linhas e colunas
Informações de linha e coluna são armazenadas no Grid do RowDefinitions & ColumnDefinitions propriedades,
que são coleções de cada de RowDefinition e ColumnDefinition objetos, respectivamente. RowDefinition tem
uma única propriedade, Height , e ColumnDefinition tem uma propriedade única, Width . As opções para altura e
largura são da seguinte maneira:
Auto – automaticamente os tamanhos para ajustar o conteúdo da linha ou coluna. Especificado como
GridUnitType.Auto em C# ou como Auto em XAML.
Proportional(*) – dimensiona as colunas e linhas como uma proporção de espaço restante. Especificado
como um valor e GridUnitType.Star em C# e como #* em XAML, com # sendo o valor desejado.
Especificando uma linha/coluna com * fará com que ela preencher o espaço disponível.
Absoluto – dimensiona as colunas e linhas com valores de altura e largura fixas, específicos. Especificado
como um valor e GridUnitType.Absolute em C# e como # em XAML, com # sendo o valor desejado.

NOTE
Os valores de largura de colunas são definidos como * por padrão no xamarin. Forms, que garante que a coluna
preencherá o espaço disponível. Os valores de altura para linhas também são definidos como * por padrão.

Considere um aplicativo que precisa de três linhas e duas colunas. A linha inferior precisa ser exatamente 200px
altura e a linha superior precisa ser duas vezes com a altura da linha intermediária. A coluna à esquerda deve ser
grande o suficiente para caber o conteúdo e a coluna à direita precisa preencher o espaço restante.
No XAML:

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*" />
<RowDefinition Height="*" />
<RowDefinition Height="200" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid>

No C#:

var grid = new Grid();


grid.RowDefinitions.Add (new RowDefinition { Height = new GridLength(2, GridUnitType.Star) });
grid.RowDefinitions.Add (new RowDefinition { Height = new GridLength (1, GridUnitType.Star) });
grid.RowDefinitions.Add (new RowDefinition { Height = new GridLength(200)});
grid.ColumnDefinitions.Add (new ColumnDefinition{ Width = new GridLength (200) });

Colocando exibições em uma grade


Para colocar os modos de exibição em um Grid você precisará adicioná-los como filhos na grade, e em seguida,
especificar quais linhas e colunas eles pertencem.
No XAML, use Grid.Row e Grid.Column em cada exibição individual para especificar o posicionamento. Observe
que Grid.Row e Grid.Column especificar local com base nas listas de base zero de linhas e colunas. Isso significa
que, em uma 4x4 grade, a célula superior esquerda é (0,0) e a célula inferior direita é (3,3).
O Grid mostrado a seguir contém quatro células:
No XAML:

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Text="Top Left" Grid.Row="0" Grid.Column="0" />
<Label Text="Top Right" Grid.Row="0" Grid.Column="1" />
<Label Text="Bottom Left" Grid.Row="1" Grid.Column="0" />
<Label Text="Bottom Right" Grid.Row="1" Grid.Column="1" />
</Grid>

No C#:
var grid = new Grid();

grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star)});


grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star)});
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star)});
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star)});

var topLeft = new Label { Text = "Top Left" };


var topRight = new Label { Text = "Top Right" };
var bottomLeft = new Label { Text = "Bottom Left" };
var bottomRight = new Label { Text = "Bottom Right" };

grid.Children.Add(topLeft, 0, 0);
grid.Children.Add(topRight, 1, 0);
grid.Children.Add(bottomLeft, 0, 1);
grid.Children.Add(bottomRight, 1, 1);

O código acima cria a grade com quatro rótulos, duas colunas e duas linhas. Observe que cada rótulo terá o
mesmo tamanho e que as linhas se expandem para usar todo o espaço disponível.
No exemplo acima, as exibições são adicionadas para o Grid.Children coleção usando o Add sobrecarga que
especifica os argumentos left e top. Ao usar o Add durante a sobrecarga que especifica para a esquerda, direita,
superior e argumentos de parte inferior, esquerda e argumentos superior sempre fará referência às células dentro
a Grid , à direita e argumentos de parte inferior podem aparecer para se referir às células que estão fora de
Grid . Isso ocorre porque o argumento à direita sempre deve ser maior que o argumento esquerdo e o
argumento inferior sempre deve ser maior que o argumento superior. O exemplo a seguir mostra o código
equivalente usando os dois Add sobrecargas:

// left, top
grid.Children.Add(topLeft, 0, 0);
grid.Children.Add(topRight, 1, 0);
grid.Children.Add(bottomLeft, 0, 1);
grid.Children.Add(bottomRight, 1, 1);

// left, right, top, bottom


grid.Children.Add(topLeft, 0, 1, 0, 1);
grid.Children.Add(topRight, 1, 2, 0, 1);
grid.Children.Add(bottomLeft, 0, 1, 1, 2);
grid.Children.Add(bottomRight, 1, 2, 1, 2);

Espaçamento
Grid tem propriedades para controlar o espaçamento entre linhas e colunas. As seguintes propriedades estão
disponíveis para personalizar o Grid :
ColumnSpacing – a quantidade de espaço entre colunas. O valor padrão dessa propriedade é 6.
RowSpacing – a quantidade de espaço entre as linhas. O valor padrão dessa propriedade é 6.
O XAML a seguir especifica um Grid com duas colunas, uma linha e 5 px de espaçamento entre colunas:

<Grid ColumnSpacing="5">
<Grid.ColumnDefinitions>
<ColumnDefinitions Width="*" />
<ColumnDefinitions Width="*" />
</Grid.ColumnDefinitions>
</Grid>

No C#:
var grid = new Grid { ColumnSpacing = 5 };
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength (1, GridUnitType.Star)});
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength (1, GridUnitType.Star)});

Intervalos
Geralmente, ao trabalhar com uma grade, há um elemento que deve ocupar mais de uma linha ou coluna.
Considere um aplicativo de calculadora simples:

Observe que o botão 0 abrange duas colunas, assim como em que as calculadoras internos para cada plataforma.
Isso é feito usando o ColumnSpan propriedade, que especifica quantas colunas um elemento deve ocupar. O
XAML para esse botão:

<Button Text = "0" Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="2" />

E, em C#:

Button zeroButton = new Button { Text = "0" };


controlGrid.Children.Add (zeroButton, 0, 4);
Grid.SetColumnSpan (zeroButton, 2);

Observe que no código, métodos estáticos do Grid classe são usados para executar alterações de
posicionamento, incluindo as alterações ColumnSpan e RowSpan . Também Observe que, ao contrário de outras
propriedades que podem ser definidas a qualquer momento, as propriedades definidas usando os métodos
estáticos já devem estar na grade antes que sejam alteradas.
O XAML completo para o aplicativo Calculadora acima é da seguinte maneira:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="LayoutSamples.CalculatorGridXAML"
Title = "Calculator - XAML"
BackgroundColor="#404040">
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="plainButton" TargetType="Button">
<Setter Property="BackgroundColor" Value="#eee"/>
<Setter Property="TextColor" Value="Black" />
<Setter Property="BorderRadius" Value="0"/>
<Setter Property="FontSize" Value="40" />
</Style>
<Style x:Key="darkerButton" TargetType="Button">
<Setter Property="BackgroundColor" Value="#ddd"/>
<Setter Property="TextColor" Value="Black" />
<Setter Property="BorderRadius" Value="0"/>
<Setter Property="FontSize" Value="40" />
</Style>
<Style x:Key="orangeButton" TargetType="Button">
<Setter Property="BackgroundColor" Value="#E8AD00"/>
<Setter Property="TextColor" Value="White" />
<Setter Property="BorderRadius" Value="0"/>
<Setter Property="FontSize" Value="40" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<Grid x:Name="controlGrid" RowSpacing="1" ColumnSpacing="1">
<Grid.RowDefinitions>
<RowDefinition Height="150" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Text="0" Grid.Row="0" HorizontalTextAlignment="End" VerticalTextAlignment="End"
TextColor="White"
FontSize="60" Grid.ColumnSpan="4" />
<Button Text = "C" Grid.Row="1" Grid.Column="0"
Style="{StaticResource darkerButton}" />
<Button Text = "+/-" Grid.Row="1" Grid.Column="1"
Style="{StaticResource darkerButton}" />
<Button Text = "%" Grid.Row="1" Grid.Column="2"
Style="{StaticResource darkerButton}" />
<Button Text = "div" Grid.Row="1" Grid.Column="3"
Style="{StaticResource orangeButton}" />
<Button Text = "7" Grid.Row="2" Grid.Column="0"
Style="{StaticResource plainButton}" />
<Button Text = "8" Grid.Row="2" Grid.Column="1"
Style="{StaticResource plainButton}" />
<Button Text = "9" Grid.Row="2" Grid.Column="2"
Style="{StaticResource plainButton}" />
<Button Text = "X" Grid.Row="2" Grid.Column="3"
Style="{StaticResource orangeButton}" />
<Button Text = "4" Grid.Row="3" Grid.Column="0"
Style="{StaticResource plainButton}" />
<Button Text = "5" Grid.Row="3" Grid.Column="1"
Style="{StaticResource plainButton}" />
<Button Text = "6" Grid.Row="3" Grid.Column="2"
Style="{StaticResource plainButton}" />
Style="{StaticResource plainButton}" />
<Button Text = "-" Grid.Row="3" Grid.Column="3"
Style="{StaticResource orangeButton}" />
<Button Text = "1" Grid.Row="4" Grid.Column="0"
Style="{StaticResource plainButton}" />
<Button Text = "2" Grid.Row="4" Grid.Column="1"
Style="{StaticResource plainButton}" />
<Button Text = "3" Grid.Row="4" Grid.Column="2"
Style="{StaticResource plainButton}" />
<Button Text = "+" Grid.Row="4" Grid.Column="3"
Style="{StaticResource orangeButton}" />
<Button Text = "0" Grid.ColumnSpan="2"
Grid.Row="5" Grid.Column="0" Style="{StaticResource plainButton}" />
<Button Text = "." Grid.Row="5" Grid.Column="2"
Style="{StaticResource plainButton}" />
<Button Text = "=" Grid.Row="5" Grid.Column="3"
Style="{StaticResource orangeButton}" />
</Grid>
</ContentPage.Content>
</ContentPage>

Observe que tanto o rótulo na parte superior da grade e o botão zero são occuping mais de uma coluna. Embora
um layout semelhante pode ser obtido usando grades aninhadas, a ColumnSpan & RowSpan abordagem é mais
simples.
A implementação do C#:

public CalculatorGridCode ()
{
Title = "Calculator - C#";
BackgroundColor = Color.FromHex ("#404040");

var plainButton = new Style (typeof(Button)) {


Setters = {
new Setter { Property = Button.BackgroundColorProperty, Value = Color.FromHex ("#eee") },
new Setter { Property = Button.TextColorProperty, Value = Color.Black },
new Setter { Property = Button.BorderRadiusProperty, Value = 0 },
new Setter { Property = Button.FontSizeProperty, Value = 40 }
}
};
var darkerButton = new Style (typeof(Button)) {
Setters = {
new Setter { Property = Button.BackgroundColorProperty, Value = Color.FromHex ("#ddd") },
new Setter { Property = Button.TextColorProperty, Value = Color.Black },
new Setter { Property = Button.BorderRadiusProperty, Value = 0 },
new Setter { Property = Button.FontSizeProperty, Value = 40 }
}
};
var orangeButton = new Style (typeof(Button)) {
Setters = {
new Setter { Property = Button.BackgroundColorProperty, Value = Color.FromHex ("#E8AD00") },
new Setter { Property = Button.TextColorProperty, Value = Color.White },
new Setter { Property = Button.BorderRadiusProperty, Value = 0 },
new Setter { Property = Button.FontSizeProperty, Value = 40 }
}
};

var controlGrid = new Grid { RowSpacing = 1, ColumnSpacing = 1 };


controlGrid.RowDefinitions.Add (new RowDefinition { Height = new GridLength (150) });
controlGrid.RowDefinitions.Add (new RowDefinition { Height = new GridLength (1, GridUnitType.Star) });
controlGrid.RowDefinitions.Add (new RowDefinition { Height = new GridLength (1, GridUnitType.Star) });
controlGrid.RowDefinitions.Add (new RowDefinition { Height = new GridLength (1, GridUnitType.Star) });
controlGrid.RowDefinitions.Add (new RowDefinition { Height = new GridLength (1, GridUnitType.Star) });
controlGrid.RowDefinitions.Add (new RowDefinition { Height = new GridLength (1, GridUnitType.Star) });

controlGrid.ColumnDefinitions.Add (new ColumnDefinition { Width = new GridLength (1, GridUnitType.Star) });


controlGrid.ColumnDefinitions.Add (new ColumnDefinition { Width = new GridLength (1, GridUnitType.Star) });
controlGrid.ColumnDefinitions.Add (new ColumnDefinition { Width = new GridLength (1, GridUnitType.Star) });
controlGrid.ColumnDefinitions.Add (new ColumnDefinition { Width = new GridLength (1, GridUnitType.Star) });

var label = new Label {


Text = "0",
HorizontalTextAlignment = TextAlignment.End,
VerticalTextAlignment = TextAlignment.End,
TextColor = Color.White,
FontSize = 60
};
controlGrid.Children.Add (label, 0, 0);

Grid.SetColumnSpan (label, 4);

controlGrid.Children.Add (new Button { Text = "C", Style = darkerButton }, 0, 1);


controlGrid.Children.Add (new Button { Text = "+/-", Style = darkerButton }, 1, 1);
controlGrid.Children.Add (new Button { Text = "%", Style = darkerButton }, 2, 1);
controlGrid.Children.Add (new Button { Text = "div", Style = orangeButton }, 3, 1);
controlGrid.Children.Add (new Button { Text = "7", Style = plainButton }, 0, 2);
controlGrid.Children.Add (new Button { Text = "8", Style = plainButton }, 1, 2);
controlGrid.Children.Add (new Button { Text = "9", Style = plainButton }, 2, 2);
controlGrid.Children.Add (new Button { Text = "X", Style = orangeButton }, 3, 2);
controlGrid.Children.Add (new Button { Text = "4", Style = plainButton }, 0, 3);
controlGrid.Children.Add (new Button { Text = "5", Style = plainButton }, 1, 3);
controlGrid.Children.Add (new Button { Text = "6", Style = plainButton }, 2, 3);
controlGrid.Children.Add (new Button { Text = "-", Style = orangeButton }, 3, 3);
controlGrid.Children.Add (new Button { Text = "1", Style = plainButton }, 0, 4);
controlGrid.Children.Add (new Button { Text = "2", Style = plainButton }, 1, 4);
controlGrid.Children.Add (new Button { Text = "3", Style = plainButton }, 2, 4);
controlGrid.Children.Add (new Button { Text = "+", Style = orangeButton }, 3, 4);
controlGrid.Children.Add (new Button { Text = ".", Style = plainButton }, 2, 5);
controlGrid.Children.Add (new Button { Text = "=", Style = orangeButton }, 3, 5);

var zeroButton = new Button { Text = "0", Style = plainButton };


controlGrid.Children.Add (zeroButton, 0, 5);
Grid.SetColumnSpan (zeroButton, 2);

Content = controlGrid;
}

Links relacionados
Criação de aplicativos móveis com xamarin. Forms, capítulo 17
Grade
Layout (amostra)
Exemplo de BusinessTumble (amostra)
O xamarin. Forms FlexLayout
12/04/2019 • 42 minutes to read

baixar o exemplo
Use FlexLayout para empilhamento ou encapsulando uma coleção de exibições filho.
O xamarin. Forms FlexLayout há de novo no xamarin. Forms versão 3.0. Ele se baseia na folha de estilos módulo
de Layout de caixa flexível, comumente conhecido como flex layout ou flex caixa, assim chamada porque ele inclui
muitas opções flexíveis para organizar filhos no layout.
FlexLayout é semelhante ao xamarin. Forms StackLayout em que ele pode organizar seus filhos horizontalmente
e verticalmente em uma pilha. No entanto, o FlexLayout também é capaz de quebra automática de seus filhos se
houver muitas para caber em uma única linha ou coluna, e também tem muitas opções para a orientação,
alinhamento e adaptar-se a vários tamanhos de tela.
FlexLayout deriva Layout<View> e herda um Children propriedade do tipo IList<View> .
FlexLayout define seis propriedades vinculáveis públicas e cinco propriedades vinculáveis anexadas que afetam o
tamanho, orientação e o alinhamento dos elementos filho. (Se você não estiver familiarizado com as propriedades
vinculáveis anexadas, consulte o artigo propriedades anexadas.) Essas propriedades são descritas
detalhadamente nas seções a seguir as propriedades vinculáveis detalhadamente e as propriedades
anexadas associáveis detalhadamente. No entanto, este artigo começa com uma seção em algumas cenários
comuns de uso de FlexLayout que descreve muitas dessas propriedades de modo mais informal. Até o final do
artigo, você verá como combinar FlexLayout com folhas de estilos CSS.

Cenários de uso comuns


O FlexLayoutDemos programa de exemplo contém várias páginas que demonstram alguns usos comuns do
FlexLayout e permite fazer experiências com suas propriedades.

Usando FlexLayout para uma pilha simple


O simples pilha página mostra como FlexLayout pode substituir por um StackLayout , mas com a marcação
mais simples. Tudo o que neste exemplo é definido na página XAML. O FlexLayout contém quatro filhos:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:FlexLayoutDemos"
x:Class="FlexLayoutDemos.SimpleStackPage"
Title="Simple Stack">

<FlexLayout Direction="Column"
AlignItems="Center"
JustifyContent="SpaceEvenly">

<Label Text="FlexLayout in Action"


FontSize="Large" />

<Image Source="{local:ImageResource FlexLayoutDemos.Images.SeatedMonkey.jpg}" />

<Button Text="Do-Nothing Button" />

<Label Text="Another Label" />


</FlexLayout>
</ContentPage>

Aqui está a página em execução no iOS, Android e plataforma Universal do Windows:

Três propriedades do FlexLayout são mostrados na SimpleStackPage.xaml arquivo:


O Direction estiver definida como um valor de FlexDirection enumeração. O padrão é Row . Definindo a
propriedade como Column faz com que os filhos do FlexLayout sejam organizados em uma única coluna
de itens.
Quando itens de um FlexLayout são organizados em uma coluna, o FlexLayout é considerado como
tendo uma vertical eixo principal e um horizontal cruzar eixo.
O AlignItems propriedade é do tipo FlexAlignItems e especifica como os itens são alinhados no eixo
transversal. O Center opção faz com que cada item centralizado horizontalmente.
Se você estivesse usando um StackLayout em vez de uma FlexLayout para essa tarefa, você teria
centralizar todos os itens por meio da atribuição a HorizontalOptions propriedade de cada item para
Center . O HorizontalOptions propriedade não funciona para os filhos de um FlexLayout , mas a única
AlignItems propriedade realiza o mesmo objetivo. Se você precisar, você pode usar o AlignSelf anexados
a propriedade associável para substituir o AlignItems propriedade para itens individuais:
<Label Text="FlexLayout in Action"
FontSize="Large"
FlexLayout.AlignSelf="Start" />

Com essa alteração, essa Label é posicionado na borda esquerda do FlexLayout quando a ordem de
leitura é esquerda para a direita.
O JustifyContent propriedade é do tipo FlexJustify e especifica como os itens são organizados no eixo
principal. O SpaceEvenly opção aloca todos os espaço vertical abandonado igualmente entre todos os
itens e acima do primeiro item e abaixo do último item.
Se você estivesse usando um StackLayout , você precisará atribuir a VerticalOptions propriedade de cada
item para CenterAndExpand para conseguir um efeito semelhante. Mas o CenterAndExpand opção alocará
duas vezes mais espaço entre cada item que antes do primeiro item e depois do último item. Você pode
imitar a CenterAndExpand opção de VerticalOptions definindo o JustifyContent propriedade do
FlexLayout para SpaceAround .

Eles FlexLayout propriedades são discutidas mais detalhadamente na seção as propriedades vinculáveis
detalhadamente abaixo.
Usando FlexLayout para quebra automática de itens
O foto encapsulamento página do FlexLayoutDemos exemplo demonstra como FlexLayout pode encapsular
a seus filhos para linhas ou colunas adicionais. O arquivo XAML instancia o FlexLayout e atribui as duas
propriedades:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="FlexLayoutDemos.PhotoWrappingPage"
Title="Photo Wrapping">
<Grid>
<ScrollView>
<FlexLayout x:Name="flexLayout"
Wrap="Wrap"
JustifyContent="SpaceAround" />
</ScrollView>

<ActivityIndicator x:Name="activityIndicator"
IsRunning="True"
VerticalOptions="Center" />
</Grid>
</ContentPage>

O Direction propriedade deste FlexLayout não for definido, para que ele tenha a configuração padrão de Row ,
que significa que os filhos são organizados em linhas e o eixo principal é horizontal.
O Wrap é de propriedade de um tipo de enumeração FlexWrap . Se houver itens demais para caber em uma
linha, a configuração dessa propriedade faz com que os itens quebre para a próxima linha.
Observe que o FlexLayout é um filho de um ScrollView . Se houver muitas linhas para caber na página, em
seguida, a ScrollView tem um padrão Orientation propriedade de Vertical e permite a rolagem vertical.
O JustifyContent propriedade aloca espaço remanescente no eixo principal (o eixo horizontal), de modo que
cada item fica entre a mesma quantidade de espaço em branco.
O arquivo code-behind acessa uma coleção de fotos de exemplo e adicioná-los para o Children coleção do
FlexLayout :
public partial class PhotoWrappingPage : ContentPage
{
// Class for deserializing JSON list of sample bitmaps
[DataContract]
class ImageList
{
[DataMember(Name = "photos")]
public List<string> Photos = null;
}

public PhotoWrappingPage ()
{
InitializeComponent ();

LoadBitmapCollection();
}

async void LoadBitmapCollection()


{
int imageDimension = Device.RuntimePlatform == Device.iOS ||
Device.RuntimePlatform == Device.Android ? 240 : 120;

string urlSuffix = String.Format("?width={0}&height={0}&mode=max", imageDimension);

using (WebClient webClient = new WebClient())


{
try
{
// Download the list of stock photos
Uri uri = new Uri("http://docs.xamarin.com/demo/stock.json");
byte[] data = await webClient.DownloadDataTaskAsync(uri);

// Convert to a Stream object


using (Stream stream = new MemoryStream(data))
{
// Deserialize the JSON into an ImageList object
var jsonSerializer = new DataContractJsonSerializer(typeof(ImageList));
ImageList imageList = (ImageList)jsonSerializer.ReadObject(stream);

// Create an Image object for each bitmap


foreach (string filepath in imageList.Photos)
{
Image image = new Image
{
Source = ImageSource.FromUri(new Uri(filepath + urlSuffix))
};
flexLayout.Children.Add(image);
}
}
}
catch
{
flexLayout.Children.Add(new Label
{
Text = "Cannot access list of bitmap files"
});
}
}

activityIndicator.IsRunning = false;
activityIndicator.IsVisible = false;
}
}

Aqui está o programa em execução, progressivamente rolado de cima para baixo:


Layout de página com FlexLayout
Há um layout padrão do design da web chamada a Santo graal porque ele é um formato de layout que é algo
extremamente desejável, mas muitas vezes é difícil perceber com perfeição. O layout consiste em um cabeçalho
na parte superior da página e rodapé na parte inferior, ambos os Estender até a largura total da página. Ocupar o
centro da página é o conteúdo principal, mas geralmente com um menu em colunas à esquerda das informações
de conteúdo e suplementares (às vezes chamado de um separar área) à direita. Seção 5.4.1 da especificação de
Layout de caixa flexível CSS descreve como o layout de Santo graal pode ser realizado com uma caixa flexível.
O Layout Santo Graal página do FlexLayoutDemos exemplo mostra uma implementação simples desse
layout usando um FlexLayout aninhado em outro. Como essa página é projetada para um telefone no modo
retrato, as áreas para a esquerda e direita da área de conteúdo são apenas 50 pixels de largura:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="FlexLayoutDemos.HolyGrailLayoutPage"
Title="Holy Grail Layout">

<FlexLayout Direction="Column">

<!-- Header -->


<Label Text="HEADER"
FontSize="Large"
BackgroundColor="Aqua"
HorizontalTextAlignment="Center" />

<!-- Body -->


<FlexLayout FlexLayout.Grow="1">

<!-- Content -->


<Label Text="CONTENT"
FontSize="Large"
BackgroundColor="Gray"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center"
FlexLayout.Grow="1" />

<!-- Navigation items-->


<BoxView FlexLayout.Basis="50"
FlexLayout.Order="-1"
Color="Blue" />

<!-- Aside items -->


<BoxView FlexLayout.Basis="50"
Color="Green" />

</FlexLayout>

<!-- Footer -->


<Label Text="FOOTER"
FontSize="Large"
BackgroundColor="Pink"
HorizontalTextAlignment="Center" />
</FlexLayout>
</ContentPage>

Aqui ele está em execução:

As áreas de navegação e aside são renderizadas com um BoxView à esquerda e direita.


A primeira FlexLayout o XAML arquivo tem um eixo principal vertical e contém três filhos organizados em uma
coluna. Esses são o cabeçalho, o corpo da página e rodapé. Aninhada FlexLayout tem um eixo horizontal de
principal com três filhos organizados em uma linha.
Três propriedades vinculáveis anexadas são demonstradas neste programa:
O Order anexados a propriedade associável é definida no primeiro BoxView . Esta propriedade é um
inteiro com um valor padrão de 0. Você pode usar essa propriedade para alterar a ordem de layout.
Geralmente os desenvolvedores preferem o conteúdo da página apareça na marcação antes dos itens de
navegação e separar itens. Definindo o Order propriedade na primeira BoxView para um valor menor do
que seus outros irmãos faz com que ele seja exibido como o primeiro item na linha. Da mesma forma, você
pode garantir que um item é exibido por último, definindo o Order propriedade para um valor maior do
que seus irmãos.
O Basis anexados a propriedade associável é definida nos dois BoxView itens para fornecer a eles uma
largura de 50 pixels. Essa propriedade é do tipo FlexBasis , uma estrutura que define uma propriedade
estática do tipo FlexBasis denominado Auto , que é o padrão. Você pode usar Basis para especificar um
tamanho de pixel ou uma porcentagem que indica quanto espaço o item ocupa no eixo principal. Ele é
chamado uma base porque especifica um tamanho do item que é a base de layout subsequente.
O Grow propriedade é definida em aninhada Layout e, no Label filho que representa o conteúdo. Essa
propriedade é do tipo float e tem um valor padrão de 0. Quando definido como um valor positivo, todo
o espaço restante no eixo principal é alocado para esse item e irmãos com valores positivos de Grow . O
espaço é alocado proporcionalmente para os valores, um pouco semelhante a especificação de estrela em
um Grid .
A primeira Growpropriedade anexada é definida em aninhada FlexLayout , indicando que esse
FlexLayout é ocupar todo o espaço vertical não utilizado dentro externo FlexLayout . A segunda Grow
propriedade anexada é definida em de Label que representa o conteúdo, que indica que esse conteúdo é
ocupar todo o espaço horizontal não utilizado dentro interno FlexLayout .
Há também um semelhante Shrink anexados a propriedade associável que você pode usar quando o
tamanho dos filhos excede o tamanho do FlexLayout mas encapsulamento não for desejado.
Itens de catálogo com FlexLayout
O itens de catálogo página na FlexLayoutDemos exemplo é semelhante ao 1 do exemplo na seção 1.1 da
especificação CSS Flex Layout caixa, exceto pelo fato de que ele exibe uma série rolável horizontalmente de
imagens e descrições dos três Monkeys (Macacos):
Cada um de Monkeys três (Macacos) é um FlexLayout contido em um Frame que é determinado explícita de
altura e largura e que também é um filho de uma maior FlexLayout . Nesse arquivo XAML, a maioria das
propriedades do FlexLayout filhos são especificados em estilos, todos, exceto um dos quais é um estilo implícito:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:FlexLayoutDemos"
x:Class="FlexLayoutDemos.CatalogItemsPage"
Title="Catalog Items">
<ContentPage.Resources>
<Style TargetType="Frame">
<Setter Property="BackgroundColor" Value="LightYellow" />
<Setter Property="BorderColor" Value="Blue" />
<Setter Property="Margin" Value="10" />
<Setter Property="CornerRadius" Value="15" />
</Style>

<Style TargetType="Label">
<Setter Property="Margin" Value="0, 4" />
</Style>

<Style x:Key="headerLabel" TargetType="Label">


<Setter Property="Margin" Value="0, 8" />
<Setter Property="FontSize" Value="Large" />
<Setter Property="TextColor" Value="Blue" />
</Style>

<Style TargetType="Image">
<Setter Property="FlexLayout.Order" Value="-1" />
<Setter Property="FlexLayout.AlignSelf" Value="Center" />
</Style>

<Style TargetType="Button">
<Setter Property="Text" Value="LEARN MORE" />
<Setter Property="FontSize" Value="Large" />
<Setter Property="TextColor" Value="White" />
<Setter Property="BackgroundColor" Value="Green" />
<Setter Property="BorderRadius" Value="20" />
</Style>
</ContentPage.Resources>

<ScrollView Orientation="Both">
<FlexLayout>
<Frame WidthRequest="300"
HeightRequest="480">

<FlexLayout Direction="Column">
<Label Text="Seated Monkey"
Style="{StaticResource headerLabel}" />
<Label Text="This monkey is laid back and relaxed, and likes to watch the world go by."
/>
<Label Text=" &#x2022; Doesn't make a lot of noise" />
<Label Text=" &#x2022; Often smiles mysteriously" />
<Label Text=" &#x2022; Sleeps sitting up" />
<Image Source="{local:ImageResource FlexLayoutDemos.Images.SeatedMonkey.jpg}"
WidthRequest="180"
HeightRequest="180" />
<Label FlexLayout.Grow="1" />
<Button />
</FlexLayout>
</Frame>

<Frame WidthRequest="300"
HeightRequest="480">

<FlexLayout Direction="Column">
<Label Text="Banana Monkey"
Style="{StaticResource headerLabel}" />
<Label Text="Watch this monkey eat a giant banana." />
<Label Text=" &#x2022; More fun than a barrel of monkeys" />
<Label Text=" &#x2022; Banana not included" />
<Image Source="{local:ImageResource FlexLayoutDemos.Images.Banana.jpg}"
WidthRequest="240"
HeightRequest="180" />
<Label FlexLayout.Grow="1" />
<Button />
</FlexLayout>
</Frame>

<Frame WidthRequest="300"
HeightRequest="480">

<FlexLayout Direction="Column">
<Label Text="Face-Palm Monkey"
Style="{StaticResource headerLabel}" />
<Label Text="This monkey reacts appropriately to ridiculous assertions and actions." />
<Label Text=" &#x2022; Cynical but not unfriendly" />
<Label Text=" &#x2022; Seven varieties of grimaces" />
<Label Text=" &#x2022; Doesn't laugh at your jokes" />
<Image Source="{local:ImageResource FlexLayoutDemos.Images.FacePalm.jpg}"
WidthRequest="180"
HeightRequest="180" />
<Label FlexLayout.Grow="1" />
<Button />
</FlexLayout>
</Frame>
</FlexLayout>
</ScrollView>
</ContentPage>

O estilo implícito para o Image inclui as configurações de duas propriedades vinculáveis anexadas de Flexlayout
:

<Style TargetType="Image">
<Setter Property="FlexLayout.Order" Value="-1" />
<Setter Property="FlexLayout.AlignSelf" Value="Center" />
</Style>

O Order configuração do –1 faz com que o Image elemento a ser exibido pela primeira vez em cada uma das
aninhada FlexLayout modos de exibição, independentemente de sua posição dentro da coleção de filhos. O
AlignSelf propriedade de Center faz com que o Image centralizado dentro de FlexLayout . Isso substitui a
configuração do AlignItems propriedade, que tem um valor padrão de Stretch , o que significa que o Label e
Button filhos são ampliados para a largura total do FlexLayout .

Dentro de cada um dos três FlexLayout modos de exibição, um espaço em branco Label precede a Button , mas
tem um Grow configuração de 1. Isso significa que todo o espaço vertical extra é alocado para isso em branco
Label , que efetivamente envia a Button na parte inferior.

As propriedades vinculáveis em detalhes


Agora que você já viu alguns aplicativos comuns FlexLayout , as propriedades de FlexLayout podem ser
explorados mais detalhadamente. FlexLayout define seis propriedades vinculáveis definida para o FlexLayout
em si, em código ou XAML, a orientação do controle e o alinhamento. (Uma dessas propriedades, Position , não
é abordado neste artigo.)
Você pode fazer experiências com cinco restantes propriedades vinculáveis usando o experiências página do
FlexLayoutDemos exemplo. Esta página permite que você adicione ou remova os filhos de um FlexLayout e
definir combinações das cinco propriedades associáveis. Todos os filhos do FlexLayout estão Label modos de
exibição de várias cores e tamanhos, com o Text propriedade definida como um número correspondente à sua
posição no Children coleção.
Quando o programa for iniciado, cinco Picker modos de exibição exibem os valores padrão desses cinco
FlexLayout propriedades. O FlexLayout na parte inferior da tela contém três filhos:

Cada um dos Label modos de exibição tem um plano de fundo cinza que mostra o espaço alocado para que
Label dentro de FlexLayout . Plano de fundo do FlexLayout em si é azul-bebê. Ele ocupa a área inteira inferior
da página, exceto para uma pequena margem à esquerda e direita.
A propriedade de direção
O Direction propriedade é do tipo FlexDirection , uma enumeração com quatro membros:
Column
ColumnReverse (ou "reversão de coluna" em XAML )
Row , o padrão
RowReverse (ou "reversão de linha" em XAML )

No XAML, você pode especificar o valor dessa propriedade usando os nomes de membro de enumeração em
letras minúsculas, letras maiusculas, ou maiusculas e minúsculas, ou você pode usar duas cadeias de caracteres
adicionais entre parênteses são os mesmos que os indicadores CSS. (As cadeias de caracteres "coluna inverso" e
"linha reversão" são definidas na FlexDirectionTypeConverter classe usada pelo analisador XAML.)
Aqui está o experimento página mostrando (da esquerda para a direita), o Row direção, Column direção, e
ColumnReverse direção:
Observe que para o Reverse opções, os itens iniciam na parte direita ou inferior.
A propriedade de quebra automática de linha
O Wrap propriedade é do tipo FlexWrap , uma enumeração com três membros:
NoWrap , o padrão
Wrap
Reverse (ou "reversão de quebra automática de linha" em XAML )

Da esquerda para direita, essas telas mostram a NoWrap , Wrap e Reverse opções para os filhos de 12:

Quando o Wrap estiver definida como NoWrap eixo principal é restrito (como esse programa) e o eixo principal
não está altas ou largas o suficiente para se ajustar todos os filhos, o FlexLayout faz com que os itens de menor,
como a captura de tela do iOS Demonstra. Você pode controlar o shrinkness dos itens com o Shrink
propriedade associável anexada.
A propriedade JustifyContent
O JustifyContent propriedade é do tipo FlexJustify , uma enumeração com seis membros:
Start (ou "flex-start" em XAML ), o padrão
Center
End (ou "flex-end" em XAML )
SpaceBetween (ou "espaço-entre" em XAML )
SpaceAround (ou "espaço-around" em XAML )
SpaceEvenly

Esta propriedade especifica como os itens são espaçados no eixo principal, que é o eixo horizontal neste exemplo:

Em todos os três capturas de tela, o Wrap estiver definida como Wrap . O Start padrão é mostrado na captura
de tela Android anterior. Mostra a captura de tela do iOS aqui o Center opção: todos os itens são movidos para o
centro. As três outras opções começando com a palavra Space alocar o espaço extra não ocupado pelos itens.
SpaceBetween aloca o espaço igualmente entre os itens; SpaceAround puts igual espaço ao redor de cada item,
enquanto SpaceEvenly puts igual espaço entre cada item e antes do primeiro item e depois do último item na
linha.
A propriedade AlignItems
O AlignItems propriedade é do tipo FlexAlignItems , uma enumeração com quatro membros:
Stretch , o padrão
Center
Start (ou "flex-start" em XAML )
End (ou "flex-end" em XAML )

Essa é uma das duas propriedades (o outro sendo AlignContent ) que indica como os filhos são alinhados no eixo
transversal. Em cada linha, os filhos são alongados (conforme mostrado na captura de tela anterior) ou alinhados
no início, centro ou final de cada item, conforme mostrado nas capturas de três tela seguintes:
A captura de tela do iOS, as partes superiores de todos os filhos são alinhadas. No Android capturas de tela, os
itens são centralizados verticalmente com base no filho mais alto. A captura de tela de UWP, a parte inferior de
todos os itens é alinhados.
Para qualquer item individual, o AlignItems configuração pode ser substituída com o AlignSelf propriedade
associável anexada.
A propriedade AlignContent
O AlignContent propriedade é do tipo FlexAlignContent , uma enumeração com sete membros:
Stretch , o padrão
Center
Start (ou "flex-start" em XAML )
End (ou "flex-end" em XAML )
SpaceBetween (ou "espaço-entre" em XAML )
SpaceAround (ou "espaço-around" em XAML )
SpaceEvenly

Como o AlignItems , o AlignContent propriedade também alinha filhos no eixo transversal, mas afeta linhas ou
colunas inteiras:

A captura de tela do iOS, ambas as linhas estão na parte superior; na captura de tela Android está no Centro de; e
a captura de tela de UWP que eles estão na parte inferior. As linhas também podem ser espaçadas de várias
maneiras:

O AlignContent não tem nenhum efeito quando há apenas uma linha ou coluna.

As propriedades anexadas associáveis em detalhes


FlexLayout define cinco propriedades vinculáveis anexadas. Essas propriedades são definidas nos filhos do
FlexLayout e só pertencem a esse filho específico.
A propriedade AlignSelf
O AlignSelf anexados a propriedade associável é do tipo FlexAlignSelf , uma enumeração com cinco membros:
Auto , o padrão
Stretch
Center
Start (ou "flex-start" em XAML )
End (ou "flex-end" em XAML )

Para qualquer filho individual do FlexLayout , essa propriedade substituirá o AlignItems propriedade definida no
FlexLayout em si. A configuração padrão de Auto significa usar o AlignItems configuração.

Para um Label elemento denominado label (ou exemplo), você pode definir o AlignSelf propriedade no
código como este:

FlexLayout.SetAlignSelf(label, FlexAlignSelf.Center);

Observe que não há nenhuma referência para o FlexLayout pai do Label . No XAML, você definir a propriedade
como este:

<Label ... FlexLayout.AlignSelf="Center" ... />

A propriedade de ordem
O Order propriedade é do tipo int . O valor padrão é 0.
O Order propriedade permite que você altere a ordem que os filhos do FlexLayout são organizados.
Normalmente, os filhos de um FlexLayout são organizados é a mesma ordem que aparecem no Children
coleção. Você pode substituir essa ordem, definindo o Order propriedade associável anexada a um valor inteiro
diferente de zero em uma ou mais filhos. O FlexLayout , em seguida, organiza seus filhos com base na
configuração do Order propriedade em cada filho, mas filhos com o mesmo Order configuração são
organizados na ordem em que aparecem no Children coleção.
A propriedade de base
O Basis anexados a propriedade associável indica a quantidade de espaço é alocado para um filho do
FlexLayout no eixo principal. O tamanho especificado o Basis propriedade é o tamanho ao longo do eixo
principal do pai FlexLayout . Portanto, Basis indica a largura de um filho quando os filhos são organizados em
linhas ou a altura, quando os filhos são organizados em colunas.
O Basis propriedade é do tipo FlexBasis , uma estrutura. O tamanho pode ser especificado em qualquer um
dos unidades independentes de dispositivo ou como uma porcentagem do tamanho do FlexLayout . O valor
padrão de Basis é a propriedade estática FlexBasis.Auto , o que significa que o filho solicitado pelo largura ou
altura é usada.
No código, você pode definir as Basis propriedade para um Label denominado label para 40 unidades
independentes de dispositivo como este:

FlexLayout.SetBasis(label, new FlexBasis(40, false));

O segundo argumento para o FlexBasis construtor é chamado isRelative e indica se o tamanho é relativo (
true ) ou absoluto ( false ). O argumento tem um valor padrão de false , portanto, você também pode usar o
código a seguir:

FlexLayout.SetBasis(label, new FlexBasis(40));

Uma conversão implícita da float para FlexBasis for definida, portanto, você pode simplificar ainda mais:

FlexLayout.SetBasis(label, 40);

Você pode definir o tamanho para 25% do FlexLayout pai como este:

FlexLayout.SetBasis(label, new FlexBasis(0.25f, true));

Esse valor fracionário deve estar no intervalo de 0 a 1.


No XAML, você pode usar um número para um tamanho em unidades independentes de dispositivo:

<Label ... FlexLayout.Basis="40" ... />

Ou você pode especificar uma porcentagem do intervalo de 0 a 100%:

<Label ... FlexLayout.Basis="25%" ... />

O base experiências página do FlexLayoutDemos amostra permite que você experimentar o Basis
propriedade. A página exibe uma coluna encapsulada de cinco Label elementos com alternando as cores de
primeiro plano e plano de fundo. Duas Slider elementos permitem que você especifique Basis valores para o
segundo e quarto Label :
A captura de tela do iOS à esquerda mostra os dois Label elementos que estão sendo fornecidos alturas em
unidades independentes de dispositivo. A tela Android mostra-las sendo dada alturas menos da metade da altura
total do FlexLayout . Se o Basis é definida em 100%, em seguida, o filho é a altura do FlexLayout e passe para a
próxima coluna e ocupa toda a altura da coluna, como demonstra a captura de tela UWP: Ele aparece como se os
filhos de cinco são organizados em uma linha, mas, na verdade, são dispostos em cinco colunas.
A propriedade de crescimento
O Grow anexados a propriedade associável é do tipo int . O valor padrão é 0 e o valor deve ser maior que ou
igual a 0.
O Grow propriedade desempenha um papel quando o Wrap estiver definida como NoWrap e a linha de filhos
tem uma largura total menor que a largura do FlexLayout , ou a coluna de filhos tem uma altura menor que o
FlexLayout . O Grow propriedade indica como distribuir o espaço entre os filhos.

No experimento crescer página cinco Label elementos de cores alternadas são organizados em uma coluna e
dois Slider elementos permitem que você ajuste a Grow propriedade do segundo e quarto Label . A captura de
tela do iOS na extremidade esquerda mostra o padrão Grow propriedades 0:

Se qualquer um filho é fornecido um positivo Grow de valor, em seguida, esse filho ocupa todo o espaço restante,
como demonstra a captura de tela do Android. Esse espaço também pode ser alocado entre dois ou mais filhos. A
captura de tela de UWP, o Grow propriedade da segunda Label é definido como 0,5, enquanto o Grow
propriedade do quarto Label é 1.5, que fornece a quarta Label três vezes mais do espaço de sobra como o
segundo Label .
Como o modo de exibição filho usa esse espaço depende do tipo específico de filho. Para um Label , o texto pode
ser posicionado dentro do espaço total do Label usando as propriedades HorizontalTextAlignment e
VerticalTextAlignment .

A propriedade de redução
O Shrink anexados a propriedade associável é do tipo int . O valor padrão é 1, e o valor deve ser maior que ou
igual a 0.
O Shrink propriedade desempenha um papel quando o Wrap estiver definida como NoWrap e a largura de
agregação de uma linha de filhos é maior que a largura do FlexLayout , ou a altura de agregação de uma única
coluna de filhos é maior que o altura do FlexLayout . Normalmente o FlexLayout exibirá esses filhos por
constricting seus tamanhos. O Shrink propriedade pode indicar quais filhas recebem prioridade em que estão
sendo exibidos com seus tamanhos completos.
O reduzir experimento página cria uma FlexLayout com uma única linha de cinco Label filhos que exigem
mais espaço do que o FlexLayout largura. A captura de tela do iOS à esquerda mostra todos os Label
elementos com os valores padrão de 1:

Na captura de tela Android, o Shrink valor para a segunda Label é definido como 0 e que Label é exibido na
sua largura completa. Além disso, o quarto Label recebe um Shrink valor maior do que um e, em seguida, ele
foi reduzido. Mostra a captura de tela UWP Label elementos que estão sendo fornecidos um Shrink valor de 0
para permitir que sejam exibidos em seu tamanho completo, se isso for possível.
Você pode definir ambos os Grow e Shrink valores para adaptar a situações em que os tamanhos de agregação
filho, às vezes, podem ser menor que ou às vezes maior que o tamanho do FlexLayout .

Estilos da CSS com FlexLayout


Você pode usar o estilos da CSS foram recurso introduzido com o xamarin. Forms 3.0 na conexão com
FlexLayout . O itens de catálogo de CSS página do FlexLayoutDemos exemplo duplica o layout do itens de
catálogo página, mas com CSS folha de estilos para muitos dos estilos:
O original CatalogItemsPage.xaml arquivo tem cinco Style definições em seu Resources seção com 15
Setter objetos. No CssCatalogItemsPage.xaml arquivo, que foi reduzido para dois Style definições com
apenas quatro Setter objetos. Esses estilos complementam a folha de estilos CSS para propriedades que o
recurso de estilo CSS do xamarin. Forms atualmente não dá suporte:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:FlexLayoutDemos"
x:Class="FlexLayoutDemos.CssCatalogItemsPage"
Title="CSS Catalog Items">
<ContentPage.Resources>
<StyleSheet Source="CatalogItemsStyles.css" />

<Style TargetType="Frame">
<Setter Property="BorderColor" Value="Blue" />
<Setter Property="CornerRadius" Value="15" />
</Style>

<Style TargetType="Button">
<Setter Property="Text" Value="LEARN MORE" />
<Setter Property="BorderRadius" Value="20" />
</Style>
</ContentPage.Resources>

<ScrollView Orientation="Both">
<FlexLayout>
<Frame>
<FlexLayout Direction="Column">
<Label Text="Seated Monkey" StyleClass="header" />
<Label Text="This monkey is laid back and relaxed, and likes to watch the world go by."
/>
<Label Text=" &#x2022; Doesn't make a lot of noise" />
<Label Text=" &#x2022; Often smiles mysteriously" />
<Label Text=" &#x2022; Sleeps sitting up" />
<Image Source="{local:ImageResource FlexLayoutDemos.Images.SeatedMonkey.jpg}" />
<Label StyleClass="empty" />
<Button />
</FlexLayout>
</Frame>

<Frame>
<FlexLayout Direction="Column">
<Label Text="Banana Monkey" StyleClass="header" />
<Label Text="Watch this monkey eat a giant banana." />
<Label Text=" &#x2022; More fun than a barrel of monkeys" />
<Label Text=" &#x2022; Banana not included" />
<Image Source="{local:ImageResource FlexLayoutDemos.Images.Banana.jpg}" />
<Label StyleClass="empty" />
<Button />
</FlexLayout>
</Frame>

<Frame>
<FlexLayout Direction="Column">
<Label Text="Face-Palm Monkey" StyleClass="header" />
<Label Text="This monkey reacts appropriately to ridiculous assertions and actions." />
<Label Text=" &#x2022; Cynical but not unfriendly" />
<Label Text=" &#x2022; Seven varieties of grimaces" />
<Label Text=" &#x2022; Doesn't laugh at your jokes" />
<Image Source="{local:ImageResource FlexLayoutDemos.Images.FacePalm.jpg}" />
<Label StyleClass="empty" />
<Button />
</FlexLayout>
</Frame>
</FlexLayout>
</ScrollView>
</ContentPage>

A folha de estilos CSS é referenciada na primeira linha do Resources seção:


<StyleSheet Source="CatalogItemsStyles.css" />

Observe também que dois elementos em cada um dos três itens a incluem StyleClass configurações:

<Label Text="Seated Monkey" StyleClass="header" />


···
<Label StyleClass="empty" />

Elas fazem referência a seletores de CatalogItemsStyles.css folha de estilos:

frame {
width: 300;
height: 480;
background-color: lightyellow;
margin: 10;
}

label {
margin: 4 0;
}

label.header {
margin: 8 0;
font-size: large;
color: blue;
}

label.empty {
flex-grow: 1;
}

image {
height: 180;
order: -1;
align-self: center;
}

button {
font-size: large;
color: white;
background-color: green;
}

Vários FlexLayout propriedades vinculáveis anexadas são referenciadas aqui. No label.empty seletor, você verá
o flex-grow atributo, que define o estilo vazio Label para fornecer um espaço em branco acima a Button . O
image seletor contém um order atributo e um align-self atributo, que correspondem aos FlexLayout
associáveis propriedades anexadas.
Você já viu que você pode definir propriedades diretamente na FlexLayout e você pode definir propriedades
vinculáveis anexadas nos filhos de um FlexLayout . Ou, você pode definir essas propriedades indiretamente
usando estilos tradicionais baseado em XAML ou estilos CSS. O importante é saber e compreender essas
propriedades. Essas propriedades são o que torna o FlexLayout realmente flexível.

FlexLayout com Xamarin.University


Xamarin. Forms 3.0 Flex Layout, por Xamarin University
Links relacionados
FlexLayoutDemos
Xamarin. Forms ScrollView
12/04/2019 • 6 minutes to read

baixar o exemplo
ScrollView contém layouts e permite que eles para fora da tela de rolagem. ScrollView também é usado para
permitir que os modos de exibição mover automaticamente para a parte visível da tela quando o teclado está
mostrando.

Este artigo aborda:


Finalidade – a finalidade de ScrollView e quando ele é usado.
Uso – como usar ScrollView na prática.
As propriedades – propriedades públicas que podem ser lidos e modificadas.
Métodos – métodos públicos que podem ser chamados para rolar a exibição.
Eventos – eventos que podem ser usados para ouvir as alterações nos Estados da exibição.

Finalidade
ScrollView pode ser usado para garantir que os modos de exibição maiores exibem bem em telefones menores.
Por exemplo, um layout que funciona em um iPhone 6s poderão ser cortado em um iPhone 4s. Usando um
ScrollView permitiria que as partes recortadas do layout a ser exibido na tela menor.

Uso
NOTE
ScrollView s não devem ser aninhados. Além disso, ScrollView s não devem ser aninhados com outros controles que
fornecem a rolagem, como ListView e WebView .

ScrollView expõe um Content propriedade que pode ser definida como um único modo de exibição ou layout.
Considere este exemplo de um layout com um boxView muito grande, seguido por um Entry :

<ContentPage.Content>
<ScrollView>
<StackLayout>
<BoxView BackgroundColor="Red" HeightRequest="600" WidthRequest="150" />
<Entry />
</StackLayout>
</ScrollView>
</ContentPage.Content>
No C#:

var scroll = new ScrollView();


Content = scroll;
var stack = new StackLayout();
stack.Children.Add(new BoxView { BackgroundColor = Color.Red, HeightRequest = 600, WidthRequest = 600 });
stack.Children.Add(new Entry());

Antes do usuário rola para baixo, apenas o BoxView está visível:

Observe que, quando o usuário começa a inserir texto no Entry , o modo de exibição rola para mantê-lo visível na
tela:
Propriedades
ScrollView Define as propriedades a seguir:
ContentSize Obtém uma Size valor que representa o tamanho do conteúdo.
Orientation Obtém ou define um ScrollOrientation valor de enumeração que representa a direção de
rolagem do ScrollView .
ScrollX Obtém um double que representa a atual posição de rolagem X.
ScrollY Obtém um double que representa a atual posição de rolagem de Y.
HorizontalScrollBarVisibility Obtém ou define um ScrollBarVisibility valor que representa quando a
barra de rolagem horizontal está visível.
VerticalScrollBarVisibility Obtém ou define um ScrollBarVisibility valor que representa quando a barra
de rolagem vertical está visível.

Métodos
ScrollView Fornece um ScrollToAsync método, que pode ser usado para rolar a exibição usando coordenadas
ou ao especificar um modo de exibição específico que deve ficar visível.
Ao usar coordenadas, especifique o x e y coordenadas, juntamente com um valor booliano que indica se a
rolagem deve ser animada:

scroll.ScrollToAsync(0, 150, true); //scrolls so that the position at 150px from the top is visible

scroll.ScrollToAsync(label, ScrollToPosition.Start, true); //scrolls so that the label is at the start of the
list
Durante a rolagem para um elemento específico, o ScrollToPosition Especifica enumeração onde no modo de
exibição do elemento será exibido:
Centro – rola o elemento para o centro da parte visível da exibição.
Término – rola o elemento ao final da parte visível da exibição.
MakeVisible – rola o elemento para que ele fique visível dentro da exibição.
Inicie – rola o elemento ao início da parte visível da exibição.
O IsAnimated propriedade especifica como o modo de exibição será rolado. Quando definido como true, uma
animação suave será usado, em vez de instantaneamente movendo o conteúdo no modo de exibição.

Eventos
ScrollView define apenas um evento, Scrolled . Scrolled é gerado quando o modo de exibição terminou de
rolagem. Manipulador de eventos do Scrolled leva ScrolledEventArgs , que tem o ScrollX e ScrollY
propriedades. A seguir demonstra como atualizar um rótulo com a atual posição de rolagem de um ScrollView :

Label label = new Label { Text = "Position: " };


ScrollView scroll = new ScrollView();
scroll.Scrolled += (object sender, ScrolledEventArgs e) => {
label.Text = "Position: " + e.ScrollX + " x " + e.ScrollY;
};

Observe que as posições de rolagem podem ser negativas, devido ao efeito de devolução durante a rolagem no
final de uma lista.

Links relacionados
Layout (amostra)
Exemplo de BusinessTumble (amostra)
Opções de layout no xamarin. Forms
12/04/2019 • 10 minutes to read

baixar o exemplo
Cada modo de exibição do xamarin. Forms tem as propriedades HorizontalOptions e propriedades
VerticalOptions, do tipo LayoutOptions. Este artigo explica o efeito que cada valor LayoutOptions tem sobre o
alinhamento e a expansão de um modo de exibição.

Visão geral
O LayoutOptions estrutura encapsula duas as preferências de layout:
Alinhamento – o modo de exibição preferencial do alinhamento, que determina sua posição e tamanho
dentro do seu layout pai.
Expansão – usada somente por um StackLayout e indica se o modo de exibição deve usar o espaço extra, se
ele estiver disponível.
Essas preferências de layout podem ser aplicadas a um View , em relação a seu pai, definindo o
HorizontalOptions ou VerticalOptions propriedade das View dentre os campos públicos do LayoutOptions
estrutura. Os campos públicos são da seguinte maneira:
Start
Center
End
Fill
StartAndExpand
CenterAndExpand
EndAndExpand
FillAndExpand

O Start , Center , End ,e Fill campos são usados para definir o alinhamento do modo de exibição do layout do
pai:
Para alinhamento horizontal, Start posições a View no lado esquerdo do layout pai e o alinhamento vertical,
ela posiciona o View na parte superior das layout pai.
Para o alinhamento horizontal e vertical, Center horizontal ou verticalmente centraliza as View .
Para o alinhamento horizontal, End posições a View no lado direito do layout pai e o alinhamento vertical, ela
posiciona o View na parte inferior do layout pai.
Para o alinhamento horizontal, Fill garante que o View preenche a largura do layout pai e o alinhamento
vertical, garante que o View preenche o altura do layout pai.
O StartAndExpand , CenterAndExpand , EndAndExpand , e FillAndExpand valores são usados para definir a preferência
de alinhamento, e se o modo de exibição será ocupam mais espaço, se disponível dentro do pai StackLayout .

NOTE
O valor padrão de um modo de exibição HorizontalOptions e VerticalOptions propriedades é LayoutOptions.Fill .
Alinhamento
Alinhamento de controles como um modo de exibição é posicionado dentro de seu layout pai quando o layout pai
contém espaço não utilizado (ou seja, o layout do pai é maior do que o tamanho combinado de todos os seus
filhos).
Um StackLayout somente respeita o Start , Center , End , e Fill LayoutOptions campos em modos de exibição
filho que estão na direção oposta para o StackLayout orientação. Portanto, o filho exibições dentro de uma
orientação vertical StackLayout pode definir seus HorizontalOptions as propriedades para um dos Start ,
Center , End , ou Fill campos. Da mesma forma, o filho exibições dentro de uma orientação horizontal
StackLayout pode definir seus VerticalOptions as propriedades para um dos Start , Center , End , ou Fill
campos.
Um StackLayout não respeita a Start , Center , End , e Fill LayoutOptions campos em modos de exibição filho
que estão na mesma direção o StackLayout orientação. Portanto, uma orientação vertical StackLayout ignora os
Start , Center , End , ou Fill campos se eles são definidos na VerticalOptions propriedades de exibições filho.
Da mesma forma, um orientado horizontalmente StackLayout ignora os Start , Center , End , ou Fill campos
se elas são definidas no HorizontalOptions propriedades de exibições filho.

NOTE
LayoutOptions.Fill geralmente substituições dimensionar solicitações especificadas usando o HeightRequest e
WidthRequest propriedades.

O exemplo de código XAML a seguir demonstra uma orientação vertical StackLayout onde cada filho Label
define seu HorizontalOptions propriedade para um dos campos de alinhamento de quatro a LayoutOptions
estrutura:

<StackLayout Margin="0,20,0,0">
...
<Label Text="Start" BackgroundColor="Gray" HorizontalOptions="Start" />
<Label Text="Center" BackgroundColor="Gray" HorizontalOptions="Center" />
<Label Text="End" BackgroundColor="Gray" HorizontalOptions="End" />
<Label Text="Fill" BackgroundColor="Gray" HorizontalOptions="Fill" />
</StackLayout>

O código c# equivalente é mostrado abaixo:

Content = new StackLayout


{
Margin = new Thickness(0, 20, 0, 0),
Children = {
...
new Label { Text = "Start", BackgroundColor = Color.Gray, HorizontalOptions = LayoutOptions.Start },
new Label { Text = "Center", BackgroundColor = Color.Gray, HorizontalOptions = LayoutOptions.Center },
new Label { Text = "End", BackgroundColor = Color.Gray, HorizontalOptions = LayoutOptions.End },
new Label { Text = "Fill", BackgroundColor = Color.Gray, HorizontalOptions = LayoutOptions.Fill }
}
};

O código resulta no layout mostrado nas capturas de tela seguir:


Expansão
Expansão controla se um modo de exibição ocupará mais espaço, se disponível, dentro de um StackLayout . Se o
StackLayout contém espaço não utilizado (ou seja, o StackLayout é maior do que o tamanho combinado de
todos os seus filhos), o espaço não utilizado é compartilhado igualmente por todas as exibições filho que solicitam
a expansão, definindo suas HorizontalOptions ou VerticalOptions propriedades para um LayoutOptions campo
que usa o AndExpand sufixo. Observe que, quando todo o espaço no StackLayout é usado, as opções de expansão
não têm nenhum efeito.
Um StackLayout só pode expandir os modos de exibição filho na direção de sua orientação. Portanto, uma
orientação vertical StackLayout pode expandir os modos de exibição filho que definirem seus VerticalOptions
propriedades para um dos StartAndExpand , CenterAndExpand , EndAndExpand , ou FillAndExpand campos, se o
StackLayout contém espaço não utilizado. Da mesma forma, um orientado horizontalmente StackLayout pode
expandir os modos de exibição filho definirem seus HorizontalOptions propriedades para um da StartAndExpand ,
CenterAndExpand , EndAndExpand , ou FillAndExpand campos, se o StackLayout contém espaço não utilizado.

Um StackLayout não é possível expandir os modos de exibição filho na direção oposta à sua orientação. Portanto,
na orientação vertical StackLayout , definindo o HorizontalOptions propriedade em um modo de exibição filho
StartAndExpand tem o mesmo efeito que definir a propriedade como Start .

NOTE
Observe que habilitar a expansão não altera o tamanho de um modo de exibição, a menos que ele usa
LayoutOptions.FillAndExpand .

O exemplo de código XAML a seguir demonstra uma orientação vertical StackLayout onde cada filho Label
define seu VerticalOptions propriedade para um dos campos de expansão de quatro a LayoutOptions estrutura:
<StackLayout Margin="0,20,0,0">
...
<BoxView BackgroundColor="Red" HeightRequest="1" />
<Label Text="Start" BackgroundColor="Gray" VerticalOptions="StartAndExpand" />
<BoxView BackgroundColor="Red" HeightRequest="1" />
<Label Text="Center" BackgroundColor="Gray" VerticalOptions="CenterAndExpand" />
<BoxView BackgroundColor="Red" HeightRequest="1" />
<Label Text="End" BackgroundColor="Gray" VerticalOptions="EndAndExpand" />
<BoxView BackgroundColor="Red" HeightRequest="1" />
<Label Text="Fill" BackgroundColor="Gray" VerticalOptions="FillAndExpand" />
<BoxView BackgroundColor="Red" HeightRequest="1" />
</StackLayout>

O código c# equivalente é mostrado abaixo:

Content = new StackLayout


{
Margin = new Thickness(0, 20, 0, 0),
Children = {
...
new BoxView { BackgroundColor = Color.Red, HeightRequest = 1 },
new Label { Text = "StartAndExpand", BackgroundColor = Color.Gray, VerticalOptions =
LayoutOptions.StartAndExpand },
new BoxView { BackgroundColor = Color.Red, HeightRequest = 1 },
new Label { Text = "CenterAndExpand", BackgroundColor = Color.Gray, VerticalOptions =
LayoutOptions.CenterAndExpand },
new BoxView { BackgroundColor = Color.Red, HeightRequest = 1 },
new Label { Text = "EndAndExpand", BackgroundColor = Color.Gray, VerticalOptions =
LayoutOptions.EndAndExpand },
new BoxView { BackgroundColor = Color.Red, HeightRequest = 1 },
new Label { Text = "FillAndExpand", BackgroundColor = Color.Gray, VerticalOptions =
LayoutOptions.FillAndExpand },
new BoxView { BackgroundColor = Color.Red, HeightRequest = 1 }
}
};

O código resulta no layout mostrado nas capturas de tela seguir:


Cada Label ocupa a mesma quantidade de espaço dentro de StackLayout . No entanto, somente o último Label
, que define seu VerticalOptions propriedade a ser FillAndExpand tem um tamanho diferente. Além disso, cada
Label é separado por um pequeno vermelho BoxView , que permite que o espaço de Label ocupa para ser
facilmente exibidos.

Resumo
Este artigo explicou o efeito que cada LayoutOptions valor estrutura tem sobre o alinhamento e a expansão de
uma exibição, relativo ao seu pai. O Start , Center , End , e Fill campos são usados para definir o alinhamento
do modo de exibição do layout do pai e o StartAndExpand , CenterAndExpand , EndAndExpand , e FillAndExpand
campos são usados para definir a preferência de alinhamento e para determinar se o modo de exibição ocupará
mais espaço, se disponível, dentro de um StackLayout .

Links relacionados
LayoutOptions (amostra)
LayoutOptions
Margem e preenchimento
12/04/2019 • 3 minutes to read

A margem e preenchimento propriedades controlam o comportamento de layout quando um elemento é


renderizado na interface do usuário. Este artigo demonstra a diferença entre as duas propriedades e como
defini-las.

Visão geral
Margem e preenchimento são conceitos relacionados de layout:
O Margin propriedade representa a distância entre um elemento e seus elementos adjacentes e é usada para
controlar a posição de renderização do elemento e a posição de renderização de seus vizinhos. Margin
valores podem ser especificados em layout e exibição classes.
O Padding propriedade representa a distância entre um elemento e seus elementos filho e é usada para
separar o controle de seu próprio conteúdo. Padding valores podem ser especificados em layout classes.

O diagrama a seguir ilustra os dois conceitos:

Observe que Margin valores são aditivas. Portanto, se dois elementos adjacentes especificam uma margem de
20 pixels, a distância entre os elementos será 40 pixels. Além disso, margem e preenchimento são aditivos,
quando ambos são aplicadas, em que a distância entre um elemento e qualquer conteúdo será a margem e
preenchimento.
Especifica uma espessura
O Margin e Padding propriedades forem do tipo Thickness . Existem três possibilidades durante a criação de
um Thickness estrutura:
Criar uma Thickness estrutura definida por um único valor uniforme. O valor único é aplicado para a
esquerda, superior, direita e lados da parte inferior do elemento.
Criar uma Thickness estrutura definida pelos valores horizontais e verticais. O valor horizontal é aplicado
simetricamente para os lados esquerdo e direito do elemento, com o valor vertical que está sendo aplicado
simetricamente para os lados superior e inferior do elemento.
Criar uma Thickness estrutura definida por quatro valores distintos que são aplicados para a esquerda,
superior, direita e lados da parte inferior do elemento.
O exemplo de código XAML a seguir mostra todas as três possibilidades:

<StackLayout Padding="0,20,0,0">
<Label Text="Xamarin.Forms" Margin="20" />
<Label Text="Xamarin.iOS" Margin="10, 15" />
<Label Text="Xamarin.Android" Margin="0, 20, 15, 5" />
</StackLayout>

O código C# equivalente é mostrado no exemplo de código a seguir:

var stackLayout = new StackLayout {


Padding = new Thickness(0,20,0,0),
Children = {
new Label { Text = "Xamarin.Forms", Margin = new Thickness (20) },
new Label { Text = "Xamarin.iOS", Margin = new Thickness (10, 25) },
new Label { Text = "Xamarin.Android", Margin = new Thickness (0, 20, 15, 5) }
}
};

NOTE
Thickness valores podem ser negativos, que normalmente recorta ou overdraws o conteúdo.

Resumo
Este artigo demonstrou a diferença entre o Margin e Padding propriedades e como defini-las. As propriedades
controlam o comportamento de layout quando um elemento é renderizado na interface do usuário.

Links relacionados
Margem
Preenchimento
Espessura
Orientação do dispositivo
12/04/2019 • 18 minutes to read

baixar o exemplo
É importante considerar como seu aplicativo será usado e como orientação paisagem pode ser incorporada para
melhorar a experiência do usuário. Layouts individuais podem ser projetados para acomodar várias orientações e
melhor usa o espaço disponível. No nível do aplicativo, rotação pode ser desabilitada ou habilitada.

Controlando a orientação
Ao usar o xamarin. Forms, o método com suporte de controlar a orientação do dispositivo é usar as configurações
para cada projeto individual.
iOS
No iOS, a orientação do dispositivo está configurada para aplicativos que usam o Info. plist arquivo. Esse arquivo
incluirá as configurações de orientação para iPhone e iPod, bem como configurações para iPad, se o aplicativo
inclui-lo como um destino. A seguir estão as instruções específicas para seu IDE. Use as opções de IDE na parte
superior deste documento para selecionar quais instruções que você gostaria de ver:
Visual Studio
Visual Studio para Mac
No Visual Studio, abra o projeto do iOS e abra Info. plist. O arquivo será aberto em um painel de configuração,
começando com o guia de informações de implantação do iPhone:

Para configurar a orientação do iPad, selecione a informações de implantação do iPad guia na parte superior
esquerda do painel, em seguida, selecione das orientações disponíveis:
Android
Para controlar a orientação no Android, abra MainActivity.cs e defina a orientação usando o atributo decorar o
MainActivity classe:

namespace MyRotatingApp.Droid
{
[Activity (Label = "MyRotatingApp.Droid", Icon = "@drawable/icon", Theme = "@style/MainTheme",
MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation,
ScreenOrientation = ScreenOrientation.Landscape)] //This is what controls orientation
public class MainActivity : FormsAppCompatActivity
{
protected override void OnCreate (Bundle bundle)
...

Xamarin. Android dá suporte a várias opções para especificar a orientação:


Paisagem – força a orientação do aplicativo para ser paisagem, independentemente dos dados do sensor.
Retrato – força a orientação do aplicativo para ser retrato, independentemente dos dados do sensor.
Usuário – faz com que o aplicativo a ser apresentada usando a orientação de preferência do usuário.
Por trás – faz com que a orientação do aplicativo ser o mesmo que a orientação do atividade por trás dele.
Sensor – faz com que a orientação do aplicativo seja determinado pelo sensor, mesmo se o usuário tiver
desabilitado a rotação automática.
SensorLandscape – faz com que o aplicativo para usar a orientação de paisagem durante o uso de dados de
sensor para alterar a direção em que a tela é voltado para a (de modo que a tela não é vista como cabeça para
baixo).
SensorPortrait – faz com que o aplicativo para usar a orientação de retrato durante o uso de dados de sensor
para alterar a direção em que a tela é voltado para a (de modo que a tela não é vista como cabeça para baixo).
ReverseLandscape – faz com que o aplicativo para usar a orientação paisagem, voltado para a direção oposta
usual para aparecer "cabeça para baixo."
ReversePortrait – faz com que o aplicativo para usar a orientação retrato, voltado para a direção oposta usual
para aparecer "cabeça para baixo."
FullSensor – faz com que o aplicativo se baseiam nos dados de sensor para selecionar a orientação correta
(fora de 4 a possíveis).
FullUser – faz com que o aplicativo para usar as preferências do usuário orientação. Se a rotação automática
estiver habilitada, todas as 4 orientações podem ser usadas.
UserLandscape – [Nepodporuje] faz com que o aplicativo para usar a orientação paisagem, a menos que o
usuário tenha a rotação automática habilitada, caso em que ele usará o sensor para determinar a orientação.
Esta opção interromperá a compilação.
UserPortrait – [Nepodporuje] faz com que o aplicativo para usar a orientação retrato, a menos que o usuário
tenha a rotação automática habilitada, caso em que ele usará o sensor para determinar a orientação. Esta
opção interromperá a compilação.
Bloqueado – [não tem suporte] faz com que o aplicativo para usar a orientação da tela física que quer que seja
no lançamento, sem responder a alterações no dispositivo do orientação. Esta opção interromperá a
compilação.
Observe que as APIs do Android nativos fornecem muito controle sobre como a orientação é gerenciada,
incluindo as opções que contradizem explicitamente o usuário expresso preferências.
Plataforma universal do Windows
Na Universal Windows Platform (UWP ), as orientações com suporte são definidas Package. appxmanifest
arquivo. Abrir o manifesto irá revelar um painel de configuração onde as orientações com suporte podem ser
selecionadas.

Reagir a alterações na orientação


Xamarin. Forms não oferece quaisquer eventos nativos para notificar seu aplicativo de alterações de orientação no
código compartilhado. No entanto, o SizeChanged eventos do Page é acionada quando a largura ou altura do
Page alterações. Quando a largura do Page é maior que a altura, o dispositivo estiver no modo paisagem. Para
obter mais informações, consulte exibir uma imagem com base na orientação da tela.

NOTE
Há um pacote de NuGet existente e gratuito para receber notificações de alterações de orientação no código compartilhado.
Consulte a repositório GitHub para obter mais informações.

Como alternativa, é possível substituir a OnSizeAllocated método em um Page , inserindo qualquer layout alterar
lógica nele. O OnSizeAllocated método é chamado sempre que um Page é alocado um novo tamanho, o que
ocorre sempre que o dispositivo seja girado. Observe que a implementação base de OnSizeAllocated executa
funções importantes de layout, portanto, é importante chamar a implementação base na substituição:

protected override void OnSizeAllocated(double width, double height)


{
base.OnSizeAllocated(width, height); //must be called
}

Falha ao executar essa etapa resulta em uma página não está funcionando.
Observe que o OnSizeAllocated método pode ser chamado várias vezes quando um dispositivo é girado.
Alterando o layout de cada vez que é um desperdício de recursos e pode levar a cintilação. Considere o uso de
uma variável de instância dentro de sua página para controlar se a orientação é em paisagem ou retrato e
redesenhar somente quando há uma alteração:

private double width = 0;


private double height = 0;

protected override void OnSizeAllocated(double width, double height)


{
base.OnSizeAllocated(width, height); //must be called
if (this.width != width || this.height != height)
{
this.width = width;
this.height = height;
//reconfigure layout
}
}
Depois que tiver sido detectada uma alteração na orientação do dispositivo, você talvez queira adicionar ou
remover exibições adicionais de/para sua interface do usuário para reagir a alterações no espaço disponível. Por
exemplo, considere a Calculadora interna em cada plataforma em Retrato:

e o cenário:
Observe que os aplicativos aproveitam o espaço disponível com a adição de mais funcionalidades em paisagem.

Layout dinâmico
É possível para interfaces de design usando os layouts internos para que eles normalmente a transição quando o
dispositivo é girado. Durante a criação de interfaces que continuarão a ser atraente ao responder a alterações na
orientação, considere as seguintes regras gerais:
Preste atenção às taxas – alterações na orientação podem causar problemas quando determinadas
suposições são feitas com relação a taxas. Por exemplo, uma exibição que teria bastante espaço em 1/3, o
espaço vertical de uma tela em Retrato não caber em 1/3 do espaço vertical em paisagem.
Tenha cuidado com os valores absolutos – valores absolutos (pixel) que fazem sentido em Retrato talvez
não faça sentido em paisagem. Quando valores absolutos forem necessárias, use layouts aninhados para isolar
seu impacto. Por exemplo, seria razoável usar valores absolutos em um TableView ItemTemplate quando o
modelo de item tem uma altura uniforme garantida.
As regras acima também se aplicam ao implementar interfaces para vários tamanhos de tela e são geralmente
considerados práticas recomendadas. O restante deste guia explicará exemplos específicos de layouts responsivos
usando cada um dos layouts primários no xamarin. Forms.

NOTE
Para maior clareza, as seções a seguir demonstram como implementar layouts responsivos usando apenas um tipo de
Layout por vez. Na prática, geralmente é mais simples de misturar Layout s para obter um layout desejado usando o
mais simples ou mais intuitiva Layout para cada componente.
StackLayout
Considere o aplicativo a seguir, exibido em Retrato:

e o cenário:
Que pode ser feito com o XAML a seguir:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ResponsiveLayout.StackLayoutPageXaml"
Title="Stack Photo Editor - XAML">
<ContentPage.Content>
<StackLayout Spacing="10" Padding="5" Orientation="Vertical"
x:Name="outerStack"> <!-- can change orientation to make responsive -->
<ScrollView>
<StackLayout Spacing="5" HorizontalOptions="FillAndExpand"
WidthRequest="1000">
<StackLayout Orientation="Horizontal">
<Label Text="Name: " WidthRequest="75"
HorizontalOptions="Start" />
<Entry Text="deer.jpg"
HorizontalOptions="FillAndExpand" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Date: " WidthRequest="75"
HorizontalOptions="Start" />
<Entry Text="07/05/2015"
HorizontalOptions="FillAndExpand" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Tags:" WidthRequest="75"
HorizontalOptions="Start" />
<Entry Text="deer, tiger"
HorizontalOptions="FillAndExpand" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Button Text="Save" HorizontalOptions="FillAndExpand" />
</StackLayout>
</StackLayout>
</ScrollView>
<Image Source="deer.jpg" />
</StackLayout>
</ContentPage.Content>
</ContentPage>

Alguns C# é usado para alterar a orientação do outerStack com base na orientação do dispositivo:

protected override void OnSizeAllocated (double width, double height){


base.OnSizeAllocated (width, height);
if (width != this.width || height != this.height) {
this.width = width;
this.height = height;
if (width > height) {
outerStack.Orientation = StackOrientation.Horizontal;
} else {
outerStack.Orientation = StackOrientation.Vertical;
}
}
}

Observe o seguinte:
é ajustado para apresentar os controles e a imagem como uma pilha horizontal ou vertical,
outerStack
dependendo da orientação, para aproveitar melhor o espaço disponível.
AbsoluteLayout
Considere o aplicativo a seguir, exibido em Retrato:
e o cenário:
Que pode ser feito com o XAML a seguir:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ResponsiveLayout.AbsoluteLayoutPageXaml"
Title="AbsoluteLayout - XAML" BackgroundImage="deer.jpg">
<ContentPage.Content>
<AbsoluteLayout>
<ScrollView AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="PositionProportional,SizeProportional">
<AbsoluteLayout>
<Image Source="deer.jpg"
AbsoluteLayout.LayoutBounds=".5,0,300,300"
AbsoluteLayout.LayoutFlags="PositionProportional" />
<BoxView Color="#CC1A7019" AbsoluteLayout.LayoutBounds=".5
300,.7,50" AbsoluteLayout.LayoutFlags="XProportional
WidthProportional" />
<Label Text="deer.jpg" AbsoluteLayout.LayoutBounds = ".5
310,1, 50" AbsoluteLayout.LayoutFlags="XProportional
WidthProportional" HorizontalTextAlignment="Center" TextColor="White" />
</AbsoluteLayout>
</ScrollView>
<Button Text="Previous" AbsoluteLayout.LayoutBounds="0,1,.5,60"
AbsoluteLayout.LayoutFlags="PositionProportional
WidthProportional"
BackgroundColor="White" TextColor="Green" BorderRadius="0" />
<Button Text="Next" AbsoluteLayout.LayoutBounds="1,1,.5,60"
AbsoluteLayout.LayoutFlags="PositionProportional
WidthProportional" BackgroundColor="White"
TextColor="Green" BorderRadius="0" />
</AbsoluteLayout>
</ContentPage.Content>
</ContentPage>

Observe o seguinte:
Por causa da maneira que a página foi disposta, não é necessário para o código procedural introduzir a
capacidade de resposta.
O ScrollView está sendo usado para permitir que o rótulo fique visível, mesmo quando a altura da tela é
menor que a soma das alturas dos botões e a imagem fixas.
RelativeLayout
Considere o aplicativo a seguir, exibido em Retrato:
e o cenário:
Que pode ser feito com o XAML a seguir:

<?xml version="1.0" encoding="UTF-8"?>


<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ResponsiveLayout.RelativeLayoutPageXaml"
Title="RelativeLayout - XAML"
BackgroundImage="deer.jpg">
<ContentPage.Content>
<RelativeLayout x:Name="outerLayout">
<BoxView BackgroundColor="#AA1A7019"
RelativeLayout.WidthConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Width,Factor=1}"
RelativeLayout.HeightConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Height,Factor=1}"
RelativeLayout.XConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Width,Factor=0,Constant=0}"
RelativeLayout.YConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Height,Factor=0,Constant=0}" />
<ScrollView
RelativeLayout.WidthConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Width,Factor=1}"
RelativeLayout.HeightConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Height,Factor=1,Constant=-60}"
RelativeLayout.XConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Width,Factor=0,Constant=0}"
RelativeLayout.YConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Height,Factor=0,Constant=0}">
<RelativeLayout>
<Image Source="deer.jpg" x:Name="imageDeer"
RelativeLayout.WidthConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Width,Factor=.8}"
RelativeLayout.XConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Width,Factor=.1}"
RelativeLayout.YConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Height,Factor=0,Constant=10}" />
<Label Text="deer.jpg" HorizontalTextAlignment="Center"
RelativeLayout.WidthConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Width,Factor=1}"
RelativeLayout.HeightConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Height,Factor=0,Constant=75}"
RelativeLayout.XConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Width,Factor=0,Constant=0}"
RelativeLayout.YConstraint="{ConstraintExpression
Type=RelativeToView,ElementName=imageDeer,Property=Height,Factor=1,Constant=20}"
/>
</RelativeLayout>

</ScrollView>

<Button Text="Previous" BackgroundColor="White" TextColor="Green" BorderRadius="0"


RelativeLayout.YConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Height,Factor=1,Constant=-60}"
RelativeLayout.XConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Width,Factor=0,Constant=0}"
RelativeLayout.HeightConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Width,Factor=0,Constant=60}"
RelativeLayout.WidthConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Width,Factor=.5}"
/>
<Button Text="Next" BackgroundColor="White" TextColor="Green" BorderRadius="0"
RelativeLayout.XConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Width,Factor=.5}"
RelativeLayout.YConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Height,Factor=1,Constant=-60}"
RelativeLayout.HeightConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Width,Factor=0,Constant=60}"
RelativeLayout.WidthConstraint="{ConstraintExpression
RelativeLayout.WidthConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Width,Factor=.5}"
/>
</RelativeLayout>
</ContentPage.Content>
</ContentPage>

Observe o seguinte:
Por causa da maneira que a página foi disposta, não é necessário para o código procedural introduzir a
capacidade de resposta.
O ScrollView está sendo usado para permitir que o rótulo fique visível, mesmo quando a altura da tela é
menor que a soma das alturas dos botões e a imagem fixas.
Grade
Considere o aplicativo a seguir, exibido em Retrato:

e o cenário:
Que pode ser feito com o XAML a seguir:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ResponsiveLayout.GridPageXaml"
Title="Grid - XAML">
<ContentPage.Content>
<Grid x:Name="outerGrid">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="60" />
</Grid.RowDefinitions>
<Grid x:Name="innerGrid" Grid.Row="0" Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Source="deer.jpg" Grid.Row="0" Grid.Column="0" HeightRequest="300" WidthRequest="300"
/>
<Grid x:Name="controlsGrid" Grid.Row="0" Grid.Column="1" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Text="Name:" Grid.Row="0" Grid.Column="0" />
<Label Text="Date:" Grid.Row="1" Grid.Column="0" />
<Label Text="Tags:" Grid.Row="2" Grid.Column="0" />
<Entry Grid.Row="0" Grid.Column="1" />
<Entry Grid.Row="1" Grid.Column="1" />
<Entry Grid.Row="2" Grid.Column="1" />
</Grid>
</Grid>
<Grid x:Name="buttonsGrid" Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Text="Previous" Grid.Column="0" />
<Button Text="Save" Grid.Column="1" />
<Button Text="Next" Grid.Column="2" />
</Grid>
</Grid>
</ContentPage.Content>
</ContentPage>

Juntamente com o seguinte código procedural para manipular as alterações de rotação:


private double width;
private double height;

protected override void OnSizeAllocated (double width, double height){


base.OnSizeAllocated (width, height);
if (width != this.width || height != this.height) {
this.width = width;
this.height = height;
if (width > height) {
innerGrid.RowDefinitions.Clear();
innerGrid.ColumnDefinitions.Clear ();
innerGrid.RowDefinitions.Add (new RowDefinition{ Height = new GridLength (1, GridUnitType.Star)
});
innerGrid.ColumnDefinitions.Add (new ColumnDefinition { Width = new GridLength (1,
GridUnitType.Star) });
innerGrid.ColumnDefinitions.Add (new ColumnDefinition { Width = new GridLength (1,
GridUnitType.Star) });
innerGrid.Children.Remove (controlsGrid);
innerGrid.Children.Add (controlsGrid, 1, 0);
} else {
innerGrid.RowDefinitions.Clear();
innerGrid.ColumnDefinitions.Clear ();
innerGrid.ColumnDefinitions.Add (new ColumnDefinition{ Width = new GridLength (1,
GridUnitType.Star) });
innerGrid.RowDefinitions.Add (new RowDefinition { Height = new GridLength (1, GridUnitType.Auto)
});
innerGrid.RowDefinitions.Add (new RowDefinition { Height = new GridLength (1, GridUnitType.Star)
});
innerGrid.Children.Remove (controlsGrid);
innerGrid.Children.Add (controlsGrid, 0, 1);
}
}
}

Observe o seguinte:
Por causa da maneira que a página foi disposta, há um método para alterar o posicionamento de grade dos
controles.

Links relacionados
Layout (amostra)
Exemplo de BusinessTumble (amostra)
Layout dinâmico (exemplo)
Exibir uma imagem com base na orientação da tela
Layout para aplicativos de Tablet e área de trabalho
12/04/2019 • 5 minutes to read

Xamarin. Forms oferece suporte a todos os tipos de dispositivo disponíveis em plataformas com suporte, além de
telefones, os aplicativos também podem executar em:
iPads,
Tablets Android,
Tablets Windows e computadores desktop (executando o Windows 10).
Esta página aborda resumidamente:
com suporte tipos de dispositivo, e
como otimizar layouts para tablets e telefones.

Tipos de dispositivo
Dispositivos de tela maiores estão disponíveis para todas as plataformas com suporte pelo xamarin. Forms.
iPads (iOS )
O modelo do xamarin. Forms inclui automaticamente suporte a iPad, configurando o Info. plist > dispositivos
definir como Universal (o que significa que há suporte para iPhone e iPad).
Para fornecer uma experiência de inicialização agradável e verifique se a resolução de tela inteira é usada em
todos os dispositivos, você deve verificar se um tela de inicialização específicas do iPad (usando um storyboard) é
fornecido. Isso garante que o aplicativo é renderizado corretamente em dispositivos de iPad mini, iPad e iPad Pro.
Antes do iOS 9 todos os aplicativos ocupou toda a tela no dispositivo, mas agora pode executar alguns iPads
dividir a tela multitarefa. Isso significa que seu aplicativo pode levar apenas uma coluna slim na lateral da tela,
50% da largura da tela, ou a tela inteira.
O Split screen funcionalidade significa que você deve projetar seu aplicativo funcione bem com até 320 pixels de
largura ou de 1366 tanto quanto pixels de largura.
Tablets Android
O ecossistema do Android tem uma grande variedade de tamanhos de tela com suporte, de telefones pequeno
até grandes tablets. Xamarin. Forms pode dar suporte a todos os tamanhos de tela, mas como com outras
plataformas você talvez queira ajustar sua interface do usuário para dispositivos maiores.
Ao dar suporte a muitos diferentes resoluções de tela, você pode fornecer os recursos de imagem nativa em
tamanhos diferentes para otimizar a experiência do usuário. Examine os recursos do Android documentação (e,
em particular criar recursos para abranger diferentes tamanhos de tela) para obter mais informações sobre como
estruturar as pastas e os nomes de arquivo em seu aplicativo Android projeto para incluir recursos de imagem
otimizada em seu aplicativo.
Desktops e Tablets Windows
Para dar suporte a tablets e computadores desktop que executam o Windows, você precisará usar suporte do
Windows UWP, que compila aplicativos universais que são executados no Windows 10.
Aplicativos que são executados em desktops e tablets Windows podem ser redimensionados para dimensões
arbitrárias além para tela inteira em execução.
Otimizando para Tablet e área de trabalho
Você pode ajustar sua interface do usuário do xamarin. Forms, dependendo se um telefone ou dispositivo de
tablet/área de trabalho está sendo usado. Isso significa que você pode otimizar a experiência do usuário para
dispositivos de tela grande, como tablets e computadores desktop.
Device.Idiom
Você pode usar o Device classe para alterar o comportamento da interface do usuário ou aplicativo. Usando o
Device.Idiom enumeração, você pode

if (Device.Idiom == TargetIdiom.Phone)
{
HeroImage.Source = ImageSource.FromFile("hero.jpg");
} else {
HeroImage.Source = ImageSource.FromFile("herotablet.jpg");
}

Essa abordagem pode ser expandida para fazer alterações significativas aos layouts de página individual, ou até
mesmo para renderizar páginas inteiramente diferentes em telas maiores.
Aproveitando MasterDetailPage
O MasterDetailPage é ideal para telas maiores, especialmente no iPad em que ele usa o UISplitViewController
para fornecer uma experiência do iOS nativo.
Revisão esta postagem de blog do Xamarin para ver como você pode adaptar sua interface do usuário para que os
telefones usam um layout e telas maiores podem usar outro (com o MasterDetailPage ).

Links relacionados
Blog do Xamarin
Exemplo de MyShoppe
Associáveis Layouts no xamarin. Forms
12/04/2019 • 6 minutes to read

Baixar o exemplo
Layouts associáveis habilitam qualquer classe de layout que deriva de Layout<T> classe para gerar seu conteúdo
por associação a uma coleção de itens, com a opção de definir a aparência de cada item com um DataTemplate .
Layouts associáveis são fornecidos pelo BindableLayout classe, que expõe as propriedades anexadas a seguir:
ItemsSource – Especifica a coleção de IEnumerable itens a serem exibidos no layout.
ItemTemplate – Especifica o DataTemplate para aplicar a cada item na coleção de itens exibidos pelo layout.
ItemTemplateSelector – Especifica o DataTemplateSelector que será usado para escolher um DataTemplate
para um item em tempo de execução.
Essas propriedades podem ser anexadas à AbsoluteLayout , FlexLayout , Grid , RelativeLayout ,e StackLayout
classes, que derivam de Layout<T> classe.

NOTE
O ItemTemplate propriedade terá precedência quando tanto o ItemTemplate e ItemTemplateSelector são definidas.

O Layout<T> classe expõe um Children coleta, à qual os elementos filho de um layout são adicionados. Quando
o BinableLayout.ItemsSource propriedade é definida como uma coleção de itens e anexada a uma Layout<T> -
classe derivada, cada item na coleção é adicionado ao Layout<T>.Children coleção para exibição pelo layout. O
Layout<T> -classe derivada, em seguida, atualize suas exibições filha quando a coleção subjacente é alterado. Para
obter mais informações sobre o ciclo de layout do xamarin. Forms, consulte criação de um Layout personalizado.

IMPORTANT
Layouts associáveis só devem ser usados quando a coleção de itens a serem exibidos é pequena e de rolagem e a seleção
não é necessária. Enquanto a rolagem pode ser fornecida, encapsulando um layout associável em uma ScrollView , isso
não é recomendado como associáveis layouts não têm a virtualização de interface do usuário. Quando a rolagem é
necessária, uma exibição rolável que inclui a virtualização de interface do usuário, como ListView ou CollectionView ,
deve ser usado. Para observar essa recomendação pode levar a problemas de desempenho.

Populando um layout associável com dados


Um layout associável é preenchido com dados, definindo sua ItemsSource propriedade para qualquer coleção que
implemente IEnumerable e anexá-lo para um Layout<T> -classe derivada:

<Grid BindableLayout.ItemsSource="{Binding Items}" />

O código C# equivalente é:

IEnumerable<string> items = ...;


var grid = new Grid();
BindableLayout.SetItemsSource(grid, items);
Quando o BindableLayout.ItemsSource propriedade anexada é definida em um layout, mas o
BindableLayout.ItemTemplate propriedade anexada não estiver definido, todos os itens na IEnumerable coleção
será exibida por um Label criado pelo BindableLayout classe.

Definir a aparência do item


A aparência de cada item no layout associável pode ser definida ao configurar o BindableLayout.ItemTemplate
anexado à propriedade um DataTemplate :

<StackLayout BindableLayout.ItemsSource="{Binding User.TopFollowers}"


Orientation="Horizontal"
...>
<BindableLayout.ItemTemplate>
<DataTemplate>
<controls:CircleImage Source="{Binding}"
Aspect="AspectFill"
WidthRequest="44"
HeightRequest="44"
... />
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>

O código C# equivalente é:

DataTemplate circleImageTemplate = ...;


var stackLayout = new StackLayout();
BindableLayout.SetItemsSource(stackLayout, viewModel.User.TopFollowers);
BindableLayout.SetItemTemplate(stackLayout, circleImageTemplate);

Neste exemplo, todos os itens a TopFollowers coleção será exibida por um CircleImage exibição definida na
DataTemplate :

Para obter mais informações sobre modelos de dados, consulte modelos de dados do xamarin. Forms.

Escolhendo a aparência do item em tempo de execução


A aparência de cada item no layout associável pode ser escolhida em tempo de execução, com base no valor do
item, definindo a BindableLayout.ItemTemplateSelector anexado à propriedade um DataTemplateSelector :

<FlexLayout BindableLayout.ItemsSource="{Binding User.FavoriteTech}"


BindableLayout.ItemTemplateSelector="{StaticResource TechItemTemplateSelector}"
... />

O código C# equivalente é:
DataTemplateSelector dataTemplateSelector = new TechItemTemplateSelector { ... };
var flexLayout = new FlexLayout();
BindableLayout.SetItemsSource(flexLayout, viewModel.User.FavoriteTech);
BindableLayout.SetItemTemplateSelector(flexLayout, dataTemplateSelector);

O DataTemplateSelector usada no exemplo de aplicativo é mostrado no exemplo a seguir:

public class TechItemTemplateSelector : DataTemplateSelector


{
public DataTemplate DefaultTemplate { get; set; }
public DataTemplate XamarinFormsTemplate { get; set; }

protected override DataTemplate OnSelectTemplate(object item, BindableObject container)


{
return (string)item == "Xamarin.Forms" ? XamarinFormsTemplate : DefaultTemplate;
}
}

O TechItemTemplateSelector classe define DefaultTemplate e XamarinFormsTemplate DataTemplate propriedades


que são definidas para modelos de dados diferentes. O OnSelectTemplate método retorna o XamarinFormsTemplate
, que exibe um item em vermelho-escuro com um núcleo ao lado dele, quando o item é igual a "Xamarin. Forms".
Quando o item não for igual a "Xamarin. Forms", o OnSelectTemplate método retorna o DefaultTemplate , que
exibe um item usando a cor padrão de um Label :

Para obter mais informações sobre os seletores de modelo de dados, consulte criando um xamarin. Forms
DataTemplateSelector.

Links relacionados
Demonstração de Layout associável (amostra)
Criar um layout personalizado
Modelos de dados do xamarin. Forms
Criando um DataTemplateSelector xamarin. Forms
Criar um Layout personalizado
12/04/2019 • 27 minutes to read

baixar o exemplo
Xamarin. Forms define quatro classes de layout – StackLayout, AbsoluteLayout, RelativeLayout e grade, e cada
organiza seus filhos de uma maneira diferente. No entanto, às vezes, é necessário para organizar o conteúdo da
página usando um layout que não são fornecido pelo xamarin. Forms. Este artigo explica como escrever uma
classe de layout personalizado e demonstra uma classe de WrapLayout sensíveis à orientação que organiza seus
filhos horizontalmente pela página e, em seguida, ajusta a exibição dos filhos subsequentes em linhas adicionais.

Visão geral
No xamarin. Forms, todas as classes de layout derivam de Layout<T> classe e restringir o tipo genérico para
View e seus tipos derivados. Por sua vez, o Layout<T> classe deriva de Layout classe, que fornece o mecanismo
para posicionamento e o filho de dimensionamento elementos.
Cada elemento visual é responsável por determinar seu próprio tamanho preferencial, o que é conhecido como
o solicitado tamanho. Page , Layout , e Layout<View> tipos derivados são responsáveis por determinar o local e
o tamanho do seu filho ou filhos, em relação a mesmos. Portanto, o layout envolve uma relação pai-filho, no qual
o pai determina qual deve ser o tamanho de seus filhos, mas tentará acomodar o tamanho solicitado do filho.
Uma compreensão detalhada dos ciclos de layout e a invalidação da xamarin. Forms é necessária para criar um
layout personalizado. Esses ciclos agora serão discutidos.

Layout
Layout começa na parte superior da árvore visual com uma página, e ele passa todas as ramificações da árvore
visual para abranger todos os elementos visuais em uma página. Elementos que são pais de outros elementos
são responsáveis por redimensionar e posicionar seus filhos em relação a mesmos.
O VisualElement classe define um Measure o método que mede um elemento para operações de layout, e um
Layout método Especifica a área retangular que o elemento será renderizado no. Quando um aplicativo é
iniciado e a primeira página for exibida, um ciclo de layout primeiro consistindo de Measure chamadas e, em
seguida Layout chama, inicia no Page objeto:
1. Durante o ciclo de layout, cada elemento pai é responsável por chamar o Measure método em seus filhos.
2. Após os filhos terem sido medidos, todos os elementos pai é responsável por chamar o Layout método em
seus filhos.
Esse ciclo garante que cada elemento visual na página recebe chamadas para o Measure e Layout métodos. O
processo é mostrado no diagrama a seguir:
NOTE
Observe que os ciclos de layout também podem ocorrer em um subconjunto da árvore visual se algo for alterado para
afetar o layout. Isso inclui itens que estão sendo adicionados ou removidos da coleção como em uma StackLayout , uma
alteração no IsVisible propriedade de um elemento ou uma alteração no tamanho de um elemento.

Cada classe de xamarin. Forms que tem um Content ou um Children propriedade tem um substituível
LayoutChildren método. Classes de layout personalizados que derivam de Layout<View> deve substituir esse
método e certifique-se de que o Measure e Layout são métodos chamado em todos os filhos do elemento, para
fornecer o layout personalizado desejado.
Além disso, cada classe que deriva de Layout ou Layout<View> deve substituir o OnMeasure método, que é
sempre que uma classe de layout Determina o tamanho que ele precisa estar fazendo chamadas para o Measure
métodos de seus filhos.

NOTE
Elementos determinam seu tamanho com base no restrições, que indicam a quantidade de espaço está disponível para um
elemento dentro do pai do elemento. Restrições passada para o Measure e OnMeasure métodos podem variar de 0 a
Double.PositiveInfinity . É um elemento restrita, ou totalmente restrita, quando ele recebe uma chamada para seu
Measure método com argumentos não infinita - o elemento é restrita para um tamanho específico. É um elemento
irrestrita, ou parcialmente restrita, quando ele recebe uma chamada para seu Measure método com pelo menos um
argumento igual a Double.PositiveInfinity – a restrição de infinita pode ser pensada como indicando o
dimensionamento automático.

Invalidação
Invalidação de é o processo pelo qual uma alteração em um elemento em uma página dispara um novo ciclo de
layout. Elementos são considerados inválidos quando eles não terão mais o tamanho correto ou a posição. Por
exemplo, se o FontSize propriedade de uma Button alterações, o Button será considerada inválida porque ela
não terá mais o tamanho correto. Redimensionando o Button , em seguida, pode ter um efeito dominó das
alterações no layout através do restante de uma página.
Elementos invalidam a mesmos, invocando o InvalidateMeasure método, geralmente quando uma propriedade
do elemento é alterada que pode resultar em um novo tamanho do elemento. Este método aciona o
MeasureInvalidated evento, que lida com o pai do elemento para disparar um novo ciclo de layout.
O Layout classe define um manipulador para o MeasureInvalidated evento em todos os filhos adicionados ao
seu Content propriedade ou Children coleção e desanexa o manipulador quando o filho é removido. Portanto,
todos os elementos na árvore visual que tem filhos é alertado sempre que um de seus filhos altera o tamanho. O
diagrama a seguir ilustra como uma alteração no tamanho de um elemento na árvore visual pode causar
alterações ripple acima na árvore:

No entanto, o Layout classe tenta restringir o impacto de uma alteração no tamanho de um filho no layout de
uma página. Se o layout é restringido de tamanho, em seguida, uma alteração de tamanho de filho não afeta
nada maior do que o layout do pai na árvore visual. No entanto, geralmente uma alteração no tamanho de um
layout afeta como o layout organiza seus filhos. Portanto, qualquer alteração no tamanho de um layout iniciará
um ciclo de layout para o layout e o layout receberá chamadas para seus OnMeasure e LayoutChildren métodos.
O Layout classe define também uma InvalidateLayout método que tem uma finalidade similar do
InvalidateMeasure método. O InvalidateLayout método deve ser chamado sempre que for feita uma alteração
que afeta como o layout posiciona e dimensiona seus filhos. Por exemplo, o Layout classe invoca o
InvalidateLayout método sempre que um filho é adicionado ou removido de um layout.

O InvalidateLayoutpode ser substituído para implementar um cache para minimizar repetitivas invocações da
Measure métodos de filhos do layout. Substituindo o InvalidateLayout método fornecerá uma notificação de
quando os filhos são adicionados ou removidos do layout. Da mesma forma, o OnChildMeasureInvalidated
método pode ser substituído para fornecer uma notificação quando um dos filhos do layout muda de tamanho.
Para ambas as substituições de método, um layout personalizado deve responder ao limpar o cache. Para obter
mais informações, consulte Calculando e armazenando dados.

Criar um Layout personalizado


O processo para criar um layout personalizado é da seguinte maneira:
1. Crie uma classe que derive da classe Layout<View> . Para obter mais informações, consulte criando um
WrapLayout.
2. [opcional] adicionar propriedades, apoiadas por propriedades vinculáveis, para todos os parâmetros que
devem ser definidas na classe de layout. Para obter mais informações, consulte Adicionando propriedades
apoiado por propriedades vinculáveis.
3. Substituir a OnMeasure método para invocar o Measure método em todo o layout filhos e retornar um
tamanho solicitado para o layout. Para obter mais informações, consulte substituindo o método OnMeasure.
4. Substituir o LayoutChildren método para invocar o Layout filhos do todos os o layout método. Falha ao
invocar o Layout método em cada filho em um layout resultará na filho nunca receber um tamanho correto
ou posição e, portanto, o filho não se tornará visível na página. Para obter mais informações, consulte
substituindo o método LayoutChildren.

NOTE
Ao enumerar os filhos na OnMeasure e LayoutChildren substituições, ignore qualquer filho cujo IsVisible estiver
definida como false . Isso garantirá que o layout personalizado não deixar espaço para os filhos invisíveis.

1. [opcional] substituir a InvalidateLayout método a ser notificado quando os filhos são adicionados ou
removidos do layout. Para obter mais informações, consulte substituindo o método InvalidateLayout.
2. [opcional] substituir a OnChildMeasureInvalidated método a ser notificado quando um dos filhos do layout
muda de tamanho. Para obter mais informações, consulte substituindo o método
OnChildMeasureInvalidated.

NOTE
Observe que o OnMeasure substituição não será invocada se o tamanho do layout é controlado pelo seu pai, em vez de
seus filhos. No entanto, a substituição será chamada se uma ou ambas as restrições são infinitas ou se a classe de layout
tem não padrão HorizontalOptions ou VerticalOptions valores de propriedade. Por esse motivo, o
LayoutChildren substituição não pode contar com tamanhos de filho obtidos durante a OnMeasure chamada de
método. Em vez disso, LayoutChildren deve invocar o Measure método nos filhos do layout, antes de invocar o
Layout método. Como alternativa, o tamanho dos filhos obtido na OnMeasure substituição pode ser armazenados em
cache para evitar mais tarde Measure invocações no LayoutChildren substituição, mas a classe de layout será preciso
saber quando os tamanhos precisam ser obtido novamente. Para obter mais informações, consulte Calculando e
armazenando dados de Layout.

A classe de layout, em seguida, pode ser consumida por adicioná-lo para um Page e pela adição de filhos no
layout. Para obter mais informações, consulte consumindo o WrapLayout.
Criando um WrapLayout
O aplicativo de exemplo demonstra uma orientação diferencia WrapLayout classe que organiza seus filhos
horizontalmente pela página e, em seguida, ajusta a exibição dos filhos subsequentes em linhas adicionais.
O WrapLayout classe aloca a mesma quantidade de espaço para cada filho, conhecido como o tamanho de
célula, com base no tamanho máximo dos filhos. Menor do que o tamanho da célula pode ser posicionado
dentro da célula de filhos com base em suas HorizontalOptions e VerticalOptions valores de propriedade.
O WrapLayout definição de classe é mostrada no exemplo de código a seguir:

public class WrapLayout : Layout<View>


{
Dictionary<Size, LayoutData> layoutDataCache = new Dictionary<Size, LayoutData>();
...
}

Calcular e armazenar em cache dados de Layout


O LayoutData estrutura armazena dados sobre uma coleção de filhos em um número de propriedades:
VisibleChildCount– o número de filhos que são visíveis no layout.
CellSize – o tamanho máximo de todos os filhos, ajustado para o tamanho do layout.
Rows – o número de linhas.
Columns – o número de colunas.

O layoutDataCache campo é usado para armazenar vários LayoutData valores. Quando o aplicativo for iniciado,
dois LayoutData objetos serão armazenados em cache para o layoutDataCache dicionário para a orientação
atual – uma para os argumentos de restrição para o OnMeasure substituição e outro para o width e height
argumentos para o LayoutChildren substituir. Para girar o dispositivo em orientação paisagem, o OnMeasure
substituir e o LayoutChildren substituição será novamente invocada, que resulta em dois outro LayoutData
objetos a serem armazenados em cache no dicionário. No entanto, ao retornar o dispositivo para a orientação
retrato, não há cálculos adicionais são necessários porque o layoutDataCache já tem os dados necessários.
O seguinte exemplo de código mostra a GetLayoutData método, que calcula as propriedades do LayoutData
estruturados com base em um determinado tamanho:

LayoutData GetLayoutData(double width, double height)


{
Size size = new Size(width, height);

// Check if cached information is available.


if (layoutDataCache.ContainsKey(size))
{
return layoutDataCache[size];
}

int visibleChildCount = 0;
Size maxChildSize = new Size();
int rows = 0;
int columns = 0;
LayoutData layoutData = new LayoutData();

// Enumerate through all the children.


foreach (View child in Children)
{
// Skip invisible children.
if (!child.IsVisible)
continue;

// Count the visible children.


visibleChildCount++;

// Get the child's requested size.


SizeRequest childSizeRequest = child.Measure(Double.PositiveInfinity, Double.PositiveInfinity);

// Accumulate the maximum child size.


maxChildSize.Width = Math.Max(maxChildSize.Width, childSizeRequest.Request.Width);
maxChildSize.Height = Math.Max(maxChildSize.Height, childSizeRequest.Request.Height);
}

if (visibleChildCount != 0)
{
// Calculate the number of rows and columns.
if (Double.IsPositiveInfinity(width))
{
columns = visibleChildCount;
rows = 1;
}
else
{
columns = (int)((width + ColumnSpacing) / (maxChildSize.Width + ColumnSpacing));
columns = Math.Max(1, columns);
rows = (visibleChildCount + columns - 1) / columns;
}

// Now maximize the cell size based on the layout size.


Size cellSize = new Size();

if (Double.IsPositiveInfinity(width))
cellSize.Width = maxChildSize.Width;
else
cellSize.Width = (width - ColumnSpacing * (columns - 1)) / columns;
cellSize.Width = (width - ColumnSpacing * (columns - 1)) / columns;

if (Double.IsPositiveInfinity(height))
cellSize.Height = maxChildSize.Height;
else
cellSize.Height = (height - RowSpacing * (rows - 1)) / rows;

layoutData = new LayoutData(visibleChildCount, cellSize, rows, columns);


}

layoutDataCache.Add(size, layoutData);
return layoutData;
}

O GetLayoutData método executa as seguintes operações:


Ele determina se um calculado LayoutData valor já está no cache e retorna-o se ele estiver disponível.
Caso contrário, ele enumera todos os filhos, invocando o Measure método em cada filho com uma largura
infinita e a altura e determina o tamanho máximo de filho.
Desde que haja pelo menos um filho visível, ele calcula o número de linhas e colunas necessárias e, em
seguida, calcula um tamanho de célula para os filhos com base nas dimensões do WrapLayout . Observe que o
tamanho da célula é geralmente um pouco mais amplo do que o tamanho máximo de filhos, mas que
também pode ser menor se o WrapLayout não é grande o suficiente para a mais ampla filho ou tall suficiente
para o filho mais alto.
Ele armazena o novo LayoutData valor no cache.
Adicionando propriedades apoiadas por propriedades vinculáveis
O WrapLayout classe define ColumnSpacing e RowSpacing propriedades, cujos valores são usados para separar as
linhas e colunas no layout, e que é apoiado por propriedades associáveis. As propriedades vinculáveis são
mostradas no exemplo de código a seguir:

public static readonly BindableProperty ColumnSpacingProperty = BindableProperty.Create(


"ColumnSpacing",
typeof(double),
typeof(WrapLayout),
5.0,
propertyChanged: (bindable, oldvalue, newvalue) =>
{
((WrapLayout)bindable).InvalidateLayout();
});

public static readonly BindableProperty RowSpacingProperty = BindableProperty.Create(


"RowSpacing",
typeof(double),
typeof(WrapLayout),
5.0,
propertyChanged: (bindable, oldvalue, newvalue) =>
{
((WrapLayout)bindable).InvalidateLayout();
});

Invoca o manipulador de propriedade alterada de cada propriedade associável a InvalidateLayout substituição


do método para disparar um novo layout passar o WrapLayout . Para obter mais informações, consulte
substituindo o método InvalidateLayout e substituindo o método OnChildMeasureInvalidated.
Substituindo o método OnMeasure
O OnMeasure substituição é mostrada no exemplo de código a seguir:
protected override SizeRequest OnMeasure(double widthConstraint, double heightConstraint)
{
LayoutData layoutData = GetLayoutData(widthConstraint, heightConstraint);
if (layoutData.VisibleChildCount == 0)
{
return new SizeRequest();
}

Size totalSize = new Size(layoutData.CellSize.Width * layoutData.Columns + ColumnSpacing *


(layoutData.Columns - 1),
layoutData.CellSize.Height * layoutData.Rows + RowSpacing * (layoutData.Rows - 1));
return new SizeRequest(totalSize);
}

Invoca a substituição de GetLayoutData método e construções de um SizeRequest objeto dos dados retornados,
levando em consideração também a RowSpacing e ColumnSpacing valores de propriedade. Para obter mais
informações sobre o GetLayoutData método, consulte Calculando e armazenando dados.

IMPORTANT
O Measure e OnMeasure métodos nunca devem solicitar uma dimensão de infinita, retornando um SizeRequest valor
com uma propriedade definida como Double.PositiveInfinity . No entanto, pelo menos um dos argumentos de
restrição OnMeasure pode ser Double.PositiveInfinity .

Substituindo o método LayoutChildren


O LayoutChildren substituição é mostrada no exemplo de código a seguir:
protected override void LayoutChildren(double x, double y, double width, double height)
{
LayoutData layoutData = GetLayoutData(width, height);

if (layoutData.VisibleChildCount == 0)
{
return;
}

double xChild = x;
double yChild = y;
int row = 0;
int column = 0;

foreach (View child in Children)


{
if (!child.IsVisible)
{
continue;
}

LayoutChildIntoBoundingRegion(child, new Rectangle(new Point(xChild, yChild), layoutData.CellSize));


if (++column == layoutData.Columns)
{
column = 0;
row++;
xChild = x;
yChild += RowSpacing + layoutData.CellSize.Height;
}
else
{
xChild += ColumnSpacing + layoutData.CellSize.Width;
}
}
}

A substituição começa com uma chamada para o GetLayoutData método e, em seguida, enumera todos os filhos
para dimensionar e posicioná-los dentro da célula de cada filho. Isso é feito invocando o
LayoutChildIntoBoundingRegion método, que é usado para posicionar um filho dentro de um retângulo com base
em seu HorizontalOptions e VerticalOptions valores de propriedade. Isso é equivalente a fazer uma chamada
para o filho Layout método.

NOTE
Observe que o retângulo transmitido para o LayoutChildIntoBoundingRegion método inclui toda a área em que o filho
pode residir.

Para obter mais informações sobre o GetLayoutData método, consulte Calculando e armazenando dados.
Substituindo o método InvalidateLayout
O InvalidateLayout substituição é invocada quando filhos são adicionados ou removidos do layout, ou quando
um do WrapLayout alterações de propriedades de valor, conforme mostrado no exemplo de código a seguir:

protected override void InvalidateLayout()


{
base.InvalidateLayout();
layoutInfoCache.Clear();
}

A substituição invalida o layout e descarta todas as informações de layout em cache.


NOTE
Para parar o Layout classe invocando o InvalidateLayout substituição do método sempre que um filho é adicionado
ou removido de um layout, o ShouldInvalidateOnChildAdded e ShouldInvalidateOnChildRemoved métodos e retorno
false . A classe de layout, em seguida, pode implementar um processo personalizado quando filhos são adicionados ou
removidos.

Substituindo o método OnChildMeasureInvalidated


O OnChildMeasureInvalidated substituição é invocada quando um dos filhos do layout muda de tamanho e é
mostrado no exemplo de código a seguir:

protected override void OnChildMeasureInvalidated()


{
base.OnChildMeasureInvalidated();
layoutInfoCache.Clear();
}

A substituição invalida o layout filho e descarta todas as informações de layout em cache.


Consumindo o WrapLayout
O WrapLayout classe pode ser consumido, colocando-o em um Page tipo derivado, conforme demonstrado no
exemplo de código XAML a seguir:

<ContentPage ... xmlns:local="clr-namespace:ImageWrapLayout">


<ScrollView Margin="0,20,0,20">
<local:WrapLayout x:Name="wrapLayout" />
</ScrollView>
</ContentPage>

O código c# equivalente é mostrado abaixo:

public class ImageWrapLayoutPageCS : ContentPage


{
WrapLayout wrapLayout;

public ImageWrapLayoutPageCS()
{
wrapLayout = new WrapLayout();

Content = new ScrollView


{
Margin = new Thickness(0, 20, 0, 20),
Content = wrapLayout
};
}
...
}

Filhos, em seguida, podem ser adicionados para o WrapLayout conforme necessário. O seguinte exemplo de
código mostra Image elementos que estão sendo adicionados ao WrapLayout :
protected override async void OnAppearing()
{
base.OnAppearing();

var images = await GetImageListAsync();


foreach (var photo in images.Photos)
{
var image = new Image
{
Source = ImageSource.FromUri(new Uri(photo + string.Format("?width={0}&height={0}&mode=max",
Device.RuntimePlatform == Device.UWP ? 120 : 240)))
};
wrapLayout.Children.Add(image);
}
}

async Task<ImageList> GetImageListAsync()


{
var requestUri = "https://docs.xamarin.com/demo/stock.json";
using (var client = new HttpClient())
{
var result = await client.GetStringAsync(requestUri);
return JsonConvert.DeserializeObject<ImageList>(result);
}
}

Quando a página que contém o WrapLayout aparecer, de forma assíncrona, o aplicativo de exemplo acessa um
arquivo JSON remoto que contém uma lista de fotos, cria um Image elemento para cada foto e adiciona-o para
o WrapLayout . Isso resulta na exibição mostrada nas capturas de tela seguir:

As capturas de tela a seguir mostram o WrapLayout depois é girada para a orientação paisagem:
O número de colunas em cada linha depende do tamanho da foto, a largura da tela e o número de pixels por
unidade independente de dispositivo. O Image elementos de forma assíncrona carregar as fotos e, portanto, o
WrapLayout classe receberá chamadas frequentes para seus LayoutChildren método conforme cada Image
elemento recebe um novo tamanho com base na foto carregada.

Resumo
Este artigo explica como escrever uma classe de layout personalizado e demonstramos uma orientação
diferencia WrapLayout classe que organiza seus filhos horizontalmente pela página e, em seguida, ajusta a
exibição dos filhos subsequentes em linhas adicionais.
Links relacionados
WrapLayout (amostra)
Layouts personalizados
Criar Layouts personalizados no xamarin. Forms (vídeo)
Layout
Layout
VisualElement
Compactação de Layout
12/04/2019 • 8 minutes to read

baixar o exemplo
Compactação de layout remove os layouts especificados da árvore visual em uma tentativa de melhorar o
desempenho de renderização da página. Este artigo explica como habilitar a compactação de layout e os
benefícios que ele pode trazer.

Visão geral
Xamarin. Forms executa usando duas séries de chamadas de método recursiva de layout:
Layout começa na parte superior da árvore visual com uma página, e ele passa todas as ramificações da
árvore visual para abranger todos os elementos visuais em uma página. Elementos que são pais de outros
elementos são responsáveis por redimensionar e posicionar seus filhos em relação a mesmos.
Invalidação de é o processo pelo qual uma alteração em um elemento em uma página dispara um novo ciclo
de layout. Elementos são considerados inválidos quando eles não terão mais o tamanho correto ou a posição.
Todos os elementos na árvore visual que tem filhos é alertado sempre que um de seus filhos altera tamanhos.
Portanto, uma alteração no tamanho de um elemento na árvore visual pode causar alterações ripple acima na
árvore.
Para obter mais informações sobre como o xamarin. Forms executa o layout, consulte criação de um Layout
personalizado.
O resultado do processo de layout é uma hierarquia de controles nativos. No entanto, essa hierarquia inclui os
renderizadores de contêiner adicional e wrappers para renderizadores de plataforma, aumentando ainda mais a
hierarquia de exibição de aninhamento. O maior o nível de aninhamento, maior a quantidade de trabalho que o
xamarin. Forms deve executar para exibir uma página. Para layouts complexos, a hierarquia de exibição pode ser
profundo e abrangente, com vários níveis de aninhamento.
Por exemplo, considere o seguinte botão do aplicativo de exemplo para fazer logon no Facebook:

Esse botão é especificado como um controle personalizado com a hierarquia de exibição XAML a seguir:
<ContentView ...>
<StackLayout>
<StackLayout ...>
<AbsoluteLayout ...>
<Button ... />
<Image ... />
<Image ... />
<BoxView ... />
<Label ... />
<Button ... />
</AbsoluteLayout>
</StackLayout>
<Label ... />
</StackLayout>
</ContentView>

A hierarquia de exibição aninhada resultante poderá ser examinada com Xamarin Inspector. No Android, a
hierarquia de exibição aninhada contém exibições de 17:

Compactação de layout, que está disponível para aplicativos xamarin. Forms nas plataformas Android e iOS, tem
como objetivo para mesclar a exibição de aninhamento, removendo os layouts especificados da árvore visual, que
pode melhorar o desempenho de renderização da página. O benefício de desempenho que é fornecido varia
dependendo da complexidade de uma página, a versão do sistema operacional que está sendo usado e o
dispositivo no qual o aplicativo está em execução. No entanto, os maiores ganhos de desempenho serão
observados em versões mais antigas.

NOTE
Embora este artigo se concentra nos resultados da aplicação de compactação de layout no Android, é igualmente aplicável
para iOS.

Compactação de Layout
No XAML, a compactação de layout pode ser habilitada definindo o CompressedLayout.IsHeadless anexado à
propriedade true em uma classe de layout:

<StackLayout CompressedLayout.IsHeadless="true">
...
</StackLayout>
Como alternativa, ele pode ser habilitado em c#, especificando a instância de layout como o primeiro argumento
para o CompressedLayout.SetIsHeadless método:

CompressedLayout.SetIsHeadless(stackLayout, true);

IMPORTANT
Uma vez que a compactação de layout remove um layout da árvore visual, não é adequado para layouts que têm uma
aparência visual, ou que obtêm entrada por toque. Portanto, layouts que defina VisualElement propriedades (como
BackgroundColor , IsVisible , Rotation , Scale , TranslationX e TranslationY ou que aceitar gestos, não são
candidatos para o layout compactação. No entanto, a habilitação da compactação de layout em um layout que define as
propriedades de aparência visual, ou que aceita a gestos, não resultará em um erro de compilação ou tempo de execução.
Em vez disso, compactação de layout será aplicada e as propriedades de aparência visual e reconhecimento de gesto,
falharão silenciosamente.

Para o botão do Facebook, compactação de layout pode ser habilitada nas classes de layout de três:

<StackLayout CompressedLayout.IsHeadless="true">
<StackLayout CompressedLayout.IsHeadless="true" ...>
<AbsoluteLayout CompressedLayout.IsHeadless="true" ...>
...
</AbsoluteLayout>
</StackLayout>
...
</StackLayout>

No Android, isso resulta em uma hierarquia de exibição aninhada de 14 exibições:

Em comparação com a hierarquia de exibição aninhada original das exibições de 17, isso representa uma redução
no número de modos de exibição de 17%. Embora essa redução pode aparecer insignificante, a redução de modo
de exibição ao longo de uma página inteira pode ser mais significativa.
Renderizadores Rápidos
Renderizadores rápidos reduzem os custos de renderização de controles do xamarin. Forms no Android e inflação
nivelando a hierarquia resultante de modo nativo. Isso aprimora o desempenho criando menos objetos, que por
sua vez, resulta em uma árvore visual menos complexa e menos uso de memória. Para obter mais informações
sobre renderizadores rápidos, consulte os renderizadores rápidos.
Para o botão do Facebook no aplicativo de exemplo, a combinação de compactação de layout e os renderizadores
rápidos produz uma hierarquia de exibição aninhada de exibições de 8:
Em comparação com a hierarquia de exibição aninhada original das exibições de 17, isso representa uma redução
de 52%.
O aplicativo de exemplo contém uma página extraída de um aplicativo real. Sem compactação de layout e os
renderizadores rápidos, a página produz uma hierarquia de exibição aninhada de 130 exibições no Android.
Habilitando os renderizadores rápidos e compactação de layout em classes de layout adequado reduz a hierarquia
de exibição aninhada a 70 modos de exibição, uma redução de 46%.

Resumo
Compactação de layout remove os layouts especificados da árvore visual em uma tentativa de melhorar o
desempenho de renderização da página. O benefício de desempenho que isso oferece varia dependendo da
complexidade de uma página, da versão do sistema operacional que está sendo usado e do dispositivo no qual o
aplicativo está sendo executado. No entanto, os maiores ganhos de desempenho serão observados em versões
mais antigas.

Links relacionados
Criar um layout personalizado
Renderizadores Rápidos
LayoutCompression (amostra)
Xamarin. Forms ListView
12/04/2019 • 5 minutes to read

Baixar o exemplo
ListView é uma exibição para apresentar as listas de dados, especialmente listas longas que exigem rolagem.

IMPORTANT
CollectionView é um modo de exibição para apresentar as listas de dados usando as especificações de layout diferente.
Tem como objetivo fornecer uma mais flexível e alternativa de alto desempenho para o ListView . Para obter mais
informações, consulte xamarin. Forms CollectionView.

Casos de uso
Certifique-se de que ListView é o controle certo para suas necessidades. ListView pode ser usado em qualquer
situação em que você está exibindo a lista rolável de dados. ListViews dão suporte a ações de contexto e
associação de dados.
Não deve ser confundido com o ListView modo de tabela. O controle de modo de tabela é uma opção melhor,
sempre que você tem uma lista não associadas de opções ou de dados. Por exemplo, o aplicativo de
configurações do iOS, que tem um conjunto predefinido de principalmente de opções, é mais adequado usar o
modo de tabela que ListView.
Também Observe que um ListView é melhor adequada para dados homogêneos – ou seja, todos os dados
devem ser do mesmo tipo. Isso ocorre porque apenas um tipo de célula pode ser usado para cada linha na lista.
TableViews pode dar suporte a vários tipos de célula, portanto, eles são uma opção melhor quando você
precisar combinar modos de exibição.

Componentes
ListView tem um número de componentes disponíveis para praticar a funcionalidade nativa de cada
plataforma. Cada um desses componentes é descrita abaixo:
Cabeçalhos e rodapés – separar de texto ou modo de exibição para exibir no início e no final de uma lista
de dados da lista. Cabeçalhos e rodapés de páginas podem ser associados a uma fonte de dados
independentemente da fonte de dados do ListView.
Grupos – dados em um ListView que podem ser agrupados para facilitar a navegação. Normalmente, os
grupos são associados a dados:
Células – dados em um ListView são apresentados nas células. Cada célula corresponde a uma linha de
dados. Houver células internas à sua escolha, ou você pode definir sua própria célula personalizado. Células
de internas e personalizadas podem ser usadas/definido em XAML ou código.
Interna – criados nas células, especialmente TextCell e ImageCell, pode ser ótimo para o
desempenho, já que eles correspondem aos controles nativos em cada plataforma.
TextCell – exibe uma cadeia de caracteres de texto, opcionalmente, com o texto detalhado.
Texto de detalhe é renderizado como uma segunda linha em uma fonte menor com uma cor de
ênfase.
ImageCell – exibe uma imagem com texto. Aparece como um TextCell com uma imagem à
esquerda.
Células personalizadas – células personalizadas são ótimos quando você precisa apresentar dados
complexos. Por exemplo, uma exibição personalizada poderia ser usada para apresentar uma lista de
músicas, incluindo o álbum e o artista:
Para saber mais sobre como personalizar células em um ListView, consulte personalizando aparência de célula
do ListView.

Funcionalidade
ListView oferece suporte a um número de estilos de interação, incluindo:
Atualização de pull – ListView oferece suporte a pull para atualizar em cada plataforma.
Ações de contexto – ListView oferece suporte a executar ações em itens individuais em uma lista. Por
exemplo, você pode implementar a ação para passar o dedo no iOS, ou toque ações no Android.
Seleção – você pode escutar seleções e contíguas para agir quando uma linha é tocada.
Para saber mais sobre os recursos de interatividade do ListView, consulte ações & interatividade com ListView.

Links relacionados
Trabalhando com ListView (amostra)
Associação bidirecional (amostra)
Criado em células (amostra)
Células personalizadas (amostra)
Agrupamento (amostra)
Exibição de renderizador personalizado (amostra)
Interatividade do ListView (amostra)
Fontes de dados de ListView
12/04/2019 • 5 minutes to read

baixar o exemplo
Um ListView é usado para exibir listas de dados. Aprenderemos sobre preenchendo um ListView com dados e
como podemos fazer a ligação para o item selecionado.

ItemsSource
Um ListView é preenchida com dados usando o ItemsSource propriedade, que pode aceitar qualquer coleção que
implementa IEnumerable . A maneira mais simples para preencher um ListView envolve o uso de uma matriz de
cadeias de caracteres:

<ListView>
<ListView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>mono</x:String>
<x:String>monodroid</x:String>
<x:String>monotouch</x:String>
<x:String>monorail</x:String>
<x:String>monodevelop</x:String>
<x:String>monotone</x:String>
<x:String>monopoly</x:String>
<x:String>monomodal</x:String>
<x:String>mononucleosis</x:String>
</x:Array>
</ListView.ItemsSource>
</ListView>

O código c# equivalente é:

var listView = new ListView();


listView.ItemsSource = new string[]
{
"mono",
"monodroid",
"monotouch",
"monorail",
"monodevelop",
"monotone",
"monopoly",
"monomodal",
"mononucleosis"
};

//monochrome will not appear in the list because it was added


//after the list was populated.
listView.ItemsSource.Add("monochrome");
A abordagem acima preencherá o ListView com uma lista de cadeias de caracteres. Por padrão, ListView
chamará ToString e exibir o resultado em um TextCell para cada linha. Para personalizar como os dados são
exibidos, consulte aparência da célula.
Porque ItemsSource foi enviada para uma matriz, não será atualizado com as alterações de matriz ou lista
subjacentes. Se você quiser que o ListView para atualizar automaticamente à medida que itens são adicionados,
removidos ou alterados na lista subjacente, você precisará usar um ObservableCollection . ObservableCollection é
definido em System.Collections.ObjectModel e é exatamente como qualquer List , exceto que ele pode notificar
ListView de todas as alterações:

ObservableCollection<Employee> employees = new ObservableCollection<Employee>();


listView.ItemsSource = employees;

//Mr. Mono will be added to the ListView because it uses an ObservableCollection


employees.Add(new Employee(){ DisplayName="Mr. Mono"});

Associação de dados
Associação de dados é a "cola" que associa as propriedades de um objeto de interface do usuário para as
propriedades de um objeto do CLR, como uma classe em seu ViewModel. Associação de dados é útil porque ele
simplifica o desenvolvimento de interfaces do usuário, substituindo muito código clichê que sem graça.
Associação de dados funciona mantendo os objetos sincronizados como alteram seus valores associados. Em vez
de precisar escrever manipuladores de eventos para sempre que um valor de controle é alterada, você estabelecer
a associação e habilitar a associação em seu ViewModel.
Para obter mais informações sobre associação de dados, consulte Noções básicas de vinculação de dados que é a
parte quatro da série de artigos de Noções básicas de XAML do xamarin. Forms.
Células de associação
Propriedades de células (e seus filhos de células) podem ser associadas às propriedades de objetos no
ItemsSource . Por exemplo, um ListView pode ser usado para apresentar uma lista de funcionários.

A classe do funcionário:

public class Employee


{
public string DisplayName {get; set;}
}

ObservableCollection<Employee> é criado e definido como o ListView do ItemsSource :

ObservableCollection<Employee> employees = new ObservableCollection<Employee>();


public EmployeeListPage()
{
//defined in XAML to follow
EmployeeView.ItemsSource = employees;
...
}

A lista é preenchida com dados:

public EmployeeListPage()
{
...
employees.Add(new Employee{ DisplayName="Rob Finnerty"});
employees.Add(new Employee{ DisplayName="Bill Wrestler"});
employees.Add(new Employee{ DisplayName="Dr. Geri-Beth Hooper"});
employees.Add(new Employee{ DisplayName="Dr. Keith Joyce-Purdy"});
employees.Add(new Employee{ DisplayName="Sheri Spruce"});
employees.Add(new Employee{ DisplayName="Burt Indybrick"});
}

O trecho a seguir demonstra um ListView associado a uma lista de funcionários:

<?xml version="1.0" encoding="utf-8" ?>


<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:constants="clr-namespace:XamarinFormsSample;assembly=XamarinFormsXamlSample"
x:Class="XamarinFormsXamlSample.Views.EmployeeListPage"
Title="Employee List">
<ListView x:Name="EmployeeView">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding DisplayName}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>

Observe que a associação foi configurada no código para manter a simplicidade, embora ele foi vinculado em
XAML.
O bit anterior de XAML define uma ContentPage que contém um ListView . Fonte de dados das ListView é
definido por meio de ItemsSource atributo. O layout de cada linha na ItemsSource é definido dentro de
ListView.ItemTemplate elemento.

Esse é o resultado:
Associação SelectedItem
Muitas vezes você desejará ligar para o item selecionado de um ListView , em vez de usar um manipulador de
eventos para responder a alterações. Para fazer isso no XAML, associar a SelectedItem propriedade:

<ListView x:Name="listView"
SelectedItem="{Binding Source={x:Reference SomeLabel},
Path=Text}">

</ListView>

Supondo listView do ItemsSource é uma lista de cadeias de caracteres SomeLabel terão sua propriedade de texto
associada ao SelectedItem .

Links relacionados
Associação bidirecional (amostra)
Personalizando a aparência de célula do ListView
12/04/2019 • 10 minutes to read

Baixar o exemplo
ListView apresenta listas roláveis, o que podem ser personalizadas por meio do uso de ViewCell s. ViewCells
pode ser usado para exibir texto e imagens, que indica um estado de verdadeiro/falso e receber entrada do
usuário.

Criado em células
Xamarin. Forms vem com células internos que funcionam para muitos aplicativos simples:
TextCell – para exibir o texto
ImageCell – para exibir uma imagem com texto.
Duas células adicionais, SwitchCell e EntryCell estão disponíveis, no entanto, eles não são comumente usados
com ListView . Ver TableView para obter mais informações sobre essas células.
TextCell
TextCell é uma célula para exibir o texto, opcionalmente com uma segunda linha como texto de detalhes.
TextCells são renderizados como controles nativos em tempo de execução, portanto, o desempenho é muito
bom em comparação com um personalizado ViewCell . TextCells são personalizáveis, permitindo que você
defina:
Text – o texto que é mostrado na primeira linha, em fonte grande.
Detail – o texto que é mostrado abaixo da primeira linha, em uma fonte menor.
TextColor – a cor do texto.
DetailColor – a cor do texto de detalhes
ImageCell
ImageCell , como TextCell , pode ser usado para exibir texto e texto secundário detalhes e oferece excelente
desempenho usando controles nativos de cada plataforma. ImageCell é diferente do TextCell em que ele
exibe uma imagem à esquerda do texto.
ImageCell é útil quando você precisa exibir uma lista de dados com um aspecto visual, como uma lista de
contatos ou filmes. ImageCells são personalizáveis, permitindo que você defina:
Text – o texto que é mostrado na primeira linha, em fontes grandes
Detail – o texto que é mostrado abaixo da primeira linha, em uma fonte menor
TextColor – a cor do texto
DetailColor – a cor do texto de detalhes
ImageSource – a imagem a ser exibida ao lado do texto
Células personalizadas
Quando as células internas não fornecerem o layout necessário, células personalizadas implementado o layout
necessário. Por exemplo, você talvez queira apresentar uma célula com dois rótulos que têm o mesmo peso. Um
TextCell seria insuficiente porque o TextCell tem um rótulo que for menor. A maioria das personalizações de
célula adicionar dados somente leitura adicionais (como rótulos adicionais, imagens ou outras informações de
exibição).
Todas as células personalizadas devem derivar de ViewCell , a mesma classe base que todos os internos célula
tipos de uso.
Xamarin. Forms 2 introduziu um novo comportamento de cache sobre o ListView controle que pode ser
definida para melhorar o desempenho de rolagem para alguns tipos de células personalizadas.
Este é um exemplo de uma célula personalizada:
XAML
O XAML para criar o layout acima está abaixo:

<?xml version="1.0" encoding="UTF-8"?>


<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="demoListView.ImageCellPage">
<ContentPage.Content>
<ListView x:Name="listView">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout BackgroundColor="#eee"
Orientation="Vertical">
<StackLayout Orientation="Horizontal">
<Image Source="{Binding image}" />
<Label Text="{Binding title}"
TextColor="#f35e20" />
<Label Text="{Binding subtitle}"
HorizontalOptions="EndAndExpand"
TextColor="#503026" />
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
</ContentPage>

O XAML acima está fazendo muito. Vamos dividi-lo:


A célula personalizada está aninhada em uma DataTemplate , que está dentro de ListView.ItemTemplate . Isso
é o mesmo processo usando qualquer outra célula.
ViewCell é o tipo de célula personalizado. O filho de DataTemplate elemento deve ser do ou derivar do tipo
ViewCell .
Observe que dentro de ViewCell , layout é gerenciado por um StackLayout . Esse layout nos permite
personalizar a cor do plano de fundo. Observe que qualquer propriedade do StackLayout que é associável
pode ser associado dentro de uma célula personalizada, apesar de que não é mostrada aqui.
Dentro de ViewCell , layout pode ser gerenciado por qualquer layout de xamarin. Forms.
C#
Especificar uma célula personalizada em C# é um pouco mais detalhado do que o equivalente em XAML. Vamos
analisar:
Primeiro, defina uma classe de célula personalizado, com ViewCell como a classe base:

public class CustomCell : ViewCell


{
public CustomCell()
{
//instantiate each of our views
var image = new Image ();
StackLayout cellWrapper = new StackLayout ();
StackLayout horizontalLayout = new StackLayout ();
Label left = new Label ();
Label right = new Label ();

//set bindings
left.SetBinding (Label.TextProperty, "title");
right.SetBinding (Label.TextProperty, "subtitle");
image.SetBinding (Image.SourceProperty, "image");

//Set properties for desired design


cellWrapper.BackgroundColor = Color.FromHex ("#eee");
horizontalLayout.Orientation = StackOrientation.Horizontal;
right.HorizontalOptions = LayoutOptions.EndAndExpand;
left.TextColor = Color.FromHex ("#f35e20");
right.TextColor = Color.FromHex ("503026");

//add views to the view hierarchy


horizontalLayout.Children.Add (image);
horizontalLayout.Children.Add (left);
horizontalLayout.Children.Add (right);
cellWrapper.Children.Add (horizontalLayout);
View = cellWrapper;
}
}

Em seu construtor para a página com o ListView , defina o ListView ItemTemplate propriedade para um novo
DataTemplate :

public partial class ImageCellPage : ContentPage


{
public ImageCellPage ()
{
InitializeComponent ();
listView.ItemTemplate = new DataTemplate (typeof(CustomCell));
}
}

Observe que o construtor para DataTemplate usa um tipo. O operador typeof obtém o tipo CLR para
CustomCell .
Alterações de contexto de associação
Ao associar a um tipo de célula personalizado BindableProperty instâncias, os controles de interface do usuário
exibindo as BindableProperty valores devem usar o OnBindingContextChanged substituição para definir os dados
a serem exibidos no cada célula, em vez do construtor de célula, conforme demonstrado no exemplo de código a
seguir:

public class CustomCell : ViewCell


{
Label nameLabel, ageLabel, locationLabel;

public static readonly BindableProperty NameProperty =


BindableProperty.Create ("Name", typeof(string), typeof(CustomCell), "Name");
public static readonly BindableProperty AgeProperty =
BindableProperty.Create ("Age", typeof(int), typeof(CustomCell), 0);
public static readonly BindableProperty LocationProperty =
BindableProperty.Create ("Location", typeof(string), typeof(CustomCell), "Location");

public string Name {


get { return(string)GetValue (NameProperty); }
set { SetValue (NameProperty, value); }
}

public int Age {


get { return(int)GetValue (AgeProperty); }
set { SetValue (AgeProperty, value); }
}

public string Location {


get { return(string)GetValue (LocationProperty); }
set { SetValue (LocationProperty, value); }
}
...

protected override void OnBindingContextChanged ()


{
base.OnBindingContextChanged ();

if (BindingContext != null) {
nameLabel.Text = Name;
ageLabel.Text = Age.ToString ();
locationLabel.Text = Location;
}
}
}

O OnBindingContextChanged substituto será chamado quando o BindingContextChanged evento aciona em


resposta ao valor da BindingContext a alteração de propriedade. Portanto, quando o BindingContext for
alterado, os controles de interface do usuário exibindo o BindableProperty valores devem definir seus dados.
Observe que o BindingContext devem ser verificados para uma null de valor, pois isso pode ser definido pelo
xamarin. Forms para coleta de lixo, que por sua vez resultará na OnBindingContextChanged substituir o que está
sendo chamado.
Como alternativa, os controles de interface do usuário podem associar à BindableProperty instâncias para exibir
seus valores, o que elimina a necessidade de substituir o OnBindingContextChanged método.

NOTE
Ao substituir OnBindingContextChanged , certifique-se de que a classe base OnBindingContextChanged método é
chamado para que os representantes registrados recebam o BindingContextChanged eventos.
No XAML, associando o tipo de célula personalizado a dados pode ser obtida conforme mostrado no exemplo
de código a seguir:

<ListView x:Name="listView">
<ListView.ItemTemplate>
<DataTemplate>
<local:CustomCell Name="{Binding Name}" Age="{Binding Age}" Location="{Binding Location}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

Isso vincula o Name , Age , e Location propriedades vinculáveis no CustomCell da instância, como o Name ,
Age , e Location propriedades de cada objeto na coleção subjacente.

A associação equivalente em C# é mostrada no exemplo de código a seguir:

var customCell = new DataTemplate (typeof(CustomCell));


customCell.SetBinding (CustomCell.NameProperty, "Name");
customCell.SetBinding (CustomCell.AgeProperty, "Age");
customCell.SetBinding (CustomCell.LocationProperty, "Location");

var listView = new ListView {


ItemsSource = people,
ItemTemplate = customCell
};

No iOS e Android, se o ListView reciclagem de elementos e a célula personalizada usa um renderizador


personalizado, o renderizador personalizado deve implementar corretamente a notificação de alteração de
propriedade. Quando as células são reutilizadas seus valores de propriedade serão alterado quando o contexto
de associação é atualizado ao de uma célula disponível, com PropertyChanged eventos sendo gerados. Para
obter mais informações, consulte personalizar uma ViewCell. Para obter mais informações sobre a reciclagem
de célula, consulte estratégia de cache.

Links relacionados
Criado em células (amostra)
Células personalizadas (amostra)
Associação de contexto alterado (amostra)
Personalizando a aparência de ListView
12/04/2019 • 10 minutes to read

Baixar o exemplo
ListView tem a capacidade de controlar a apresentação da lista, além de ViewCell instâncias para cada linha na
lista.

Agrupamento
Muitas vezes, grandes conjuntos de dados podem se tornar complicados quando apresentadas em uma lista de
rolagem contínua. Habilitação de agrupamento pode melhorar a experiência do usuário nesses casos, organizar
melhor o conteúdo e ativar os controles específicos da plataforma que facilitam a navegação de dados.
Quando o agrupamento é ativado para um ListView , uma linha de cabeçalho é adicionada para cada grupo.
Para habilitar o agrupamento:
Crie uma lista de listas (uma lista de grupos, cada grupo que está sendo uma lista de elementos).
Defina as ListView do ItemsSource à lista.
Definir IsGroupingEnabled como true.
Definir GroupDisplayBinding para associar a propriedade dos grupos que está sendo usada como o título do
grupo.
[Opcional] Definir GroupShortNameBinding para associar à propriedade que está sendo usada como o nome
curto para o grupo dos grupos. O nome curto é usado para as listas de salto (coluna direita no iOS ).
Comece criando uma classe para os grupos:

public class PageTypeGroup : List<PageModel>


{
public string Title { get; set; }
public string ShortName { get; set; } //will be used for jump lists
public string Subtitle { get; set; }
private PageTypeGroup(string title, string shortName)
{
Title = title;
ShortName = shortName;
}

public static IList<PageTypeGroup> All { private set; get; }


}

No código acima, All é a lista será dado ao nosso ListView como a origem da associação. Title e ShortName são
as propriedades que serão usadas para títulos de grupo.
Nesse estágio, All é uma lista vazia. Adicione um construtor estático para que a lista será preenchida no início do
programa:
static PageTypeGroup()
{
List<PageTypeGroup> Groups = new List<PageTypeGroup> {
new PageTypeGroup ("Alfa", "A"){
new PageModel("Amelia", "Cedar", new switchCellPage(),""),
new PageModel("Alfie", "Spruce", new switchCellPage(), "grapefruit.jpg"),
new PageModel("Ava", "Pine", new switchCellPage(), "grapefruit.jpg"),
new PageModel("Archie", "Maple", new switchCellPage(), "grapefruit.jpg")
},
new PageTypeGroup ("Bravo", "B"){
new PageModel("Brooke", "Lumia", new switchCellPage(),""),
new PageModel("Bobby", "Xperia", new switchCellPage(), "grapefruit.jpg"),
new PageModel("Bella", "Desire", new switchCellPage(), "grapefruit.jpg"),
new PageModel("Ben", "Chocolate", new switchCellPage(), "grapefruit.jpg")
}
}
All = Groups; //set the publicly accessible list
}

No código acima, também podemos chamar Add nos elementos de groups , que são instâncias do tipo
PageTypeGroup . Isso é possível porque PageTypeGroup herda de List<PageModel> . Este é um exemplo da lista de
padrão de listas observado acima.
Aqui está o XAML para exibir a lista agrupada:

<?xml version="1.0" encoding="UTF-8"?>


<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DemoListView.GroupingViewPage"
<ContentPage.Content>
<ListView x:Name="GroupedView"
GroupDisplayBinding="{Binding Title}"
GroupShortNameBinding="{Binding ShortName}"
IsGroupingEnabled="true">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Title}"
Detail="{Binding Subtitle}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
</ContentPage>

O resultado é o seguinte:
Observe que temos:
Definir GroupShortNameBinding para o ShortName propriedade definida em nossa classe de grupo
Definir GroupDisplayBinding para o Title propriedade definida em nossa classe de grupo
Definir IsGroupingEnabled como true
Alterado o ListView do ItemsSource à lista agrupada
Personalizar agrupamento
Se o agrupamento tiver sido habilitado na lista, o cabeçalho de grupo também pode ser personalizado.
Assim como o ListView tem um ItemTemplate para definir como as linhas são exibidas, ListView tem um
GroupHeaderTemplate .
Um exemplo de como personalizar o cabeçalho de grupo em XAML é mostrado aqui:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DemoListView.GroupingViewPage">
<ContentPage.Content>
<ListView x:Name="GroupedView"
GroupDisplayBinding="{Binding Title}"
GroupShortNameBinding="{Binding ShortName}"
IsGroupingEnabled="true">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Title}"
Detail="{Binding Subtitle}"
TextColor="#f35e20"
DetailColor="#503026" />
</DataTemplate>
</ListView.ItemTemplate>
<!-- Group Header Customization-->
<ListView.GroupHeaderTemplate>
<DataTemplate>
<TextCell Text="{Binding Title}"
Detail="{Binding ShortName}"
TextColor="#f35e20"
DetailColor="#503026" />
</DataTemplate>
</ListView.GroupHeaderTemplate>
<!-- End Group Header Customization -->
</ListView>
</ContentPage.Content>
</ContentPage>

Cabeçalhos e rodapés
É possível para um ListView apresentar um cabeçalho e rodapé que rolam com os elementos da lista. O cabeçalho
e rodapé podem ser cadeias de caracteres de texto ou um layout mais complicado. Observe que isso é separado do
seção grupos.
Você pode definir as Header e/ou Footer para uma cadeia de caracteres simple valor, ou você pode defini-las para
um layout mais complexo. Também há HeaderTemplate e FooterTemplate propriedades que permitem criam
layouts mais complexos para o cabeçalho e rodapé que suportam associação de dados.
Para criar um cabeçalho/rodapé simple, basta defina as propriedades de cabeçalho ou rodapé para o texto que
você deseja exibir. No código:

ListView HeaderList = new ListView() {


Header = "Header",
Footer = "Footer"
};

No XAML:

<ListView x:Name="HeaderList" Header="Header" Footer="Footer"></ListView>


Para criar um cabeçalho personalizado e um rodapé, defina os modos de exibição do cabeçalho e rodapé:

<ListView.Header>
<StackLayout Orientation="Horizontal">
<Label Text="Header"
TextColor="Olive"
BackgroundColor="Red" />
</StackLayout>
</ListView.Header>
<ListView.Footer>
<StackLayout Orientation="Horizontal">
<Label Text="Footer"
TextColor="Gray"
BackgroundColor="Blue" />
</StackLayout>
</ListView.Footer>
Visibilidade da barra de rolagem
ListView tem e VerticalScrollBarVisibility propriedades, o qual obtém ou
HorizontalScrollBarVisibility
definir um ScrollBarVisibility valor que representa quando a barra de rolagem horizontal ou vertical, está visível.
Ambas as propriedades podem ser definidas com os seguintes valores:
Defaultindica o comportamento padrão de barra de rolagem para a plataforma e é o valor padrão para o
HorizontalScrollBarVisibilitye VerticalScrollBarVisibility propriedades.
Always indica que as barras de rolagem será visíveis, mesmo quando o conteúdo se ajusta no modo de
exibição.
Never indica que as barras de rolagem não será visíveis, mesmo se o conteúdo não se encaixa no modo de
exibição.

Separadores de linha
As linhas do separador são exibidas entre ListView elementos por padrão no iOS e Android. Se você desejar
ocultar as linhas de separador no iOS e Android, defina o SeparatorVisibility propriedade em sua ListView. As
opções para SeparatorVisibility são:
Padrão -mostra uma linha separadora no iOS e Android.
Nenhum -oculta o separador em todas as plataformas.
Visibilidade do padrão:
C#:

SepratorDemoListView.SeparatorVisibility = SeparatorVisibility.Default;
XAML:

<ListView x:Name="SeparatorDemoListView" SeparatorVisibility="Default" />

Nenhum:
C#:

SepratorDemoListView.SeparatorVisibility = SeparatorVisibility.None;

XAML:

<ListView x:Name="SeparatorDemoListView" SeparatorVisibility="None" />


Você também pode definir a cor da linha do separador via o SeparatorColor propriedade:
C#:

SepratorDemoListView.SeparatorColor = Color.Green;

XAML:

<ListView x:Name="SeparatorDemoListView" SeparatorColor="Green" />


NOTE
Definindo cada uma dessas propriedades no Android, após o carregamento de ListView resulta em uma penalidade de
desempenho grande.

As alturas das linhas


Por padrão, todas as linhas em um ListView têm a mesma altura. ListView tem duas propriedades que podem ser
usadas para alterar esse comportamento:
HasUnevenRows – true / false valor, as linhas têm diferentes alturas se definido como true . Assume o padrão
de false .
RowHeight – Define a altura de cada a linha quando HasUnevenRows é false .

Você pode definir a altura de todas as linhas, definindo o RowHeight propriedade no ListView .
Altura de linha fixa personalizada
C#:

RowHeightDemoListView.RowHeight = 100;

XAML:

<ListView x:Name="RowHeightDemoListView" RowHeight="100" />


Linhas irregulares
Se você quiser linhas individuais ter alturas diferentes, você pode definir as HasUnevenRows propriedade para true .
Observe que as alturas das linhas não precisam ser definido manualmente uma vez HasUnevenRows foi definida
como true , pois as alturas serão calculadas automaticamente pelo xamarin. Forms.
C#:

RowHeightDemoListView.HasUnevenRows = true;

XAML:

<ListView x:Name="RowHeightDemoListView" HasUnevenRows="true" />


Redimensionamento de tempo de execução de linhas
Individuais ListView linhas podem ser redimensionadas por meio de programação em tempo de execução, desde
que o HasUnevenRows estiver definida como true . O Cell.ForceUpdateSize método atualiza o tamanho da célula,
mesmo quando não estiver visível no momento, conforme demonstrado no exemplo de código a seguir:

void OnImageTapped (object sender, EventArgs args)


{
var image = sender as Image;
var viewCell = image.Parent.Parent as ViewCell;

if (image.HeightRequest < 250) {


image.HeightRequest = image.Height + 100;
viewCell.ForceUpdateSize ();
}
}

O OnImageTapped manipulador de eventos é executado em resposta a uma Image em uma célula que está sendo
tocado e aumenta o tamanho do Image exibido na célula para que ela é exibida com facilidade.
Observe que há uma grande possibilidade de degradação do desempenho se esse recurso está sendo usado em
excesso.

Links relacionados
Agrupamento (amostra)
Exibição de renderizador personalizado (amostra)
Redimensionamento de linhas dinâmicas (amostra)
Notas de versão 1.4
Notas de versão 1.3
Interatividade do ListView
12/04/2019 • 9 minutes to read

Baixar o exemplo
ListView dá suporte a interagir com os dados que ele apresenta.

Toques de & seleção


O modo de seleção é controlado pela configuração de
ListView ListView.SelectionMode propriedade um valor a
ListViewSelectionMode enumeração:

Single indica que um único item pode ser selecionado, com o item selecionado que está sendo realçado. Este
é o valor padrão.
None indica que os itens não podem ser selecionados.

Quando um usuário toca um item, dois eventos são disparados:


ItemSelected Acionado quando um novo item é selecionado.
ItemTapped Acionado quando um item é tocado.
Tocar duas vezes o mesmo item será disparado duas ItemTapped eventos, mas será apenas acionar uma única
ItemSelected eventos.

NOTE
O ItemTappedEventArgs classe, que contém os argumentos de evento para o ItemTapped , o evento tem Group e
Item propriedades e uma ItemIndex propriedade cujo valor representa o índice no ListView do item tocado. Da
mesma forma, o SelectedItemChangedEventArgs classe, que contém os argumentos de evento para o ItemSelected
evento, tem um SelectedItem propriedade e um SelectedItemIndex propriedade cujo valor representa o índice no
ListView do item selecionado.

Quando o estiver definida como Single , os itens no ListView pode ser selecionado, a
SelectionMode
ItemSelected e ItemTapped eventos serão disparados e o SelectedItem propriedade será definida como o valor
do item selecionado.
Quando o estiver definida como None , os itens no ListView não pode ser selecionado, a
SelectionMode
ItemSelected evento não será disparado e o SelectedItem propriedade permanecerá null . No entanto,
ItemTapped eventos ainda serão acionados e o item tocado será realçado brevemente durante o toque.

Quando um item foi selecionado e o SelectionMode propriedade é alterada de Single para None , o
SelectedItem propriedade será definida como null e o ItemSelected evento será acionado com um null item.
As capturas de tela a seguir mostram uma ListView com o modo de seleção padrão:
Desabilitar seleção
Para desabilitar ListView conjunto de seleção a SelectionMode propriedade None :

<ListView ... SelectionMode="None" />

var listView = new ListView { ... SelectionMode = ListViewSelectionMode.None };

Ações de contexto
Muitas vezes, os usuários desejarão agir em um item em um ListView . Por exemplo, considere uma lista de
emails no aplicativo Mail. No iOS, você pode passar para excluir uma mensagem::

Ações de contexto podem ser implementadas em c# e XAML. Abaixo você encontrará guias específicos para
ambos, mas primeiro vamos dar uma olhada em alguns detalhes de implementação fundamentais para ambos.
Ações de contexto são criadas usando MenuItem s. Eventos de toque para MenuItems são acionados por
MenuItem em si, não o ListView. Isso é diferente de como os eventos de toque são tratados para células, onde o
ListView gera o evento em vez da célula. Porque o ListView está gerando o evento, seu manipulador de eventos
recebe informações de chave, como o qual o item foi selecionado ou tocado.
Por padrão, um MenuItem não tem nenhuma maneira de saber qual célula pertence. CommandParameter está
disponível em MenuItem para armazenar objetos, como o objeto por trás ViewCell de MenuItem.
CommandParameter pode ser definido em XAML e c#.

C#
Ações de contexto podem ser implementadas em qualquer Cell subclasse (contanto que ele não está sendo
usado como um cabeçalho de grupo), criando MenuItem s e adicioná-los para o ContextActions coleção para a
célula. Você tem as seguintes propriedades podem ser configuradas para a ação de contexto:
Texto – a cadeia de caracteres que aparece no item de menu.
Clicado – o evento quando o item é clicado.
IsDestructive – (opcional) quando for verdadeiro o item será renderizado da maneira diferente, no iOS.
Várias ações de contexto podem ser adicionadas a uma célula, no entanto, somente um deve ter IsDestructive
definido como true . O código a seguir demonstra como as ações de contexto seriam adicionadas a um ViewCell :

var moreAction = new MenuItem { Text = "More" };


moreAction.SetBinding (MenuItem.CommandParameterProperty, new Binding ("."));
moreAction.Clicked += async (sender, e) => {
var mi = ((MenuItem)sender);
Debug.WriteLine("More Context Action clicked: " + mi.CommandParameter);
};

var deleteAction = new MenuItem { Text = "Delete", IsDestructive = true }; // red background
deleteAction.SetBinding (MenuItem.CommandParameterProperty, new Binding ("."));
deleteAction.Clicked += async (sender, e) => {
var mi = ((MenuItem)sender);
Debug.WriteLine("Delete Context Action clicked: " + mi.CommandParameter);
};
// add to the ViewCell's ContextActions property
ContextActions.Add (moreAction);
ContextActions.Add (deleteAction);

XAML
MenuItem s também pode ser criado declarativamente em uma coleção de XAML. O XAML a seguir demonstra
uma célula personalizada com duas ações de contexto implementadas:

<ListView x:Name="ContextDemoList">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.ContextActions>
<MenuItem Clicked="OnMore" CommandParameter="{Binding .}"
Text="More" />
<MenuItem Clicked="OnDelete" CommandParameter="{Binding .}"
Text="Delete" IsDestructive="True" />
</ViewCell.ContextActions>
<StackLayout Padding="15,0">
<Label Text="{Binding title}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

No arquivo code-behind, verifique se o Clicked métodos são implementados:


public void OnMore (object sender, EventArgs e) {
var mi = ((MenuItem)sender);
DisplayAlert("More Context Action", mi.CommandParameter + " more context action", "OK");
}

public void OnDelete (object sender, EventArgs e) {


var mi = ((MenuItem)sender);
DisplayAlert("Delete Context Action", mi.CommandParameter + " delete context action", "OK");
}

NOTE
O NavigationPageRenderer para Android tem uma substituível UpdateMenuItemIcon método que pode ser usado para
carregar ícones de personalizado Drawable . Essa substituição torna possível usar as imagens de SVG como ícones em
MenuItem instâncias no Android.

Efetue pull para atualizar


Os usuários já conhecem movendo para baixo em uma lista de dados que será atualizada nessa lista. ListView dá
suporte a esse out-of-the-box. Para habilitar a funcionalidade de puxar para atualizar, defina
IsPullToRefreshEnabled para true :

<ListView ...
IsPullToRefreshEnabled="true" />

O código c# equivalente é:

listView.IsPullToRefreshEnabled = true;

Um controle giratório aparece durante a atualização, o que é preta por padrão. No entanto, a cor do controle
giratório pode ser alterada no iOS e Android, definindo o RefreshControlColor propriedade para um Color :

<ListView ...
IsPullToRefreshEnabled="true"
RefreshControlColor="Red" />

O código c# equivalente é:

listView.RefreshControlColor = Color.Red;

As capturas de tela a seguir mostram puxar para atualizar como o usuário está obtendo:
As capturas de tela a seguir mostram puxar para atualizar, depois que o usuário lançou o pull com o controle
giratório que está sendo mostrado enquanto o ListView está atualizando:

ListView é acionado o Refreshing evento para iniciar a atualização e o IsRefreshing propriedade será definida
como true . O código que é necessário para atualizar o conteúdo do ListView , em seguida, deve ser executado
após o manipulador de eventos para o Refreshing evento, ou pelo método executado pelo RefreshCommand . Uma
vez a ListView é atualizado, o IsRefreshing propriedade deve ser definida como false , ou o EndRefresh
método deve ser chamado, para indicar que a atualização for concluída.

NOTE
Ao definir uma RefreshCommand ,o CanExecute método do comando pode ser especificado para habilitar ou desabilitar o
comando.

Links relacionados
Interatividade do ListView (amostra)
Desempenho de ListView
12/04/2019 • 14 minutes to read

baixar o exemplo
Ao escrever aplicativos móveis, o desempenho é importante. Os usuários já conhecem rolagem suave e tempos
de carregamento rápido. Com falha atender às expectativas dos usuários custam avaliações na loja de aplicativos
ou no caso de um aplicativo de linha de negócios, custo organização tempo e dinheiro.
Embora ListView é um modo eficiente para exibir os dados, ele tem algumas limitações. Desempenho de
rolagem pode ser afetado ao usar células personalizadas, especialmente quando eles contenham hierarquias de
exibição profundamente aninhadas ou usam determinados layouts que exigem muita de medição. Felizmente,
existem técnicas que você pode usar para evitar um desempenho ruim.

Estratégia de cache
ListViews geralmente são usados para exibir dados muito mais do que pode caber na tela. Considere um
aplicativo de música, por exemplo. Uma biblioteca de músicas pode ter milhares de entradas. A abordagem
simple, o que seria criar uma linha para cada música, teria um desempenho ruim. Essa abordagem desperdiça
memória valiosa e pode reduzir a rolagem para um rastreamento. Outra abordagem é criar e destruir linhas como
dados são colocados na exibição. Isso exige a instanciação de constante e a limpeza de objetos de exibição, que
pode ser muito lento.
Para conservar memória, nativo ListView equivalentes para cada plataforma tem recursos internos para
reutilização de linhas. Apenas as células visíveis na tela são carregadas na memória e o conteúdo é carregado em
células existentes. Isso impede que o aplicativo precisar criar uma instância de milhares de objetos, economizando
tempo e memória.
Xamarin. Forms permite ListView célula usar novamente por meio de ListViewCachingStrategy enumeração, que
tem os seguintes valores:

public enum ListViewCachingStrategy


{
RetainElement, // the default value
RecycleElement,
RecycleElementAndDataTemplate
}

NOTE
A Universal Windows Platform (UWP) ignora a RetainElement estratégia, de cache porque ele sempre usa o cache para
melhorar o desempenho. Portanto, por padrão se comporta como se o RecycleElement estratégia de cache é aplicada.

RetainElement
O RetainElement estratégia de cache Especifica que o ListView gerará uma célula para cada item na lista, e é o
padrão ListView comportamento. Geralmente, ele deve ser usado nas seguintes circunstâncias:
Quando cada célula tem um grande número de associações (20-30 ou mais).
Quando o modelo de célula é alterado com frequência.
Quando testar revela que o RecycleElement armazenar em cache os resultados de estratégia em uma
velocidade de execução reduzida.
É importante reconhecer as consequências do RetainElement estratégia de cache ao trabalhar com células
personalizadas. Qualquer código de inicialização de célula precisará executar para a criação de cada célula, que
pode ser várias vezes por segundo. Nessa circunstância, técnicas de layout que eram um problemas em uma
página, como uso de vários aninhados StackLayout instâncias, se tornar afunilamentos de desempenho quando
elas são configuradas e destruída em tempo real conforme o usuário rolar.
RecycleElement
O RecycleElement estratégia de cache Especifica que o ListView tenta minimizar sua velocidade de execução e o
volume de memória por meio da reciclagem de células da lista. Esse modo não oferece sempre uma melhoria de
desempenho e teste deve ser executado para determinar todos os aprimoramentos. No entanto, ele geralmente é
a opção preferencial e deve ser usado nas seguintes circunstâncias:
Quando cada célula tem um pequeno número moderado de associações.
Quando cada célula BindingContext define todos os dados da célula.
Quando cada célula é basicamente semelhante, com o modelo de célula inalterável.
Durante a virtualização, a célula terá seu contexto de associação atualizado e, portanto, se um aplicativo usa esse
modo deve garantir que as atualizações de contexto de associação são manipuladas corretamente. Todos os dados
sobre a célula devem ser provenientes do contexto de associação ou poderão ocorrer erros de consistência. Isso
pode ser feito usando vinculação de dados para exibir dados da célula. Como alternativa, os dados da célula
devem ser definidos no OnBindingContextChanged substituir, em vez de no construtor da célula personalizada,
conforme demonstrado no exemplo de código a seguir:

public class CustomCell : ViewCell


{
Image image = null;

public CustomCell ()
{
image = new Image();
View = image;
}

protected override void OnBindingContextChanged ()


{
base.OnBindingContextChanged ();

var item = BindingContext as ImageItem;


if (item != null) {
image.Source = item.ImageUrl;
}
}
}

Para obter mais informações, consulte alterações de contexto de associação.


No iOS e Android, se células usam renderizadores personalizados, eles devem garantir que a notificação de
alteração de propriedade é implementada corretamente. Quando as células são reutilizadas seus valores de
propriedade serão alterado quando o contexto de associação é atualizado ao de uma célula disponível, com
PropertyChanged eventos sendo gerados. Para obter mais informações, consulte personalizar uma ViewCell.

RecycleElement com um DataTemplateSelector


Quando um ListView usa um DataTemplateSelector para selecionar um DataTemplate , a RecycleElement de
cache estratégia não armazena em cache DataTemplate s. Em vez disso, um DataTemplate é selecionado para cada
item de dados na lista.
NOTE
O RecycleElement estratégia de cache tem um pré-requisito, introduzido no xamarin. Forms 2.4, que, quando um
DataTemplateSelector é solicitado a selecionar um DataTemplate cada DataTemplate deve retornar o mesmo
ViewCell tipo. Por exemplo, dada uma ListView com um DataTemplateSelector que pode retornar
MyDataTemplateA (onde MyDataTemplateA retorna um ViewCell do tipo MyViewCellA ), ou MyDataTemplateB (onde
MyDataTemplateB retorna um ViewCell do tipo MyViewCellB ), quando MyDataTemplateA será retornada a ele deve
retornar MyViewCellA ou uma exceção será gerada.

RecycleElementAndDataTemplate
O RecycleElementAndDataTemplate estratégia de cache baseia-se a RecycleElement estratégia de cache, além disso,
garantindo que, quando um ListView usa um DataTemplateSelector para selecionar um DataTemplate ,
DataTemplate s são armazenados em cache pelo tipo de item na lista. Portanto, DataTemplate s são selecionados de
uma vez por tipo de item, em vez de uma vez por instância do item.

NOTE
O RecycleElementAndDataTemplate estratégia de cache tem um pré-requisito que o DataTemplate s retornado pelo
DataTemplateSelector deve usar o DataTemplate construtor que usa um Type .

Definindo a estratégia de cache


O ListViewCachingStrategy valor de enumeração é especificado com um ListView sobrecarga de construtor,
conforme mostrado no exemplo de código a seguir:

var listView = new ListView(ListViewCachingStrategy.RecycleElement);

No XAML, defina o CachingStrategy atributo conforme mostrado no código a seguir:

<ListView CachingStrategy="RecycleElement">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
...
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

Isso tem o mesmo efeito que definir o argumento de estratégia de cache do construtor no C#; Observe que não há
nenhuma CachingStrategy propriedade ListView .
Definir a estratégia de cache em uma subclasse ListView
Definindo o CachingStrategy atributo do XAML em uma subclasse ListView não produzirá o comportamento
desejado, porque não há nenhum CachingStrategy propriedade ListView . Além disso, se XAMLC é habilitada, a
seguinte mensagem de erro será produzida: nenhuma propriedade, a propriedade associável ou evento
encontrado para 'CachingStrategy'
A solução para esse problema é para especificar um construtor na subclasse ListView que aceita um
ListViewCachingStrategy parâmetro e o passa para a classe base:
public class CustomListView : ListView
{
public CustomListView (ListViewCachingStrategy strategy) : base (strategy)
{
}
...
}

Em seguida, a ListViewCachingStrategy valor de enumeração pode ser especificado na XAML usando o


x:Arguments sintaxe:

<local:CustomListView>
<x:Arguments>
<ListViewCachingStrategy>RecycleElement</ListViewCachingStrategy>
</x:Arguments>
</local:CustomListView>

Melhorando o desempenho de ListView


Há muitas técnicas para melhorar o desempenho de um ListView :
Associar o ItemsSource propriedade para um IList<T> coleção em vez de um IEnumerable<T> coleção, pois
IEnumerable<T> coleções não dão suporte a acesso aleatório.
Use as células internas (como TextCell / SwitchCell ), em vez de ViewCell sempre que você pode.
Use menos elementos. Por exemplo, considere usar um único FormattedString rótulo em vez de vários rótulos.
Substitua os ListView com um TableView ao exibir dados não homogêneos – ou seja, os dados de diferentes
tipos.
Limite o uso de Cell.ForceUpdateSize método. Se o uso excessivo, ele prejudicará o desempenho.
No Android, evite definir um ListView da visibilidade de separador de linha ou a cor, depois que ele foi
instanciado, já que resulta em uma penalidade de desempenho grande.
Evite alterar o layout da célula com base nas BindingContext . Isso resulta em grandes custos de inicialização e
de layout.
Evite hierarquias de layout profundamente aninhadas. Use AbsoluteLayout ou Grid para ajudar a reduzir o
aninhamento.
Evite específico LayoutOptions diferente de Fill (preenchimento é o mais barato de computação).
Evite colocar uma ListView dentro de um ScrollView pelos seguintes motivos:
O ListView implementa seu próprio rolagem.
O ListView não receberão qualquer gestos, como eles serão manipulados pelo pai ScrollView .
O ListView pode apresentar um cabeçalho personalizado e um rodapé que rola com os elementos da
lista, oferecendo potencialmente a funcionalidade que o ScrollView foi usado para. Para obter mais
informações, consulte cabeçalhos e rodapés.
Considere um renderizador personalizado se você precisar de um design muito específico e complexo,
apresentado em suas células.
AbsoluteLayout tem o potencial para executar layouts sem uma chamada única medida. Isso torna muito
poderoso para desempenho. Se AbsoluteLayout não pode ser usado, considere RelativeLayout . Se usando
RelativeLayout , passar as restrições diretamente será consideravelmente mais rápido do que usar a API de
expressão. Isso ocorre porque a API de expressão usa JIT e no iOS a árvore tem deve ser interpretado, que é mais
lento. A expressão de API é adequada para layouts de página em que ele apenas necessário layout inicial e a
rotação, mas em ListView , onde ele é executado constantemente durante a rolagem, ele reduz o desempenho.
Criar um renderizador personalizado para um ListView ou suas células é uma abordagem para reduzir o efeito
de cálculos de layout no desempenho de rolagem. Para obter mais informações, consulte Personalizando um
ListView e personalizar uma ViewCell.

Links relacionados
Exibição de renderizador personalizado (amostra)
ViewCell de renderizador personalizado (amostra)
ListViewCachingStrategy
Mapa do xamarin. Forms
12/04/2019 • 12 minutes to read

baixar o exemplo
Xamarin. Forms usa o mapa nativo APIs em cada plataforma.
Xamarin.Forms.Maps usa as APIs de mapa nativa em cada plataforma. Isso fornece uma experiência de mapas
rápido e familiar para os usuários, mas significa que algumas etapas de configuração são necessários para
atender aos requisitos de API cada plataformas. Uma vez configurado, o Map controlar funciona exatamente
como qualquer outro elemento de xamarin. Forms em código comum.
O controle de mapa tenha sido usado na MapsSample sample, que é mostrado abaixo.

Funcionalidade de mapa pode ser aprimorada ainda mais com a criação de um mapear um renderizador
personalizado.

Inicialização de mapas
Ao adicionar mapas a um aplicativo xamarin. Forms, Xamarin.Forms.Maps é um pacote do NuGet separado
que você deve adicionar a todos os projetos na solução. No Android, isso também tem uma dependência no
GooglePlayServices (NuGet outro), que é baixada automaticamente quando você adiciona
Xamarin.Forms.Maps.
Depois de instalar o pacote do NuGet, um código de inicialização é necessária em cada projeto de aplicativo
após o Xamarin.Forms.Forms.Init chamada de método. Para iOS, use o seguinte código:

Xamarin.FormsMaps.Init();

No Android, você deve passar os mesmos parâmetros que Forms.Init :

Xamarin.FormsMaps.Init(this, bundle);

Para a Universal Windows Platform (UWP ), use o seguinte código:

Xamarin.FormsMaps.Init("INSERT_AUTHENTICATION_TOKEN_HERE");
Adicione esta chamada nos seguintes arquivos para cada plataforma:
iOS -arquivo AppDelegate.cs, além de FinishedLaunching método.
Android -MainActivity.cs de arquivos, além de OnCreate método.
UWP -arquivo MainPage.xaml.cs, além de MainPage construtor.
Depois que o pacote do NuGet foi adicionado e o método de inicialização é chamado dentro de cada aplicativo,
Xamarin.Forms.Maps APIs podem ser usadas no código do projeto compartilhado ou projeto de biblioteca .NET
Standard comum.

Configuração de plataforma
Etapas de configuração adicionais são necessários em algumas plataformas antes do mapa será exibido.
iOS
Para acessar os serviços de localização no iOS, você deve definir as seguintes chaves Info. plist:
iOS 11
NSLocationWhenInUseUsageDescription – Para usar os serviços de localização quando o aplicativo está
em uso
NSLocationAlwaysAndWhenInUseUsageDescription – Para usar os serviços de localização em todos os
momentos
iOS 10 e versões anteriores
NSLocationWhenInUseUsageDescription – Para usar os serviços de localização quando o aplicativo está
em uso
NSLocationAlwaysUsageDescription – Para usar os serviços de localização em todos os momentos

Para dar suporte a iOS 11 e versões anteriores, você pode incluir todos os três chaves:
NSLocationWhenInUseUsageDescription , NSLocationAlwaysAndWhenInUseUsageDescription , e
NSLocationAlwaysUsageDescription .

A representação XML para essas chaves na Info. plist é mostrado abaixo. Você deve atualizar o string
valores para refletir como seu aplicativo está usando as informações de local:

<key>NSLocationAlwaysUsageDescription</key>
<string>Can we use your location at all times?</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Can we use your location when your app is being used?</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Can we use your location at all times?</string>

O Info. plist entradas também podem ser adicionadas no fonte exibição ao editar o Info. plist arquivo:

Android
Para usar o API do Google Maps v2 no Android, você deve gerar uma chave de API e adicioná-lo ao seu
projeto Android. Siga as instruções no documento Xamarin na obtendo uma chave de API do Google Maps v2.
Depois de seguir essas instruções, cole a chave de API na androidmanifest arquivo (Exibir código-fonte e
localizar/atualizar o seguinte elemento):
<application ...>
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="YOUR_API_KEY" />
</application>

Sem uma chave de API válida no controle maps será exibido como uma caixa cinza no Android.

NOTE
Observe que, na ordem de seu APK acessar o Google Maps, você deve incluir as impressões digitais de SHA-1 e nomes
para cada repositório de chaves (depuração e versão) que você usa para assinar o APK do pacote. Por exemplo, se você
usar um computador para outro computador para gerar a versão APK e de depuração, você deve incluir a impressão
digital SHA-1 do certificado do repositório de chaves de depuração do primeiro computador e a impressão digital do
certificado SHA-1 do repositório de chaves de versão o segundo computador. Lembre-se também ao editar as
credenciais de chave, se o aplicativo nome do pacote alterações. Ver obtendo uma chave de API do Google Maps v2.

Você também precisará habilitar as permissões apropriadas pelo botão direito do mouse no projeto do
Android e selecionando opções > Build > aplicativo Android e tique o seguinte:
AccessCoarseLocation
AccessFineLocation
AccessLocationExtraCommands
AccessMockLocation
AccessNetworkState
AccessWifiState
Internet

Alguns deles são mostradas na captura de tela abaixo:

As duas últimas são necessárias porque os aplicativos exigem uma conexão de rede para baixar os dados de
mapa. Leia sobre o Android permissões para saber mais.
Plataforma Universal do Windows
Para usar mapas na plataforma Universal do Windows, você deve gerar um token de autorização. Para obter
mais informações, consulte solicitar uma chave de autenticação de mapas no MSDN.
O token de autenticação deve ser especificado, em seguida, no FormsMaps.Init("AUTHORIZATION_TOKEN")
chamada de método, para autenticar o aplicativo com o Bing Maps.

Uso de mapas
Consulte a MapPage.cs na amostra MobileCRM para obter um exemplo de como o controle de mapa pode ser
usado no código. Um simples MapPage classe pode parecer com este - aviso de que um novo MapSpan é criado
para posicionar a exibição do mapa:
public class MapPage : ContentPage {
public MapPage() {
var map = new Map(
MapSpan.FromCenterAndRadius(
new Position(37,-122), Distance.FromMiles(0.3))) {
IsShowingUser = true,
HeightRequest = 100,
WidthRequest = 960,
VerticalOptions = LayoutOptions.FillAndExpand
};
var stack = new StackLayout { Spacing = 0 };
stack.Children.Add(map);
Content = stack;
}
}

Tipo de mapa
O conteúdo do mapa também pode ser alterado definindo o MapType propriedade, para mostrar um mapa
rodoviário regular (o padrão), imagens de satélite ou uma combinação de ambos.

map.MapType == MapType.Street;

Válido MapType valores são:


Híbrido
Satélite
Rua (o padrão)
Região do mapa e MapSpan
Conforme mostrado no trecho de código acima, fornecendo um MapSpan instância para um construtor de
mapa define a exibição inicial (o ponto central, e o nível de zoom) do mapa quando ele for carregado. O
MoveToRegion método da classe map, em seguida, pode ser usado para alterar o nível de zoom ou de posição
do mapa. Há duas maneiras para criar um novo MapSpan instância:
MapSpan.FromCenterAndRadius() -um método estático para criar um período de um Position e
especificando um Distance .
New () de MapSpan -construtor que usa um Position e os graus de latitude e longitude para exibir.

Para alterar o nível de zoom do mapa sem alterar o local, crie um novo MapSpan usando o local atual do
VisibleRegion.Center propriedade do controle de mapa. Um Slider poderia ser usado para controle de zoom
do mapa como este (no entanto, aumentar o zoom diretamente no controle de mapa, atualmente não é
possível atualizar o valor do controle deslizante):

var slider = new Slider (1, 18, 1);


slider.ValueChanged += (sender, e) => {
var zoomLevel = e.NewValue; // between 1 and 18
var latlongdegrees = 360 / (Math.Pow(2, zoomLevel));
map.MoveToRegion(new MapSpan (map.VisibleRegion.Center, latlongdegrees, latlongdegrees));
};
Pinos de mapa
Locais podem ser marcados no mapa com Pin objetos.

var position = new Position(37,-122); // Latitude, Longitude


var pin = new Pin {
Type = PinType.Place,
Position = position,
Label = "custom pin",
Address = "custom detail info"
};
map.Pins.Add(pin);

PinType pode ser definido como um dos valores a seguir, que podem afetar a maneira que o pin é renderizado
(dependendo da plataforma):
Genérico
Local
SavedPin
SearchResult

Usando XAML
Mapas também podem ser posicionados em layouts XAML, conforme mostrado neste trecho de código.

<?xml version="1.0" encoding="UTF-8" ?>


<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:maps="clr-namespace:Xamarin.Forms.Maps;assembly=Xamarin.Forms.Maps"
x:Class="MapDemo.MapPage">
<StackLayout VerticalOptions="StartAndExpand" Padding="30">
<maps:Map WidthRequest="320" HeightRequest="200"
x:Name="MyMap"
IsShowingUser="true"
MapType="Hybrid" />
</StackLayout>
</ContentPage>

NOTE
Adicional xmlns definição de namespace é necessário para referenciar os controles Xamarin.Forms.Maps.

O MapRegion e Pins pode ser definido no código usando o MyMap referência (ou o mapa de tudo o que é
chamado).

MyMap.MoveToRegion(
MapSpan.FromCenterAndRadius(
new Position(37,-122), Distance.FromMiles(1)));

Preenchendo um mapa com dados usando a associação de dados


O Map classe também expõe as propriedades a seguir:
ItemsSource – Especifica a coleção de IEnumerable itens a serem exibidos.
ItemTemplate – Especifica o DataTemplate para aplicar a cada item na coleção de itens exibidos.

Portanto, uma Map podem ser populados com dados por meio de associação de dados para associar seu
ItemsSource propriedade para um IEnumerable coleção:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:maps="clr-namespace:Xamarin.Forms.Maps;assembly=Xamarin.Forms.Maps"
x:Class="WorkingWithMaps.PinItemsSourcePage">
<Grid>
...
<maps:Map x:Name="map"
ItemsSource="{Binding Locations}">
<maps:Map.ItemTemplate>
<DataTemplate>
<maps:Pin Position="{Binding Position}"
Address="{Binding Address}"
Label="{Binding Description}" />
</DataTemplate>
</maps:Map.ItemTemplate>
</maps:Map>
...
</Grid>
</ContentPage>

O ItemsSource associa dados de propriedade para o Locations propriedade do modelo de exibição


conectados, que retorna um ObservableCollection de Location objetos, que é um tipo personalizado. Cada
Location objeto define Address e Description propriedades do tipo string e um Position propriedade do
tipo Position .
A aparência de cada item na IEnumerable coleção é definida pela configuração o ItemTemplate propriedade
para um DataTemplate que contém um Pin que associa para dados de objeto propriedades adequadas.
As capturas de tela a seguir mostram uma Map exibindo um Pin usando vinculação de dados de coleção:
Links relacionados
MapsSample
Mapear o renderizador personalizado
Amostras do Xamarin.Forms
Seletor de xamarin. Forms
12/04/2019 • 3 minutes to read

O modo de exibição do seletor é um controle para selecionar um item de texto de uma lista de dados.
O xamarin. Forms Picker exibe uma lista curta de itens, do qual o usuário pode selecionar um item. Picker
Define as propriedades a seguir:
Title do tipo string , cujo padrão é null .
TitleColor do tipo Color , a cor usada para exibir o Title texto.
ItemsSource do tipo IList , a lista de origem de itens a serem exibidos, cujo padrão é null .
SelectedIndex do tipo int , o índice do item selecionado, cujo padrão é -1.
SelectedItem do tipo object , o item selecionado, cujo padrão é null .
TextColor do tipo Color , a cor usada para exibir o texto, cujo padrão é Color.Default .
FontAttributes do tipo FontAttributes , cujo padrão é FontAtributes.None .
FontFamily do tipo string , cujo padrão é null .
FontSize do tipo double , cujo padrão é de -1,0.

Todas as propriedades têm o respaldo BindableProperty objetos, o que significa que eles podem ser estilizados e
as propriedades podem ser alvos de vinculações de dados. O SelectedIndex e SelectedItem propriedades têm
um modo de associação padrão do BindingMode.TwoWay , que significa que elas possam ser destinos de
vinculações de dados em um aplicativo que usa o Model-View -ViewModel (MVVM ) arquitetura. Para obter
informações sobre como definir propriedades de fonte, consulte fontes.
Um Picker não mostra todos os dados quando ele é exibido pela primeira vez. Em vez disso, o valor de sua
Title propriedade é mostrada como um espaço reservado nas plataformas Android e iOS:

Quando o Picker ganhos foco, seus dados é exibido e o usuário pode selecionar um item:
O Picker dispara uma SelectedIndexChanged evento quando o usuário seleciona um item. Após a seleção, o item
selecionado é exibido pelo Picker :

Existem duas técnicas para preencher uma Picker com dados:


Definindo o ItemsSource propriedade aos dados a serem exibidos. Esta é a técnica recomendada. Para obter
mais informações, consulte definindo a propriedade ItemsSource de um seletor.
Adicionando dados a ser exibida para o Items coleção. Essa técnica foi o processo original para popular uma
Picker com os dados. Para obter mais informações, consulte adicionando dados à coleção de itens do seletor.

Links relacionados
Seletor
Definindo a propriedade ItemsSource de um seletor
12/04/2019 • 7 minutes to read

baixar o exemplo
O modo de exibição do seletor é um controle para selecionar um item de texto de uma lista de dados. Este artigo
explica como preencher um seletor de dados, definindo a propriedade ItemsSource e como responder a seleção de
item pelo usuário.
Xamarin. Forms 2.3.4 aprimorou o Picker exibição adicionando a capacidade para preenchê-lo com dados,
definindo sua ItemsSource propriedade e para recuperar o item selecionado do SelectedItem propriedade. Além
disso, a cor do texto do item selecionado pode ser alterada definindo a TextColor propriedade como um Color .

Populando um seletor de data


Um Picker podem ser populados com dados, definindo sua ItemsSource propriedade para um IList coleção.
Cada item na coleção deve ser de ou derivado de, digite object . Itens podem ser adicionados no XAML,
inicializando o ItemsSource propriedade de uma matriz de itens:

<Picker x:Name="picker"
Title="Select a monkey"
TitleColor="Red">
<Picker.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Baboon</x:String>
<x:String>Capuchin Monkey</x:String>
<x:String>Blue Monkey</x:String>
<x:String>Squirrel Monkey</x:String>
<x:String>Golden Lion Tamarin</x:String>
<x:String>Howler Monkey</x:String>
<x:String>Japanese Macaque</x:String>
</x:Array>
</Picker.ItemsSource>
</Picker>

NOTE
Observe que o x:Array elemento requer um Type atributo que indica o tipo dos itens na matriz.

O código c# equivalente é mostrado abaixo:

var monkeyList = new List<string>();


monkeyList.Add("Baboon");
monkeyList.Add("Capuchin Monkey");
monkeyList.Add("Blue Monkey");
monkeyList.Add("Squirrel Monkey");
monkeyList.Add("Golden Lion Tamarin");
monkeyList.Add("Howler Monkey");
monkeyList.Add("Japanese Macaque");

var picker = new Picker { Title = "Select a monkey", TitleColor = Color.Red };


picker.ItemsSource = monkeyList;
Respondendo a seleção de item
Um Picker dá suporte à seleção de um item por vez. Quando um usuário seleciona um item, o
SelectedIndexChanged evento é acionado, o SelectedIndex propriedade é atualizada em um inteiro que representa
o índice do item selecionado na lista e o SelectedItem propriedade é atualizada para o object que representa o
item selecionado. O SelectedIndex propriedade é um número com base em zero que indica o item que o usuário
selecionado. Se nenhum item for selecionado, que é o caso quando o Picker primeiro é criado e inicializado,
SelectedIndex será -1.

NOTE
Item de comportamento de seleção em um Picker podem ser personalizadas no iOS com uma plataforma específica. Para
obter mais informações, consulte seleção de Item de seletor controlando.

O exemplo de código a seguir mostra como recuperar o SelectedItem valor da propriedade a Picker no XAML:

<Label Text="{Binding Source={x:Reference picker}, Path=SelectedItem}" />

O código c# equivalente é mostrado abaixo:

var monkeyNameLabel = new Label();


monkeyNameLabel.SetBinding(Label.TextProperty, new Binding("SelectedItem", source: picker));

Além disso, um manipulador de eventos pode ser executado quando o SelectedIndexChanged evento é acionado:

void OnPickerSelectedIndexChanged(object sender, EventArgs e)


{
var picker = (Picker)sender;
int selectedIndex = picker.SelectedIndex;

if (selectedIndex != -1)
{
monkeyNameLabel.Text = (string)picker.ItemsSource[selectedIndex];
}
}

Esse método obtém o SelectedIndex valor de propriedade e usa o valor para recuperar o item selecionado dos
ItemsSource coleção. Isso é funcionalmente equivalente ao recuperar o item selecionado dos SelectedItem
propriedade. Observe que cada item de ItemsSource coleção é do tipo object e, portanto, deve ser convertido em
um string para exibição.

NOTE
Um Picker pode ser inicializado para exibir um item específico, configurando as SelectedIndex ou SelectedItem
propriedades. No entanto, essas propriedades devem ser definidas depois de inicializar o ItemsSource coleção.

Preenchendo um seletor com dados usando a associação de dados


Um Picker pode ser também preenchido com dados usando associação de dados para associar seu ItemsSource
propriedade para um IList coleção. No XAML, isso é feito com o Binding extensão de marcação:
<Picker Title="Select a monkey"
TitleColor="Red"
ItemsSource="{Binding Monkeys}"
ItemDisplayBinding="{Binding Name}" />

O código c# equivalente é mostrado abaixo:

var picker = new Picker { Title = "Select a monkey", TitleColor = Color.Red };


picker.SetBinding(Picker.ItemsSourceProperty, "Monkeys");
picker.ItemDisplayBinding = new Binding("Name");

O ItemsSource associa dados de propriedade para o Monkeys propriedade do modelo de exibição conectados, que
retorna um IList<Monkey> coleção. O seguinte exemplo de código mostra o Monkey classe, que contém quatro
propriedades:

public class Monkey


{
public string Name { get; set; }
public string Location { get; set; }
public string Details { get; set; }
public string ImageUrl { get; set; }
}

Ao associar a uma lista de objetos, o Picker deve ser informado de qual propriedade a ser exibida de cada objeto.
Isso é feito definindo a ItemDisplayBinding propriedade para a propriedade necessária de cada objeto. Nos
exemplos de código acima, o Picker estiver definido para exibir cada Monkey.Name valor da propriedade.
Respondendo a seleção de item
Associação de dados pode ser usada para definir um objeto com o SelectedItem valor da propriedade quando ele
é alterado:

<Picker Title="Select a monkey"


TitleColor="Red"
ItemsSource="{Binding Monkeys}"
ItemDisplayBinding="{Binding Name}"
SelectedItem="{Binding SelectedMonkey}" />
<Label Text="{Binding SelectedMonkey.Name}" ... />
<Label Text="{Binding SelectedMonkey.Location}" ... />
<Image Source="{Binding SelectedMonkey.ImageUrl}" ... />
<Label Text="{Binding SelectedMonkey.Details}" ... />

O código c# equivalente é mostrado abaixo:


var picker = new Picker { Title = "Select a monkey", TitleColor = Color.Red };
picker.SetBinding(Picker.ItemsSourceProperty, "Monkeys");
picker.SetBinding(Picker.SelectedItemProperty, "SelectedMonkey");
picker.ItemDisplayBinding = new Binding("Name");

var nameLabel = new Label { ... };


nameLabel.SetBinding(Label.TextProperty, "SelectedMonkey.Name");

var locationLabel = new Label { ... };


locationLabel.SetBinding(Label.TextProperty, "SelectedMonkey.Location");

var image = new Image { ... };


image.SetBinding(Image.SourceProperty, "SelectedMonkey.ImageUrl");

var detailsLabel = new Label();


detailsLabel.SetBinding(Label.TextProperty, "SelectedMonkey.Details");

O SelectedItem associa dados de propriedade para o SelectedMonkey propriedade do modelo de exibição


conectado, o que é do tipo Monkey . Portanto, quando o usuário seleciona um item na Picker , o SelectedMonkey
propriedade será definida para selecionado Monkey objeto. O SelectedMonkey dados de objeto são exibidos na
interface do usuário por Label e Image modos de exibição:

NOTE
Observe que o SelectedItem e SelectedIndex ambas as propriedades dá suporte a associações bidirecionais por padrão.

Links relacionados
Demonstração de seletor (amostra)
Monkey App (amostra)
Seletor de associável (amostra)
Seletor de API
Adicionar dados à coleção de itens do seletor
12/04/2019 • 3 minutes to read

baixar o exemplo
O modo de exibição do seletor é um controle para selecionar um item de texto de uma lista de dados. Este artigo
explica como preencher um seletor de dados, adicionando -o à coleção de itens e como responder a seleção de
item pelo usuário.

Populando um seletor de data


Antes de xamarin. Forms 2.3.4, o processo de preenchimento de uma Picker com dados era adicionar os dados a
ser exibida para somente leitura Items coleção, que é do tipo IList<string> . Cada item na coleção deve ser do
tipo string . Itens podem ser adicionados no XAML, inicializando o Items propriedade com uma lista de
x:String itens:

<Picker Title="Select a monkey"


TitleColor="Red">
<Picker.Items>
<x:String>Baboon</x:String>
<x:String>Capuchin Monkey</x:String>
<x:String>Blue Monkey</x:String>
<x:String>Squirrel Monkey</x:String>
<x:String>Golden Lion Tamarin</x:String>
<x:String>Howler Monkey</x:String>
<x:String>Japanese Macaque</x:String>
</Picker.Items>
</Picker>

O código c# equivalente é mostrado abaixo:

var picker = new Picker { Title = "Select a monkey", TitleColor = Color.Red };


picker.Items.Add("Baboon");
picker.Items.Add("Capuchin Monkey");
picker.Items.Add("Blue Monkey");
picker.Items.Add("Squirrel Monkey");
picker.Items.Add("Golden Lion Tamarin");
picker.Items.Add("Howler Monkey");
picker.Items.Add("Japanese Macaque");

Além de adicionar dados usando o Items.Add método, dados também podem ser inseridos na coleção usando o
Items.Insert método.

Respondendo a seleção de item


Um Picker dá suporte à seleção de um item por vez. Quando um usuário seleciona um item, o
SelectedIndexChanged evento é acionado e o SelectedIndex propriedade é atualizada em um inteiro que
representa o índice do item selecionado na lista. O SelectedIndex propriedade é um número com base em zero
que indica o item selecionado pelo usuário. Se nenhum item for selecionado, que é o caso quando o Picker é
criado e inicializado, primeiramente SelectedIndex será -1.
NOTE
Item de comportamento de seleção em um Picker podem ser personalizadas no iOS com uma plataforma específica. Para
obter mais informações, consulte seleção de Item de seletor controlando.

O seguinte exemplo de código mostra a OnPickerSelectedIndexChanged método de manipulador de eventos, que é


executado quando o SelectedIndexChanged evento é acionado:

void OnPickerSelectedIndexChanged(object sender, EventArgs e)


{
var picker = (Picker)sender;
int selectedIndex = picker.SelectedIndex;

if (selectedIndex != -1)
{
monkeyNameLabel.Text = picker.Items[selectedIndex];
}
}

Esse método obtém o SelectedIndex valor de propriedade e usa o valor para recuperar o item selecionado dos
Items coleção. Porque cada item na Items coleção é um string , eles podem ser exibidos por uma Label sem a
necessidade de uma conversão.

NOTE
Um Picker pode ser inicializado para exibir um item específico, configurando as SelectedIndex propriedade. No entanto,
o SelectedIndex propriedade deve ser definida depois de inicializar o Items coleção.

Links relacionados
Demonstração de seletor (amostra)
Seletor
Controle deslizante do xamarin. Forms
12/04/2019 • 22 minutes to read

baixar o exemplo
Use um controle deslizante para selecionar um intervalo de valores contínuos.
O xamarin. Forms Slider é uma barra horizontal que pode ser manipulada pelo usuário para selecionar um
double valor de um intervalo contínuo.

O Slider define três propriedades do tipo double :


Minimum é o mínimo do intervalo, com um valor padrão de 0.
Maximum é o máximo do intervalo, com um valor padrão de 1.
Value é o valor do controle deslizante, que pode variar entre Minimum e Maximum e tem um valor padrão de 0.
Todas as três propriedades são apoiadas por BindableProperty objetos. O Value propriedade tem um modo de
associação padrão de BindingMode.TwoWay , que significa que ele é adequado como uma origem da associação em
um aplicativo que usa o Model-View -ViewModel (MVVM ) arquitetura.

WARNING
Internamente, o Slider garante que Minimum é menor que Maximum . Se Minimum ou Maximum nunca são definidas,
de modo que Minimum é não é menor que Maximum , uma exceção será gerada. Consulte a precauções seção abaixo para
obter mais informações sobre como o Minimum e Maximum propriedades.

O Slider impõe a Value propriedade para que ele fique entre Minimum e Maximum , inclusive. Se o Minimum
propriedade é definida como um valor maior que o Value propriedade, o Slider define o Value propriedade
Minimum . Da mesma forma, se Maximum é definido como um valor menor que Value , em seguida, Slider define
o Value propriedade para Maximum .
Slider define uma ValueChanged evento que é disparado quando o Value alterações, por meio de manipulação
de usuário do Slider ou quando o programa define o Value propriedade diretamente. Um ValueChanged
evento também é disparado quando o Value propriedade é forçada, conforme descrito no parágrafo anterior.
O objeto que acompanha o ValueChanged evento tem duas propriedades, ambos do tipo
ValueChangedEventArgs
double : OldValue e NewValue . No momento do evento é acionado, o valor de NewValue é igual a Value
propriedade do Slider objeto.
Slider também define DragStarted e DragCompleted eventos, que são acionados no início e no final da ação de
arrastar. Ao contrário o ValueChanged evento, o DragStarted e DragCompleted os eventos são disparados somente
por meio de manipulação de usuário do Slider . Quando o DragStarted evento é acionado, o
DragStartedCommand , do tipo ICommand , é executado. Da mesma forma, quando o DragCompleted evento é
acionado, o DragCompletedCommand , do tipo ICommand , é executado.

WARNING
Não use opções de layout horizontal irrestrita de Center , Start , ou End com Slider . No Android e UWP, o Slider
recolhe a uma barra de comprimento zero e no iOS, a barra é muito curto. Mantenha o padrão HorizontalOptions
configuração do Fill e não use uma largura de Auto ao colocar Slider em um Grid layout.
O Slider também define várias propriedades que afetam sua aparência:
MinimumTrackColor é a barra de cor à esquerda do elevador.
MaximumTrackColor é a barra de cor à direita do elevador.
ThumbColor é a cor do elevador.
ThumbImage é a imagem a ser usado para o elevador, do tipo FileImageSource .

NOTE
O ThumbColor e ThumbImage propriedades são mutuamente exclusivas. Se ambas as propriedades estiverem definidas, o
ThumbImage propriedade terá precedência.

Marcação e código básico do controle deslizante


O SliderDemos exemplo começa com três páginas que são funcionalmente idênticos, mas são implementadas
de maneiras diferentes. A primeira página usa apenas um código c#, o segundo usa XAML com um manipulador
de eventos no código e o terceiro é capaz de evitar o manipulador de eventos usando a associação de dados no
arquivo XAML.
Criando um controle deslizante no código
O código básico do controle deslizante página na SliderDemos exemplo mostra como criar um Slider e
dois Label objetos no código:
public class BasicSliderCodePage : ContentPage
{
public BasicSliderCodePage()
{
Label rotationLabel = new Label
{
Text = "ROTATING TEXT",
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.CenterAndExpand
};

Label displayLabel = new Label


{
Text = "(uninitialized)",
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.CenterAndExpand
};

Slider slider = new Slider


{
Maximum = 360
};
slider.ValueChanged += (sender, args) =>
{
rotationLabel.Rotation = slider.Value;
displayLabel.Text = String.Format("The Slider value is {0}", args.NewValue);
};

Title = "Basic Slider Code";


Padding = new Thickness(10, 0);
Content = new StackLayout
{
Children =
{
rotationLabel,
slider,
displayLabel
}
};
}
}

O Slider é inicializado para ter um Maximum propriedade de 360. O ValueChanged manipulador do Slider usa
o Value propriedade do slider objeto para definir o Rotation propriedade do primeiro Label e usa o
String.Format método com o NewValue propriedade do argumentos de evento para definir a Text propriedade
do segundo Label . Essas duas abordagens para obter o valor atual do Slider são intercambiáveis.
Aqui está o programa em execução no iOS, Android e plataforma Universal do Windows (UWP ) dispositivos:
A segunda Label exibe o texto "(não inicializado)" até que o Slider seja manipulado, o que faz com que o
primeiro ValueChanged evento seja acionado. Observe que o número de casas decimais que são exibidos é
diferente para cada plataforma. Essas diferenças estão relacionadas às implementações de plataforma a Slider e
são discutidos neste artigo na seção diferenças de implementação de plataforma.
Criando um controle deslizante no XAML
O básico XAML do controle deslizante página é funcionalmente igual código básico do controle
deslizante implementado, mas principalmente no XAML:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="SliderDemos.BasicSliderXamlPage"
Title="Basic Slider XAML"
Padding="10, 0">
<StackLayout>
<Label x:Name="rotatingLabel"
Text="ROTATING TEXT"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />

<Slider Maximum="360"
ValueChanged="OnSliderValueChanged" />

<Label x:Name="displayLabel"
Text="(uninitialized)"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>

O arquivo code-behind contém o manipulador para o ValueChanged evento:


public partial class BasicSliderXamlPage : ContentPage
{
public BasicSliderXamlPage()
{
InitializeComponent();
}

void OnSliderValueChanged(object sender, ValueChangedEventArgs args)


{
double value = args.NewValue;
rotatingLabel.Rotation = value;
displayLabel.Text = String.Format("The Slider value is {0}", value);
}
}

Também é possível que o manipulador de eventos obter o Slider que está disparando o evento por meio de
sender argumento. O Value propriedade contém o valor atual:

double value = ((Slider)sender).Value;

Se o Slider objeto recebeu um nome no arquivo XAML com um x:Name atributo (por exemplo, "controle
deslizante") e, em seguida, o manipulador de eventos pode fazer referência a esse objeto diretamente:

double value = slider.Value;

O controle deslizante de vinculação de dados


O associações básicas do controle deslizante página mostra como escrever um programa quase equivalente
que elimina a Value manipulador de eventos usando associação de dados:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="SliderDemos.BasicSliderBindingsPage"
Title="Basic Slider Bindings"
Padding="10, 0">
<StackLayout>
<Label Text="ROTATING TEXT"
Rotation="{Binding Source={x:Reference slider},
Path=Value}"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />

<Slider x:Name="slider"
Maximum="360" />

<Label x:Name="displayLabel"
Text="{Binding Source={x:Reference slider},
Path=Value,
StringFormat='The Slider value is {0:F0}'}"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>

O Rotation propriedade do primeiro Label está associado ao Value propriedade do Slider , como é o Text
propriedade do segundo Label com um StringFormat especificação. O associações básicas do controle
deslizante funções da página um pouco diferente das duas páginas anteriores: Quando a página aparece pela
primeira vez, o segundo Label exibe a cadeia de caracteres de texto com o valor. Esse é um benefício do uso de
associação de dados. Para exibir texto sem a associação de dados, você precisa inicializar especificamente a Text
propriedade do Label ou simular um acionamento do ValueChanged evento chamando o manipulador de
eventos do construtor da classe.

Precauções
O valor da Minimum propriedade sempre deve ser menor que o valor da Maximum propriedade. O código a seguir
faz com que o trecho de código a Slider para gerar uma exceção:

// Throws an exception!
Slider slider = new Slider
{
Minimum = 10,
Maximum = 20
};

O compilador c# gera código que define essas duas propriedades em sequência, e quando o Minimum estiver
definida como 10, é maior que o padrão Maximum valor 1. Você pode evitar a exceção nesse caso, definindo o
Maximum propriedade primeiro:

Slider slider = new Slider


{
Maximum = 20,
Minimum = 10
};

Definindo Maximum a 20 não é um problema porque ele é maior que o padrão Minimum valor de 0. Quando
Minimum estiver definido, o valor é menor do que o Maximum valor de 20.

O mesmo problema existe no XAML. Definir as propriedades em uma ordem que garante que Maximum é sempre
maior que Minimum :

<Slider Maximum="20"
Minimum="10" ... />

Você pode definir as Minimum e Maximum valores para números negativos, mas apenas em uma ordem em que
Minimum é sempre menor que Maximum :

<Slider Minimum="-20"
Maximum="-10" ... />

O Value propriedade é sempre igual a ou maior que o Minimum valor e menor ou igual a Maximum . Se Value é
definido como um valor fora desse intervalo, o valor será ser forçado para ficar dentro do intervalo, mas
nenhuma exceção for gerada. Por exemplo, esse código vai não gerar uma exceção:

Slider slider = new Slider


{
Value = 10
};

Em vez disso, o Value propriedade é forçada para o Maximum valor 1.


Aqui está um trecho de código mostrado acima:
Slider slider = new Slider
{
Maximum = 20,
Minimum = 10
};

Quando Minimum é definido como 10, em seguida, Value também é definido como 10.
Se um ValueChanged manipulador de eventos foi anexado no momento em que o Value propriedade é forçada
para algo diferente de seu valor padrão de 0, em seguida, um ValueChanged evento é disparado. Aqui está um
trecho de XAML:

<Slider ValueChanged="OnSliderValueChanged"
Maximum="20"
Minimum="10" />

Quando Minimum é definido como 10, Value também é definido como 10 e o ValueChanged evento é disparado.
Isso pode ocorrer antes que o restante da página foi construído, e o manipulador pode tentar fazer referência a
outros elementos na página que ainda não tem sido criados. Você talvez queira adicionar algum código para o
ValueChanged manipulador que verifica se há null valores de outros elementos na página. Ou, você pode definir
as ValueChanged manipulador de eventos após a Slider valores foram inicializados.

Diferenças de implementação de plataforma


As capturas de tela mostradas anteriormente exibem o valor da Slider com um número diferente de pontos
decimais. Isso está relacionado a como o Slider é implementado nas plataformas Android e UWP.
A implementação do Android
A implementação de Android da Slider se baseia no Android SeekBar e sempre define o Max propriedade a
1000. Isso significa que o Slider no Android tem apenas que 1.001 valores discretos. Se você definir a Slider
para ter um Minimum igual a 0 e um Maximum de 5000, em seguida, como o Slider seja manipulado, o Value
propriedade tem valores de 0, 5, 10, 15 e assim por diante.
A implementação de UWP
A implementação UWP Slider baseia-se na UWP Slider controle. O StepFrequency propriedade da UWP
Slider é definido como a diferença entre o Maximum e Minimum propriedades dividido por 10, mas não é maior
que 1.
Por exemplo, para o intervalo padrão de 0 a 1, o StepFrequency estiver definida como 0,1. Como o Slider seja
manipulado, o Value propriedade é restrita a 0, 0.1, 0.2, 0.3, 0,4, 0,5, 0,6, 0,7, 0,8, 0,9 e 1.0. (Isso fica evidente na
última página do SliderDemos exemplo.) Quando a diferença entre o Maximum e Minimum propriedades é 10 ou
superior, em seguida, StepFrequency é definido como 1 e o Value propriedade tem valores integrais.
A solução StepSlider
Mais versátil StepSlider é discutida em Capítulo 27. Renderizadores personalizados do livro criação de
aplicativos móveis com xamarin. Forms. O StepSlider é semelhante ao Slider , mas adiciona uma Steps
propriedade para especificar o número de valores entre Minimum e Maximum .

Controles deslizantes para seleção de cor


O último duas páginas na SliderDemos exemplo usam três Slider instâncias para seleção de cor. A primeira
página lida com todas as interações no arquivo code-behind, enquanto a segunda página mostra como usar a
vinculação de dados com um ViewModel.
Manipulando controles deslizantes no arquivo code -behind
O seletores de cor RGB página instancia um BoxView para exibir uma cor, três Slider instâncias para
selecionar os componentes vermelhos, verdes e azuis da cor e três Label elementos para exibir essas cores
valores:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="SliderDemos.RgbColorSlidersPage"
Title="RGB Color Sliders">
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Slider">
<Setter Property="Maximum" Value="255" />
</Style>

<Style TargetType="Label">
<Setter Property="HorizontalTextAlignment" Value="Center" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>

<StackLayout Margin="10">
<BoxView x:Name="boxView"
Color="Black"
VerticalOptions="FillAndExpand" />

<Slider x:Name="redSlider"
ValueChanged="OnSliderValueChanged" />

<Label x:Name="redLabel" />

<Slider x:Name="greenSlider"
ValueChanged="OnSliderValueChanged" />

<Label x:Name="greenLabel" />

<Slider x:Name="blueSlider"
ValueChanged="OnSliderValueChanged" />

<Label x:Name="blueLabel" />


</StackLayout>
</ContentPage>

Um Style fornece todas as três Slider elementos de um intervalo de 0 a 255. O Slider elementos
compartilham o mesmo ValueChanged manipulador, que é implementado no arquivo code-behind:
public partial class RgbColorSlidersPage : ContentPage
{
public RgbColorSlidersPage()
{
InitializeComponent();
}

void OnSliderValueChanged(object sender, ValueChangedEventArgs args)


{
if (sender == redSlider)
{
redLabel.Text = String.Format("Red = {0:X2}", (int)args.NewValue);
}
else if (sender == greenSlider)
{
greenLabel.Text = String.Format("Green = {0:X2}", (int)args.NewValue);
}
else if (sender == blueSlider)
{
blueLabel.Text = String.Format("Blue = {0:X2}", (int)args.NewValue);
}

boxView.Color = Color.FromRgb((int)redSlider.Value,
(int)greenSlider.Value,
(int)blueSlider.Value);
}
}

Os conjuntos de seção primeiro o Text propriedade de um do Label instâncias de uma cadeia de caracteres de
texto curto que indica o valor da Slider em hexadecimal. Em seguida, todos os três Slider instâncias são
acessadas para criar um Color valor dos componentes RGB:

Associando o controle deslizante para um ViewModel


O seletores de cor HSL página mostra como usar um ViewModel para executar os cálculos usados para criar
um Color valor dos valores de matiz, saturação e luminosidade. Como todos os ViewModels, o
HSLColorViewModel classe implementa o INotifyPropertyChanged interface e aciona um PropertyChanged evento
sempre que uma das propriedades é alterada:

public class HslColorViewModel : INotifyPropertyChanged


{
Color color;

public event PropertyChangedEventHandler PropertyChanged;


public event PropertyChangedEventHandler PropertyChanged;

public double Hue


{
set
{
if (color.Hue != value)
{
Color = Color.FromHsla(value, color.Saturation, color.Luminosity);
}
}
get
{
return color.Hue;
}
}

public double Saturation


{
set
{
if (color.Saturation != value)
{
Color = Color.FromHsla(color.Hue, value, color.Luminosity);
}
}
get
{
return color.Saturation;
}
}

public double Luminosity


{
set
{
if (color.Luminosity != value)
{
Color = Color.FromHsla(color.Hue, color.Saturation, value);
}
}
get
{
return color.Luminosity;
}
}

public Color Color


{
set
{
if (color != value)
{
color = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Hue"));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Saturation"));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Luminosity"));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Color"));
}
}
get
{
return color;
}
}
}

ViewModels e o INotifyPropertyChanged interface são discutidas no artigo associação de dados.


O HslColorSlidersPage.xaml arquivo XAML instancia o HslColorViewModel e o configura para a página
BindingContext propriedade. Isso permite que todos os elementos no arquivo XAML para associar a
propriedades no ViewModel:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:SliderDemos"
x:Class="SliderDemos.HslColorSlidersPage"
Title="HSL Color Sliders">

<ContentPage.BindingContext>
<local:HslColorViewModel Color="Chocolate" />
</ContentPage.BindingContext>

<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Label">
<Setter Property="HorizontalTextAlignment" Value="Center" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>

<StackLayout Margin="10">
<BoxView Color="{Binding Color}"
VerticalOptions="FillAndExpand" />

<Slider Value="{Binding Hue}" />


<Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}" />

<Slider Value="{Binding Saturation}" />


<Label Text="{Binding Saturation, StringFormat='Saturation = {0:F2}'}" />

<Slider Value="{Binding Luminosity}" />


<Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}" />
</StackLayout>
</ContentPage>

Como o Slider elementos são manipulados, o BoxView e Label elementos são atualizados do ViewModel:

O StringFormat componente de Binding extensão de marcação é definida para um formato de "F2" para exibir
duas casas decimais. (Cadeia de caracteres de formatação em associações de dados é discutida no artigo cadeia
de caracteres de formatação.) No entanto, a versão UWP do programa é limitada aos valores de 0, 0.1, 0.2,... 0.9 e
1.0. Este é um resultado direto da implementação da UWP Slider conforme descrito acima na seção diferenças
de implementação de plataforma.

Links relacionados
Exemplo de demonstrações do controle deslizante
API de controle deslizante
Seletor de xamarin. Forms
12/04/2019 • 12 minutes to read

baixar o exemplo
Use um seletor para selecionar um valor numérico de um intervalo de valores.
O xamarin. Forms Stepper consiste em dois botões rotulados com sinais de adição e de subtração. Esses botões
podem ser manipulados pelo usuário para selecionar incrementalmente uma double valor de um intervalo de
valores.
O Stepper define quatro propriedades do tipo double :
Increment é o valor para alterar o valor selecionado, com um valor padrão de 1.
Minimum é o mínimo do intervalo, com um valor padrão de 0.
Maximum é o máximo do intervalo, com um valor padrão de 100.
Value é o valor do seletor, o que pode variar entre Minimum e Maximum e tem um valor padrão de 0.

Todas essas propriedades têm o respaldo BindableProperty objetos. O Value propriedade tem um modo de
associação padrão de BindingMode.TwoWay , que significa que ele é adequado como uma origem da associação em
um aplicativo que usa o Model-View -ViewModel (MVVM ) arquitetura.

WARNING
Internamente, o Stepper garante que Minimum é menor que Maximum . Se Minimum ou Maximum nunca são definidas,
de modo que Minimum é não é menor que Maximum , uma exceção será gerada. Para obter mais informações sobre como
o Minimum e Maximum propriedades, consulte precauções seção.

O Stepper impõe o Value propriedade para que ele fique entre Minimum e Maximum , inclusive. Se o Minimum
propriedade é definida como um valor maior que o Value propriedade, o Stepper define o Value propriedade
Minimum . Da mesma forma, se Maximum é definido como um valor menor que Value , em seguida, Stepper
define o Value propriedade para Maximum .
Stepper define uma ValueChanged evento que é disparado quando o Value alterações, por meio da manipulação
do usuário a Stepper ou quando o aplicativo define o Value propriedade diretamente. Um ValueChanged evento
também é disparado quando o Value propriedade é forçada, conforme descrito no parágrafo anterior.
O objeto que acompanha o ValueChanged evento tem duas propriedades, ambos do tipo
ValueChangedEventArgs
double : OldValue e NewValue . No momento do evento é acionado, o valor de NewValue é igual a Value
propriedade do Stepper objeto.

Marcação e código de escalonador básico


O StepperDemos exemplo contém três páginas que são funcionalmente idênticos, mas são implementadas de
maneiras diferentes. A primeira página usa apenas C# código, o segundo usa XAML com um manipulador de
eventos no código e o terceiro é capaz de evitar o manipulador de eventos usando a associação de dados no
arquivo XAML.
Criando um seletor em código
O código básico de escalonador página na StepperDemos exemplo mostra como criar um Stepper e dois
Label objetos no código:

public class BasicStepperCodePage : ContentPage


{
public BasicStepperCodePage()
{
Label rotationLabel = new Label
{
Text = "ROTATING TEXT",
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.CenterAndExpand
};

Label displayLabel = new Label


{
Text = "(uninitialized)",
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.CenterAndExpand
};

Stepper stepper = new Stepper


{
Maximum = 360,
Increment = 30,
HorizontalOptions = LayoutOptions.Center
};
stepper.ValueChanged += (sender, e) =>
{
rotationLabel.Rotation = stepper.Value;
displayLabel.Text = string.Format("The Stepper value is {0}", e.NewValue);
};

Title = "Basic Stepper Code";


Content = new StackLayout
{
Margin = new Thickness(20),
Children = { rotationLabel, stepper, displayLabel }
};
}
}

O Stepper é inicializado para ter um Maximum propriedade de 360 e um Increment propriedade de 30 anos.
Manipulando o Stepper altera o valor selecionado de forma incremental entre Minimum para Maximum com base
no valor da Increment propriedade. O ValueChanged manipulador da Stepper usa os Value propriedade do
stepper objeto para definir o Rotation propriedade do primeiro Label e usa o string.Format método com o
NewValue propriedade dos argumentos do evento para definir o Text propriedade das segundo Label . Essas
duas abordagens para obter o valor atual do Stepper são intercambiáveis.
As capturas de tela a seguir mostram os código básico de escalonador página:
A segunda Label exibe o texto "(não inicializado)" até que o Stepper seja manipulado, o que faz com que o
primeiro ValueChanged evento para ser disparado.
Criando um seletor em XAML
O básico XAML de escalonador página é funcionalmente igual código básico de escalonador
implementado, mas principalmente no XAML:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="StepperDemo.BasicStepperXAMLPage"
Title="Basic Stepper XAML">
<StackLayout Margin="20">
<Label x:Name="_rotatingLabel"
Text="ROTATING TEXT"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Stepper Maximum="360"
Increment="30"
HorizontalOptions="Center"
ValueChanged="OnStepperValueChanged" />
<Label x:Name="_displayLabel"
Text="(uninitialized)"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>

O arquivo code-behind contém o manipulador para o ValueChanged eventos:


public partial class BasicStepperXAMLPage : ContentPage
{
public BasicStepperXAMLPage()
{
InitializeComponent();
}

void OnStepperValueChanged(object sender, ValueChangedEventArgs e)


{
double value = e.NewValue;
_rotatingLabel.Rotation = value;
_displayLabel.Text = string.Format("The Stepper value is {0}", value);
}
}

Também é possível que o manipulador de eventos obter o Stepper que está disparando o evento por meio de
sender argumento. O Value propriedade contém o valor atual:

double value = ((Stepper)sender).Value;

Se o Stepper objeto recebeu um nome no arquivo XAML com um x:Name atributo (por exemplo, "escalonador")
e, em seguida, o manipulador de eventos pode fazer referência a esse objeto diretamente:

double value = stepper.Value;

O seletor de vinculação de dados


O associações básicas de escalonador página mostra como escrever um aplicativo quase equivalente que
elimina a Value manipulador de eventos usando associação de dados:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="StepperDemo.BasicStepperBindingsPage"
Title="Basic Stepper Bindings">
<StackLayout Margin="20">
<Label Text="ROTATING TEXT"
Rotation="{Binding Source={x:Reference _stepper}, Path=Value}"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Stepper x:Name="_stepper"
Maximum="360"
Increment="30"
HorizontalOptions="Center" />
<Label Text="{Binding Source={x:Reference _stepper}, Path=Value, StringFormat='The Stepper value is
{0:F0}'}"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>

O Rotation propriedade do primeiro Label está associado a Value propriedade do Stepper , como é o Text
propriedade do segundo Label com um StringFormat especificação. O associações básicas de escalonador
funções da página um pouco diferente das duas páginas anteriores: quando a página aparece pela primeira vez, o
segundo Label exibe a cadeia de caracteres de texto com o valor. Esse é um benefício do uso de associação de
dados. Para exibir texto sem a associação de dados, você precisa inicializar especificamente a Text propriedade
do Label ou simular um acionamento da ValueChanged evento chamando o manipulador de eventos do
construtor de classe .
Precauções
O valor da Minimum propriedade sempre deve ser menor que o valor da Maximum propriedade. O código a seguir
faz com que o trecho de código a Stepper para gerar uma exceção:

// Throws an exception!
Stepper stepper = new Stepper
{
Minimum = 180,
Maximum = 360
};

O C# compilador gera código que define essas duas propriedades em sequência, e quando o Minimum estiver
definida como 180, é maior que o padrão Maximum valor de 100. Você pode evitar a exceção nesse caso, definindo
o Maximum propriedade primeiro:

Stepper stepper = new Stepper


{
Maximum = 360,
Minimum = 180
};

Definindo Maximum a 360 não é um problema porque ele é maior que o padrão Minimum valor de 0. Quando
Minimum estiver definido, o valor é menor do que o Maximum valor de 360.

O mesmo problema existe no XAML. Definir as propriedades em uma ordem que garante que Maximum é sempre
maior que Minimum :

<Stepper Maximum="360"
Minimum="180" ... />

Você pode definir as Minimum e Maximum valores para números negativos, mas apenas em uma ordem em que
Minimum é sempre menor que Maximum :

<Stepper Minimum="-360"
Maximum="-180" ... />

O Value propriedade é sempre maior que ou igual de Minimum valor e menor ou igual a Maximum . Se Value é
definido como um valor fora desse intervalo, o valor será ser forçado para ficar dentro do intervalo, mas
nenhuma exceção for gerada. Por exemplo, esse código vai não gerar uma exceção:

Stepper stepper = new Stepper


{
Value = 180
};

Em vez disso, o Value propriedade é forçada para o Maximum valor de 100.


Aqui está um trecho de código mostrado acima:
Stepper stepper = new Stepper
{
Maximum = 360,
Minimum = 180
};

Quando Minimum é definido para 180, então Value também é definido para 180.
Se um ValueChanged manipulador de eventos foi anexado no momento em que o Value propriedade é forçada
para algo diferente de seu valor padrão de 0, em seguida, um ValueChanged evento é disparado. Aqui está um
trecho de XAML:

<Stepper ValueChanged="OnStepperValueChanged"
Maximum="360"
Minimum="180" />

Quando Minimum é definido para 180, Value também é definido para 180 e o ValueChanged evento é disparado.
Isso pode ocorrer antes que o restante da página foi construído, e o manipulador pode tentar fazer referência a
outros elementos na página que ainda não tem sido criados. Você talvez queira adicionar algum código para o
ValueChanged manipulador que verifica se há null valores de outros elementos na página. Ou, você pode definir
a ValueChanged manipulador de eventos após os Stepper valores foram inicializados.

Links relacionados
Exemplo de demonstrações escalonador
Seletor de API
Aplicativos xamarin. Forms de estilo
12/04/2019 • 2 minutes to read

Aplicar estilo a aplicativos do Xamarin.Forms usando os estilos


XAML
Definir o estilo de um aplicativo xamarin. Forms tradicionalmente é realizado usando o Style classe
agrupar um conjunto de valores de propriedade em um único objeto, em seguida, pode ser aplicado a várias
instâncias do elemento visual. Isso ajuda a reduzir as marcações repetitivas e permite uma aparência de
aplicativos a ser alterado com mais facilidade.

Aplicar estilo a aplicativos do Xamarin.Forms usando as folhas de


estilos em cascata
Xamarin. Forms dá suporte a elementos visuais de estilo usando folhas de estilo em cascata (CSS ). Uma
folha de estilos consiste em uma lista de regras, com cada regra consiste em um ou mais seletores e um
bloco de declaração.
Aplicar estilo a aplicativos xamarin. Forms usando os
estilos XAML
12/04/2019 • 2 minutes to read

Introdução
Aplicativos xamarin. Forms geralmente contêm vários controles que têm uma aparência idêntica. Definir a
aparência de cada controle individual pode ser repetitiva e sujeito a erros. Em vez disso, podem ser criados estilos
para personalizar a aparência do controle de agrupamento e definindo as propriedades disponíveis no tipo de
controle.

Estilos explícitos
Uma explícita estilo é aquele que é aplicada aos controles seletivamente definindo suas Style propriedades.

Estilos implícitos
Uma implícita estilo é aquele que é usado por todos os controles do mesmo TargetType , sem a necessidade de
cada controle para fazer referência ao estilo.

Estilos globais
Estilos podem ser disponibilizados globalmente ao adicioná-los para o aplicativo ResourceDictionary . Isso ajuda a
evitar a duplicação de estilos em páginas ou controles.

Herança de estilo
Estilos podem herdar de outros estilos para reduzir a duplicação e habilitar a reutilização.

Estilos dinâmicos
Estilos não responder a alterações de propriedade e permanecem inalterados durante o período de um aplicativo.
No entanto, os aplicativos podem responder a alterações de estilo dinamicamente em tempo de execução usando
os recursos dinâmicos.

Estilos de dispositivo
Xamarin. Forms inclui seis dinâmica estilos, conhecidos como dispositivo estilos, o Devices.Styles classe. Todos
os seis estilos podem ser aplicados a Label somente instâncias.

Classes de estilo
Classes de estilo do xamarin. Forms permitem que vários estilos a ser aplicado a um controle, sem recorrer à
herança de estilo.
Introdução ao xamarin. Forms estilos
12/04/2019 • 7 minutes to read

Estilos permitem que a aparência dos elementos visuais para serem personalizados. Os estilos são definidos para
um tipo específico e contêm valores para as propriedades disponíveis nesse tipo.
Aplicativos xamarin. Forms geralmente contêm vários controles que têm uma aparência idêntica. Por exemplo, um
aplicativo pode ter vários Label instâncias que têm as mesmas opções de fonte e opções de layout, conforme
mostrado no exemplo de código XAML a seguir:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Styles.NoStylesPage"
Title="No Styles"
Icon="xaml.png">
<ContentPage.Content>
<StackLayout Padding="0,20,0,0">
<Label Text="These labels"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
FontSize="Large" />
<Label Text="are not"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
FontSize="Large" />
<Label Text="using styles"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
FontSize="Large" />
</StackLayout>
</ContentPage.Content>
</ContentPage>

O exemplo de código a seguir mostra a página equivalente criada em C#:


public class NoStylesPageCS : ContentPage
{
public NoStylesPageCS ()
{
Title = "No Styles";
Icon = "csharp.png";
Padding = new Thickness (0, 20, 0, 0);

Content = new StackLayout {


Children = {
new Label {
Text = "These labels",
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.CenterAndExpand,
FontSize = Device.GetNamedSize (NamedSize.Large, typeof(Label))
},
new Label {
Text = "are not",
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.CenterAndExpand,
FontSize = Device.GetNamedSize (NamedSize.Large, typeof(Label))
},
new Label {
Text = "using styles",
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.CenterAndExpand,
FontSize = Device.GetNamedSize (NamedSize.Large, typeof(Label))
}
}
};
}
}

Cada Label instância tem valores de propriedade idênticas para controlar a aparência do texto exibido pelo
Label . Isso resulta na aparência mostrada nas capturas de tela seguir:

Definir a aparência de cada controle individual pode ser repetitiva e sujeito a erros. Em vez disso, pode ser criado
um estilo que define a aparência e, em seguida, são aplicados aos controles necessários.

Criar um estilo
O Style classe agrupa uma coleção de valores de propriedade em um único objeto, em seguida, pode ser
aplicado a várias instâncias do elemento visual. Isso ajuda a reduzir as marcações repetitivas e permite uma
aparência de aplicativos a ser alterado com mais facilidade.
Embora os estilos foram projetados principalmente para aplicativos baseados em XAML, eles também podem ser
criados em c#:
Style instâncias criadas no XAML geralmente são definidas em uma ResourceDictionary que é atribuído ao
Resources coleção de um controle, página, ou para o Resources coleção do aplicativo.
Style as instâncias criadas na linguagem c# normalmente são definidas na classe da página, ou em uma classe
que pode ser acessada globalmente.
Escolher onde definir um Style afeta onde ele pode ser usado:
Style só podem ser aplicadas a instâncias definidas no nível de controle para o controle e seus filhos.
Style só podem ser aplicadas a instâncias definidas no nível da página para a página e seus filhos.
Style instâncias definidas no nível do aplicativo podem ser aplicadas em todo o aplicativo.

Cada Style instância contém uma coleção de um ou mais Setter objetos, com cada Setter tendo um Property
e uma Value . O Property é o nome da propriedade associável do elemento de estilo é aplicado, e o Value é o
valor que é aplicado à propriedade.
Cada Style instância pode ser explícita, ou implícita:
Uma explícita Style instância é definida especificando uma TargetType e um x:Key valor e, em seguida,
definindo o elemento de destino Style propriedade para o x:Key referência. Para obter mais informações
sobre explícita estilos, consulte estilos explícitos.
Uma implícita Style instância é definida especificando-se apenas um TargetType . O Style instância, em
seguida, serão automaticamente aplicada a todos os elementos desse tipo. Observe que pode efetuar
subclasses do TargetType não tem automaticamente o Style aplicado. Para obter mais informações sobre
implícita estilos, consulte estilos implícitos.
Ao criar uma Style , o TargetType propriedade sempre é necessária. O seguinte exemplo de código mostra uma
explícita estilo (Observe o x:Key ) criado em XAML:

<Style x:Key="labelStyle" TargetType="Label">


<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
<Setter Property="FontSize" Value="Large" />
</Style>

Para aplicar uma Style , o objeto de destino deve ser um VisualElement que corresponde a TargetType valor da
propriedade do Style , conforme mostrado no exemplo de código XAML a seguir:

<Label Text="Demonstrating an explicit style" Style="{StaticResource labelStyle}" />

Estilos inferiores na hierarquia de exibição têm precedência sobre aquelas definidas superior para cima. Por
exemplo, definir uma Style que define Label.TextColor para Red no aplicativo de nível será substituído por um
estilo de nível de página que define Label.TextColor para Green . Da mesma forma, um estilo de nível de página
será substituído por um estilo de controle. Além disso, se Label.TextColor for definido diretamente em uma
propriedade de controle, isso tem precedência sobre todos os estilos.
Os artigos nesta seção demonstram e explicam como criar e aplicar explícita e implícita estilos, como criar estilos
globais, herança, de estilo como responder a alterações de estilo em tempo de execução e como usar os estilos
internos incluídos no xamarin. Forms.
NOTE
O que é StyleId?
Antes de xamarin. Forms 2.2, o StyleId propriedade foi usada para identificar elementos individuais em um aplicativo para
identificação em testes de interface do usuário e em mecanismos de tema como Pixate. No entanto, o xamarin. Forms 2.2
introduziu o AutomationId propriedade, que substituiu o StyleId propriedade.

Links relacionados
Extensões de marcação XAML
Estilo
Setter
Estilos explícitos no xamarin. Forms
12/04/2019 • 6 minutes to read

baixar o exemplo
Um estilo explícito é aquele que é aplicada aos controles seletivamente, definindo suas propriedades de estilo.

Criar um estilo explícito em XAML


Para declarar uma Style no nível da página, uma ResourceDictionary deve ser adicionado à página e, em seguida,
um ou mais Style declarações podem ser incluídas no ResourceDictionary . Um Style é feita explícito
fornecendo sua declaração de uma x:Key atributo, que concede a ele uma chave descritiva no ResourceDictionary
. Explícito estilos, em seguida, devem ser aplicados a elementos visuais específicos definindo seus Style
propriedades.
O seguinte exemplo de código mostra explícita estilos declarados em XAML em uma página ResourceDictionary e
aplicadas para a página Label instâncias:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.ExplicitStylesPage" Title="Explicit"
Icon="xaml.png">
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="labelRedStyle" TargetType="Label">
<Setter Property="HorizontalOptions"
Value="Center" />
<Setter Property="VerticalOptions"
Value="CenterAndExpand" />
<Setter Property="FontSize" Value="Large" />
<Setter Property="TextColor" Value="Red" />
</Style>
<Style x:Key="labelGreenStyle" TargetType="Label">
...
<Setter Property="TextColor" Value="Green" />
</Style>
<Style x:Key="labelBlueStyle" TargetType="Label">
...
<Setter Property="TextColor" Value="Blue" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout Padding="0,20,0,0">
<Label Text="These labels"
Style="{StaticResource labelRedStyle}" />
<Label Text="are demonstrating"
Style="{StaticResource labelGreenStyle}" />
<Label Text="explicit styles,"
Style="{StaticResource labelBlueStyle}" />
<Label Text="and an explicit style override"
Style="{StaticResource labelBlueStyle}"
TextColor="Teal" />
</StackLayout>
</ContentPage.Content>
</ContentPage>

O ResourceDictionary define três explícita estilos que são aplicados para a página Label instâncias. Cada Style é
usado para exibir texto em uma cor diferente, e também define a fonte de opções de layout de tamanho e
horizontal e vertical. Cada Style é aplicado a um outro Label definindo seu Style propriedades usando o
StaticResource extensão de marcação. Isso resulta na exibição mostrada nas capturas de tela seguir:

Além disso, o último Label tem um Style aplicado a ele, mas também substitui o TextColor propriedade para
um diferente Color valor.
Criar um estilo explícito no nível de controle
Além de criar explícita estilos no nível da página, eles também podem ser criados no nível de controle, conforme
mostrado no exemplo de código a seguir:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.ExplicitStylesPage" Title="Explicit"
Icon="xaml.png">
<ContentPage.Content>
<StackLayout Padding="0,20,0,0">
<StackLayout.Resources>
<ResourceDictionary>
<Style x:Key="labelRedStyle" TargetType="Label">
...
</Style>
...
</ResourceDictionary>
</StackLayout.Resources>
<Label Text="These labels" Style="{StaticResource labelRedStyle}" />
...
</StackLayout>
</ContentPage.Content>
</ContentPage>

Neste exemplo, o explícita Style instâncias são atribuídas para o Resources coleção da StackLayout controle. Os
estilos, em seguida, podem ser aplicados para o controle e seus filhos.
Para obter informações sobre a criação de estilos em um aplicativo ResourceDictionary , consulte estilos globais.

Criar um estilo explícito em C#


Style instâncias podem ser adicionadas a uma página Resources coleção no C#, criando um novo
ResourceDictionary e, em seguida, adicionando o Style para instâncias de ResourceDictionary , conforme
mostrado no exemplo de código a seguir:
public class ExplicitStylesPageCS : ContentPage
{
public ExplicitStylesPageCS ()
{
var labelRedStyle = new Style (typeof(Label)) {
Setters = {
...
new Setter { Property = Label.TextColorProperty, Value = Color.Red }
}
};
var labelGreenStyle = new Style (typeof(Label)) {
Setters = {
...
new Setter { Property = Label.TextColorProperty, Value = Color.Green }
}
};
var labelBlueStyle = new Style (typeof(Label)) {
Setters = {
...
new Setter { Property = Label.TextColorProperty, Value = Color.Blue }
}
};

Resources = new ResourceDictionary ();


Resources.Add ("labelRedStyle", labelRedStyle);
Resources.Add ("labelGreenStyle", labelGreenStyle);
Resources.Add ("labelBlueStyle", labelBlueStyle);
...

Content = new StackLayout {


Children = {
new Label { Text = "These labels",
Style = (Style)Resources ["labelRedStyle"] },
new Label { Text = "are demonstrating",
Style = (Style)Resources ["labelGreenStyle"] },
new Label { Text = "explicit styles,",
Style = (Style)Resources ["labelBlueStyle"] },
new Label { Text = "and an explicit style override",
Style = (Style)Resources ["labelBlueStyle"], TextColor = Color.Teal }
}
};
}
}

O construtor define três explícita estilos que são aplicados para a página Label instâncias. Cada explícita Style é
adicionado para o ResourceDictionary usando o Add método, especificando um key cadeia de caracteres para se
referir a Style instância. Cada Style é aplicado a um outro Label definindo suas Style propriedades.
No entanto, não há nenhuma vantagem em usar um ResourceDictionary aqui. Em vez disso, Style instâncias
podem ser atribuídas diretamente para o Style propriedades dos elementos visuais necessários e o
ResourceDictionary poderá ser removido, conforme mostrado no exemplo a seguir exemplo de código:
public class ExplicitStylesPageCS : ContentPage
{
public ExplicitStylesPageCS ()
{
var labelRedStyle = new Style (typeof(Label)) {
...
};
var labelGreenStyle = new Style (typeof(Label)) {
...
};
var labelBlueStyle = new Style (typeof(Label)) {
...
};
...
Content = new StackLayout {
Children = {
new Label { Text = "These labels", Style = labelRedStyle },
new Label { Text = "are demonstrating", Style = labelGreenStyle },
new Label { Text = "explicit styles,", Style = labelBlueStyle },
new Label { Text = "and an explicit style override", Style = labelBlueStyle,
TextColor = Color.Teal }
}
};
}
}

O construtor define três explícita estilos que são aplicados para a página Label instâncias. Cada Style é usado
para exibir texto em uma cor diferente, e também define a fonte de opções de layout de tamanho e horizontal e
vertical. Cada Style é aplicado a um outro Label definindo seu Style propriedades. Além disso, o último
Label tem uma Style aplicados a ele, mas também substitui o TextColor propriedade em outro Color valor.

Links relacionados
Extensões de marcação XAML
Estilos básicos (amostra)
Trabalhar com estilos (amostra)
Dicionário de recurso
Estilo
Setter
Estilos implícitos no xamarin. Forms
12/04/2019 • 6 minutes to read

baixar o exemplo
Um estilo implícito é aquele que é usado por todos os controles de TargetType mesmo, sem a necessidade de cada
controle para fazer referência ao estilo.

Criar um estilo implícito em XAML


Para declarar uma Style no nível da página, uma ResourceDictionary deve ser adicionado à página e, em seguida,
um ou mais Style declarações podem ser incluídas no ResourceDictionary . Um Style é feita implícita não
especificando um x:Key atributo. O estilo será aplicado, em seguida, para elementos visuais que correspondem a
TargetType exatamente, mas não para elementos que são derivados da TargetType valor.

O seguinte exemplo de código mostra uma implícita estilo declarado em XAML em uma página
ResourceDictionary e aplicadas para a página Entry instâncias:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:Styles;assembly=Styles"
x:Class="Styles.ImplicitStylesPage" Title="Implicit" Icon="xaml.png">
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Entry">
<Setter Property="HorizontalOptions" Value="Fill" />
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
<Setter Property="BackgroundColor" Value="Yellow" />
<Setter Property="FontAttributes" Value="Italic" />
<Setter Property="TextColor" Value="Blue" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout Padding="0,20,0,0">
<Entry Text="These entries" />
<Entry Text="are demonstrating" />
<Entry Text="implicit styles," />
<Entry Text="and an implicit style override" BackgroundColor="Lime" TextColor="Red" />
<local:CustomEntry Text="Subclassed Entry is not receiving the style" />
</StackLayout>
</ContentPage.Content>
</ContentPage>

O ResourceDictionary define um único implícita estilo é aplicado para a página Entry instâncias. O Style é
usado para exibir o texto azul em um plano de fundo amarelo, enquanto também definir outras opções de
aparência. O Style é adicionado para a página ResourceDictionary sem especificar um x:Key atributo. Portanto,
o Style é aplicada a todos os a Entry instâncias implicitamente, conforme eles correspondem a TargetType
propriedade do Style exatamente. No entanto, o Style não é aplicada para o CustomEntry instância, que é uma
subclasse Entry . Isso resulta na exibição mostrada nas capturas de tela seguir:
Além disso, o quarto Entry substitui o BackgroundColor e TextColor propriedades do estilo implícito para
diferentes Color valores.
Criar um estilo implícito no nível de controle
Além de criar implícita estilos no nível da página, eles também podem ser criados no nível de controle, conforme
mostrado no exemplo de código a seguir:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:Styles;assembly=Styles"
x:Class="Styles.ImplicitStylesPage" Title="Implicit" Icon="xaml.png">
<ContentPage.Content>
<StackLayout Padding="0,20,0,0">
<StackLayout.Resources>
<ResourceDictionary>
<Style TargetType="Entry">
<Setter Property="HorizontalOptions" Value="Fill" />
...
</Style>
</ResourceDictionary>
</StackLayout.Resources>
<Entry Text="These entries" />
...
</StackLayout>
</ContentPage.Content>
</ContentPage>

Neste exemplo, o implícita Style é atribuído para o Resources coleção da StackLayout controle. O implícita
estilo, em seguida, pode ser aplicado ao controle e seus filhos.
Para obter informações sobre a criação de estilos em um aplicativo ResourceDictionary , consulte estilos globais.

Criar um estilo implícito em C#


Style instâncias podem ser adicionadas a uma página Resources coleção no C#, criando um novo
ResourceDictionary e, em seguida, adicionando o Style para instâncias de ResourceDictionary , conforme
mostrado no exemplo de código a seguir:
public class ImplicitStylesPageCS : ContentPage
{
public ImplicitStylesPageCS ()
{
var entryStyle = new Style (typeof(Entry)) {
Setters = {
...
new Setter { Property = Entry.TextColorProperty, Value = Color.Blue }
}
};

...
Resources = new ResourceDictionary ();
Resources.Add (entryStyle);

Content = new StackLayout {


Children = {
new Entry { Text = "These entries" },
new Entry { Text = "are demonstrating" },
new Entry { Text = "implicit styles," },
new Entry { Text = "and an implicit style override", BackgroundColor = Color.Lime, TextColor =
Color.Red },
new CustomEntry { Text = "Subclassed Entry is not receiving the style" }
}
};
}
}

O construtor define uma única implícita estilo é aplicado para a página Entry instâncias. O Style é usado para
exibir o texto azul em um plano de fundo amarelo, enquanto também definir outras opções de aparência. O Style
é adicionado para a página ResourceDictionary sem especificar um key cadeia de caracteres. Portanto, o Style é
aplicada a todos os a Entry instâncias implicitamente, conforme eles correspondem a TargetType propriedade do
Style exatamente. No entanto, o Style não é aplicada para o CustomEntry instância, que é uma subclasse Entry
.

Aplicar um estilo a tipos derivados


O Style.ApplyToDerivedTypes propriedade permite que um estilo a ser aplicado aos controles que derivam do tipo
de base referenciado pela TargetType propriedade. Portanto, definir essa propriedade como true permite que
um único estilo como destino vários tipos, desde que os tipos derivam do tipo base especificado no TargetType
propriedade.
O exemplo a seguir mostra um estilo implícito que define a cor de fundo Button instâncias para vermelho:

<Style TargetType="Button"
ApplyToDerivedTypes="True">
<Setter Property="BackgroundColor"
Value="Red" />
</Style>

Colocando esse estilo em um nível de página ResourceDictionary resultará em que ele está sendo aplicada a todos
os Button instâncias na página e também para todos os controles que derivam de Button . No entanto, se o
ApplyToDerivedTypes propriedade permanece definida, o estilo só deve ser aplicado a Button instâncias.

O código C# equivalente é:
var buttonStyle = new Style(typeof(Button))
{
ApplyToDerivedTypes = true,
Setters =
{
new Setter
{
Property = VisualElement.BackgroundColorProperty,
Value = Color.Red
}
}
};

Resources = new ResourceDictionary { buttonStyle };

Links relacionados
Extensões de marcação XAML
Estilos básicos (amostra)
Trabalhar com estilos (amostra)
Dicionário de recurso
Estilo
Setter
Estilos globais no xamarin. Forms
12/04/2019 • 5 minutes to read

baixar o exemplo
Estilos podem se tornar disponíveis globalmente ao adicioná -los a dicionário de recursos do aplicativo. Isso ajuda
a evitar a duplicação de estilos em páginas ou controles.

Criar um estilo global em XAML


Por padrão, todos os aplicativos do Xamarin.Forms criados de um modelo usam a classe App para implementar a
subclasse Application . Para declarar uma Style no nível do aplicativo, na caixa de diálogo ResourceDictionary
usando XAML, o padrão aplicativo classe deve ser substituído por um XAML Aplicativo classe e code-behind
associado. Para obter mais informações, consulte trabalhando com a classe App.
O seguinte exemplo de código mostra uma Style declarado no nível do aplicativo:

<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.App">
<Application.Resources>
<ResourceDictionary>
<Style x:Key="buttonStyle" TargetType="Button">
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
<Setter Property="BorderColor" Value="Lime" />
<Setter Property="BorderRadius" Value="5" />
<Setter Property="BorderWidth" Value="5" />
<Setter Property="WidthRequest" Value="200" />
<Setter Property="TextColor" Value="Teal" />
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>

Isso ResourceDictionary define um único explícita estilo, buttonStyle , que será usado para definir a aparência da
Button instâncias. No entanto, os estilos globais podem ser explícita ou implícita.
O exemplo de código a seguir mostra uma página do XAML aplicando o buttonStyle para a página Button
instâncias:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.ApplicationStylesPage"
Title="Application" Icon="xaml.png">
<ContentPage.Content>
<StackLayout Padding="0,20,0,0">
<Button Text="These buttons" Style="{StaticResource buttonStyle}" />
<Button Text="are demonstrating" Style="{StaticResource buttonStyle}" />
<Button Text="application style overrides" Style="{StaticResource buttonStyle}" />
</StackLayout>
</ContentPage.Content>
</ContentPage>

Isso resulta na exibição mostrada nas capturas de tela seguir:


Para obter informações sobre a criação de estilos em uma página ResourceDictionary , consulte estilos explícitos e
estilos implícitos.
Substituir os estilos
Estilos inferiores na hierarquia de exibição têm precedência sobre aquelas definidas superior para cima. Por
exemplo, definir uma Style que define Button.TextColor para Red no aplicativo de nível será substituído por um
estilo de nível de página que define Button.TextColor para Green . Da mesma forma, um estilo de nível de página
será substituído por um estilo de controle. Além disso, se Button.TextColor for definido diretamente em uma
propriedade de controle, isso terá precedência sobre todos os estilos. Essa precedência é demonstrada no exemplo
de código a seguir:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.ApplicationStylesPage"
Title="Application" Icon="xaml.png">
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="buttonStyle" TargetType="Button">
...
<Setter Property="TextColor" Value="Red" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout Padding="0,20,0,0">
<StackLayout.Resources>
<ResourceDictionary>
<Style x:Key="buttonStyle" TargetType="Button">
...
<Setter Property="TextColor" Value="Blue" />
</Style>
</ResourceDictionary>
</StackLayout.Resources>
<Button Text="These buttons" Style="{StaticResource buttonStyle}" />
<Button Text="are demonstrating" Style="{StaticResource buttonStyle}" />
<Button Text="application style overrides" Style="{StaticResource buttonStyle}" />
</StackLayout>
</ContentPage.Content>
</ContentPage>

O original buttonStyle , definidas no nível do aplicativo, é substituído pelo buttonStyle instância definida no nível
da página. Além disso, o estilo de nível de página é substituído pelo nível de controle buttonStyle . Portanto, o
Button instâncias são exibidas com o texto azul, conforme mostrado nas capturas de tela seguir:

Criar um estilo global em C#


Style instâncias podem ser adicionadas para o aplicativo Resources coleção no C#, criando um novo
ResourceDictionary e, em seguida, adicionando o Style para instâncias de ResourceDictionary , como como
mostrado no exemplo de código a seguir:

public class App : Application


{
public App ()
{
var buttonStyle = new Style (typeof(Button)) {
Setters = {
...
new Setter { Property = Button.TextColorProperty, Value = Color.Teal }
}
};

Resources = new ResourceDictionary ();


Resources.Add ("buttonStyle", buttonStyle);
...
}
...
}

O construtor define uma única explícita estilo para a aplicação Button instâncias em todo o aplicativo. Explícito
Style instâncias são adicionadas para o ResourceDictionary usando o Add método, especificando um key cadeia
de caracteres para se referir a Style instância. O Style instância, em seguida, pode ser aplicada a todos os
controles do tipo correto no aplicativo. No entanto, os estilos globais podem ser explícita ou implícita.
O exemplo de código a seguir mostra um C# página aplicando o buttonStyle para a página Button instâncias:
public class ApplicationStylesPageCS : ContentPage
{
public ApplicationStylesPageCS ()
{
...
Content = new StackLayout {
Children = {
new Button { Text = "These buttons", Style = (Style)Application.Current.Resources
["buttonStyle"] },
new Button { Text = "are demonstrating", Style = (Style)Application.Current.Resources
["buttonStyle"] },
new Button { Text = "application styles", Style = (Style)Application.Current.Resources
["buttonStyle"]
}
}
};
}
}

O buttonStyle é aplicado ao Button instâncias, definindo suas Style propriedades e controla a aparência do
Button instâncias.

Links relacionados
Extensões de marcação XAML
Estilos básicos (amostra)
Trabalhar com estilos (amostra)
Dicionário de recurso
Estilo
Setter
Herança de estilo no xamarin. Forms
12/04/2019 • 5 minutes to read

baixar o exemplo
Estilos podem herdar de outros estilos para reduzir a duplicação e habilitar a reutilização.

Herança de estilo em XAML


Herança de estilo é executada, definindo o Style.BasedOn propriedade a um existente Style . No XAML, isso é
feito definindo a BasedOn propriedade para um StaticResource extensão de marcação que faz referência a um
criado anteriormente Style . No C#, isso é feito definindo a BasedOn propriedade para um Style instância.
Estilos de herdam de um estilo de base podem incluir Setter instâncias para novas propriedades, ou usá-los para
substituir os estilos do estilo de base. Além disso, os estilos que herdam de um estilo base devem ter como destino
o mesmo tipo ou um tipo derivado do tipo de destino pelo estilo de base. Por exemplo, se um estilo base utiliza
View instâncias, os estilos que são baseados no estilo de base podem ter como destino View instâncias ou tipos
que derivam de View classe, como Label e Button instâncias.
O código a seguir demonstra explícita herança de estilo em uma página XAML:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.StyleInheritancePage"
Title="Inheritance" Icon="xaml.png">
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="baseStyle" TargetType="View">
<Setter Property="HorizontalOptions"
Value="Center" />
<Setter Property="VerticalOptions"
Value="CenterAndExpand" />
</Style>
<Style x:Key="labelStyle" TargetType="Label"
BasedOn="{StaticResource baseStyle}">
...
<Setter Property="TextColor" Value="Teal" />
</Style>
<Style x:Key="buttonStyle" TargetType="Button"
BasedOn="{StaticResource baseStyle}">
<Setter Property="BorderColor" Value="Lime" />
...
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout Padding="0,20,0,0">
<Label Text="These labels"
Style="{StaticResource labelStyle}" />
...
<Button Text="So is the button"
Style="{StaticResource buttonStyle}" />
</StackLayout>
</ContentPage.Content>
</ContentPage>

O baseStyle destinos View instâncias e define o HorizontalOptions e VerticalOptions propriedades. O


baseStyle não é definida diretamente em todos os controles. Em vez disso, labelStyle e buttonStyle herdam
dela, definir valores de propriedade associável adicionais. O labelStyle e buttonStyle , em seguida, são aplicadas
para o Label instâncias e Button instância, definindo suas Style propriedades. Isso resulta na exibição mostrada
nas capturas de tela seguir:

NOTE
Um estilo implícito pode ser derivado de um estilo explícito, mas um estilo explícito não pode ser derivado de um estilo
implícito.

Respeitando a cadeia de herança


Um estilo pode herdar apenas de estilos no mesmo nível ou superior na hierarquia de exibição. Isso significa que:
Um recurso de nível de aplicativo só pode herdar de outros recursos de nível de aplicativo.
Um recurso de nível de página pode herdar de recursos de nível de aplicativo e outros recursos de nível de
página.
Um recurso de nível de controle pode herdar de recursos de nível de aplicativo, recursos de nível de página e
outros recursos de nível de controle.
Esta cadeia de herança é demonstrada no exemplo de código a seguir:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.StyleInheritancePage"
Title="Inheritance" Icon="xaml.png">
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="baseStyle" TargetType="View">
...
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout Padding="0,20,0,0">
<StackLayout.Resources>
<ResourceDictionary>
<Style x:Key="labelStyle" TargetType="Label" BasedOn="{StaticResource baseStyle}">
...
</Style>
<Style x:Key="buttonStyle" TargetType="Button" BasedOn="{StaticResource baseStyle}">
...
</Style>
</ResourceDictionary>
</StackLayout.Resources>
...
</StackLayout>
</ContentPage.Content>
</ContentPage>

Neste exemplo, labelStyle e buttonStyle é recursos de nível de controle enquanto baseStyle é um recurso de
nível de página. No entanto, enquanto labelStyle e buttonStyle herdar baseStyle , não é possível baseStyle
herdar de labelStyle ou buttonStyle , devido aos seus respectivos locais na hierarquia de exibição.

Herança de estilo em C#
A equivalente C# página, onde Style instâncias são atribuídas diretamente para o Style propriedades dos
controles necessários, é mostrado no exemplo de código a seguir:
public class StyleInheritancePageCS : ContentPage
{
public StyleInheritancePageCS ()
{
var baseStyle = new Style (typeof(View)) {
Setters = {
new Setter {
Property = View.HorizontalOptionsProperty, Value = LayoutOptions.Center },
...
}
};

var labelStyle = new Style (typeof(Label)) {


BasedOn = baseStyle,
Setters = {
...
new Setter { Property = Label.TextColorProperty, Value = Color.Teal }
}
};

var buttonStyle = new Style (typeof(Button)) {


BasedOn = baseStyle,
Setters = {
new Setter { Property = Button.BorderColorProperty, Value = Color.Lime },
...
}
};
...

Content = new StackLayout {


Children = {
new Label { Text = "These labels", Style = labelStyle },
...
new Button { Text = "So is the button", Style = buttonStyle }
}
};
}
}

O baseStyle destinos View instâncias e define o HorizontalOptions e VerticalOptions propriedades. O


baseStyle não é definida diretamente em todos os controles. Em vez disso, labelStyle e buttonStyle herdam
dela, definir valores de propriedade associável adicionais. O labelStyle e buttonStyle , em seguida, são aplicadas
para o Label instâncias e Button instância, definindo suas Style propriedades.

Links relacionados
Extensões de marcação XAML
Estilos básicos (amostra)
Trabalhar com estilos (amostra)
Dicionário de recurso
Estilo
Setter
Estilos dinâmicos no xamarin. Forms
12/04/2019 • 7 minutes to read

baixar o exemplo
Estilos não responder a alterações de propriedade e permanecem inalterados durante o período de um aplicativo.
Por exemplo, depois de atribuir um estilo a um elemento visual, se uma das instâncias de Setter for modificada,
removido, ou uma nova instância de Setter adicionada, as alterações não aplicadas para o elemento visual. No
entanto, os aplicativos podem responder a alterações de estilo dinamicamente em tempo de execução usando os
recursos dinâmicos.
O DynamicResource extensão de marcação é semelhante de StaticResource extensão de marcação em que ambos
usam uma chave de dicionário para buscar um valor de uma ResourceDictionary . No entanto, enquanto o
StaticResource executa uma pesquisa de dicionário único, o DynamicResource mantém um link para a chave do
dicionário. Portanto, se a entrada de dicionário associada com a chave for substituída, a alteração é aplicada ao
elemento visual. Isso permite que as alterações de estilo de tempo de execução a ser feita em um aplicativo.
O exemplo de código a seguir demonstra dinâmico estilos em uma página XAML:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.DynamicStylesPage" Title="Dynamic"
Icon="xaml.png">
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="baseStyle" TargetType="View">
...
</Style>
<Style x:Key="blueSearchBarStyle"
TargetType="SearchBar"
BasedOn="{StaticResource baseStyle}">
...
</Style>
<Style x:Key="greenSearchBarStyle"
TargetType="SearchBar">
...
</Style>
...
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout Padding="0,20,0,0">
<SearchBar Placeholder="These SearchBar controls"
Style="{DynamicResource searchBarStyle}" />
...
</StackLayout>
</ContentPage.Content>
</ContentPage>

O SearchBar instâncias uso o DynamicResource extensão de marcação para fazer referência a um Style chamado
searchBarStyle , que não é definido no XAML. No entanto, porque o Style propriedades do SearchBar instâncias
são definidas usando um DynamicResource , a chave de dicionário ausente não resulta em uma exceção sendo
lançada.
Em vez disso, no arquivo code-behind, o construtor cria um ResourceDictionary entrada com a chave
searchBarStyle , conforme mostrado no exemplo de código a seguir:
public partial class DynamicStylesPage : ContentPage
{
bool originalStyle = true;

public DynamicStylesPage ()
{
InitializeComponent ();
Resources ["searchBarStyle"] = Resources ["blueSearchBarStyle"];
}

void OnButtonClicked (object sender, EventArgs e)


{
if (originalStyle) {
Resources ["searchBarStyle"] = Resources ["greenSearchBarStyle"];
originalStyle = false;
} else {
Resources ["searchBarStyle"] = Resources ["blueSearchBarStyle"];
originalStyle = true;
}
}
}

Quando o OnButtonClicked manipulador de eventos é executado, searchBarStyle alternará entre


blueSearchBarStyle e greenSearchBarStyle . Isso resulta na exibição mostrada nas capturas de tela seguir:

] (dynamic-images/dynamic-style-green-
large.png#lightbox "Verde estilo dinâmico de exemplo")
O exemplo de código a seguir demonstra a página equivalente em C#:

public class DynamicStylesPageCS : ContentPage


{
bool originalStyle = true;

public DynamicStylesPageCS ()
{
...
var baseStyle = new Style (typeof(View)) {
...
};
var blueSearchBarStyle = new Style (typeof(SearchBar)) {
...
};
var greenSearchBarStyle = new Style (typeof(SearchBar)) {
...
};
...
var searchBar1 = new SearchBar { Placeholder = "These SearchBar controls" };
searchBar1.SetDynamicResource (VisualElement.StyleProperty, "searchBarStyle");
...
Resources = new ResourceDictionary ();
Resources.Add ("blueSearchBarStyle", blueSearchBarStyle);
Resources.Add ("greenSearchBarStyle", greenSearchBarStyle);
Resources ["searchBarStyle"] = Resources ["blueSearchBarStyle"];

Content = new StackLayout {


Children = { searchBar1, searchBar2, searchBar3, searchBar4, button }
};
}
...
}

No C#, o instâncias de uso de SetDynamicResource método a referenciar searchBarStyle . O


SearchBar
OnButtonClicked código do manipulador de eventos é idêntico ao exemplo XAML e, quando executada,
searchBarStyle alternará entre blueSearchBarStyle e greenSearchBarStyle .

Herança de estilo dinâmica


Derivar um estilo de um estilo dinâmico não pode ser feito usando o Style.BasedOn propriedade. Em vez disso, o
Style classe inclui os BaseResourceKey propriedade, que pode ser definida como uma chave de dicionário cujo
valor pode alterar dinamicamente.
O exemplo de código a seguir demonstra dinâmico herança de estilo em uma página XAML:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.DynamicStylesInheritancePage"
Title="Dynamic Inheritance" Icon="xaml.png">
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="baseStyle" TargetType="View">
...
</Style>
<Style x:Key="blueSearchBarStyle" TargetType="SearchBar" BasedOn="{StaticResource baseStyle}">
...
</Style>
<Style x:Key="greenSearchBarStyle" TargetType="SearchBar">
...
</Style>
<Style x:Key="tealSearchBarStyle" TargetType="SearchBar" BaseResourceKey="searchBarStyle">
...
</Style>
...
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout Padding="0,20,0,0">
<SearchBar Text="These SearchBar controls" Style="{StaticResource tealSearchBarStyle}" />
...
</StackLayout>
</ContentPage.Content>
</ContentPage>

O SearchBar instâncias de uso de StaticResource extensão de marcação para fazer referência a um Style
chamado tealSearchBarStyle . Isso Style define algumas propriedades adicionais e usa o BaseResourceKey
propriedade a referenciar searchBarStyle . O DynamicResource extensão de marcação não é necessária porque
tealSearchBarStyle não será alterado, exceto para o Style deriva. Portanto, tealSearchBarStyle mantém um link
para searchBarStyle e é alterado quando o estilo de base é alterado.
No arquivo code-behind, o construtor cria um ResourceDictionary entrada com a chave searchBarStyle , de
acordo com o exemplo anterior que demonstrou estilos dinâmicos. Quando o OnButtonClicked manipulador de
eventos é executado, searchBarStyle alternará entre blueSearchBarStyle e greenSearchBarStyle . Isso resulta na
exibição mostrada nas capturas de tela seguir:
O exemplo de código a seguir demonstra a página equivalente em C#:

public class DynamicStylesInheritancePageCS : ContentPage


{
bool originalStyle = true;

public DynamicStylesInheritancePageCS ()
{
...
var baseStyle = new Style (typeof(View)) {
...
};
var blueSearchBarStyle = new Style (typeof(SearchBar)) {
...
};
var greenSearchBarStyle = new Style (typeof(SearchBar)) {
...
};
var tealSearchBarStyle = new Style (typeof(SearchBar)) {
BaseResourceKey = "searchBarStyle",
...
};
...
Resources = new ResourceDictionary ();
Resources.Add ("blueSearchBarStyle", blueSearchBarStyle);
Resources.Add ("greenSearchBarStyle", greenSearchBarStyle);
Resources ["searchBarStyle"] = Resources ["blueSearchBarStyle"];

Content = new StackLayout {


Children = {
new SearchBar { Text = "These SearchBar controls", Style = tealSearchBarStyle },
...
}
};
}
...
}

O tealSearchBarStyle é atribuído diretamente para o Style propriedade do SearchBar instâncias. Isso Style
define algumas propriedades adicionais e usa o BaseResourceKey propriedade a referenciar searchBarStyle . O
SetDynamicResource método não é necessário aqui porque tealSearchBarStyle não será alterado, exceto para o
Style deriva. Portanto, tealSearchBarStyle mantém um link para searchBarStyle e é alterado quando o estilo de
base é alterado.
Links relacionados
Extensões de marcação XAML
Estilos dinâmicos (amostra)
Trabalhar com estilos (amostra)
Dicionário de recurso
Estilo
Setter
Estilos de dispositivo no xamarin. Forms
12/04/2019 • 4 minutes to read

baixar o exemplo
Xamarin. Forms inclui seis estilos dinâmicos, conhecidos como estilos de dispositivo, na classe Device.Styles.
O dispositivo estilos são:
BodyStyle
CaptionStyle
ListItemDetailTextStyle
ListItemTextStyle
SubtitleStyle
TitleStyle

Todos os estilos de seis só podem ser aplicados a Label instâncias. Por exemplo, uma Label que está exibindo o
corpo de um parágrafo pode definir seus Style propriedade a ser BodyStyle .
O exemplo de código a seguir demonstra como usar o dispositivo estilos em uma página XAML:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.DeviceStylesPage" Title="Device"
Icon="xaml.png">
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="myBodyStyle" TargetType="Label"
BaseResourceKey="BodyStyle">
<Setter Property="TextColor" Value="Accent" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout Padding="0,20,0,0">
<Label Text="Title style"
Style="{DynamicResource TitleStyle}" />
<Label Text="Subtitle text style"
Style="{DynamicResource SubtitleStyle}" />
<Label Text="Body style"
Style="{DynamicResource BodyStyle}" />
<Label Text="Caption style"
Style="{DynamicResource CaptionStyle}" />
<Label Text="List item detail text style"
Style="{DynamicResource ListItemDetailTextStyle}" />
<Label Text="List item text style"
Style="{DynamicResource ListItemTextStyle}" />
<Label Text="No style" />
<Label Text="My body style"
Style="{StaticResource myBodyStyle}" />
</StackLayout>
</ContentPage.Content>
</ContentPage>

Os estilos de dispositivo são associados ao uso de DynamicResource extensão de marcação. A natureza dinâmica
dos estilos pode ser vista no iOS, alterando a acessibilidade configurações para o tamanho do texto. A aparência
do dispositivo estilos é diferente em cada plataforma, conforme mostrado nas capturas de tela seguir:
Dispositivo estilos também podem ser derivados de definindo o BaseResourceKey propriedade para o nome da
chave para o estilo de dispositivo. No exemplo de código acima, myBodyStyle herda BodyStyle e define uma cor
do texto acentuados. Para obter mais informações sobre herança de estilo dinâmica, consulte herança de estilo
dinâmica.
O exemplo de código a seguir demonstra a página equivalente em C#:

public class DeviceStylesPageCS : ContentPage


{
public DeviceStylesPageCS ()
{
var myBodyStyle = new Style (typeof(Label)) {
BaseResourceKey = Device.Styles.BodyStyleKey,
Setters = {
new Setter {
Property = Label.TextColorProperty,
Value = Color.Accent
}
}
};

Title = "Device";
Icon = "csharp.png";
Padding = new Thickness (0, 20, 0, 0);

Content = new StackLayout {


Children = {
new Label { Text = "Title style", Style = Device.Styles.TitleStyle },
new Label { Text = "Subtitle style", Style = Device.Styles.SubtitleStyle },
new Label { Text = "Body style", Style = Device.Styles.BodyStyle },
new Label { Text = "Caption style", Style = Device.Styles.CaptionStyle },
new Label { Text = "List item detail text style",
Style = Device.Styles.ListItemDetailTextStyle },
new Label { Text = "List item text style", Style = Device.Styles.ListItemTextStyle },
new Label { Text = "No style" },
new Label { Text = "My body style", Style = myBodyStyle }
}
};
}
}

O Style propriedade de cada Label instância é definida como a propriedade apropriada do Devices.Styles
classe.

Acessibilidade
O dispositivo estilos respeitarem as preferências de acessibilidade, para que os tamanhos de fonte serão alterado
conforme as preferências de acessibilidade são alteradas em cada plataforma. Portanto, para dar suporte a texto
acessível, certifique-se de que o dispositivo estilos são usados como base para qualquer estilo de texto dentro de
seu aplicativo.
As capturas de tela a seguir demonstram os estilos de dispositivo em cada plataforma, com o menor tamanho de
fonte acessível:

As capturas de tela a seguir demonstram os estilos de dispositivo em cada plataforma, com o maior tamanho de
fonte acessível:

Links relacionados
Estilos de texto
Extensões de marcação XAML
Estilos dinâmicos (amostra)
Trabalhar com estilos (amostra)
Device.Styles
Dicionário de recurso
Estilo
Setter
Classes de estilo do xamarin. Forms
12/04/2019 • 5 minutes to read

Baixar o exemplo
Classes de estilo do xamarin. Forms permitem que vários estilos a ser aplicado a um controle, sem recorrer à
herança de estilo.

Criar classes de estilo


Uma classe de estilo que pode ser criada, definindo o Class propriedade em uma Style para um string que
representa o nome de classe. A vantagem que oferece, sobre a definição de um estilo explícito usando o x:Key de
atributo, é que várias classes de estilo podem ser aplicadas a um VisualElement .

IMPORTANT
Vários estilos podem compartilhar o mesmo nome de classe, desde que eles se destinam a diferentes tipos. Isso permite que
várias classes de estilo, que são nomeadas de maneira idêntica, para tipos diferentes de destino.

O exemplo a seguir mostra três BoxView classes, estilo e uma VisualElement classe de estilo:
<ContentPage ...>
<ContentPage.Resources>
<Style TargetType="BoxView"
Class="Separator">
<Setter Property="BackgroundColor"
Value="#CCCCCC" />
<Setter Property="HeightRequest"
Value="1" />
</Style>

<Style TargetType="BoxView"
Class="Rounded">
<Setter Property="BackgroundColor"
Value="#1FAECE" />
<Setter Property="HorizontalOptions"
Value="Start" />
<Setter Property="CornerRadius"
Value="10" />
</Style>

<Style TargetType="BoxView"
Class="Circle">
<Setter Property="BackgroundColor"
Value="#1FAECE" />
<Setter Property="WidthRequest"
Value="100" />
<Setter Property="HeightRequest"
Value="100" />
<Setter Property="HorizontalOptions"
Value="Start" />
<Setter Property="CornerRadius"
Value="50" />
</Style>

<Style TargetType="VisualElement"
Class="Rotated"
ApplyToDerivedTypes="true">
<Setter Property="Rotation"
Value="45" />
</Style>
</ContentPage.Resources>
</ContentPage>

O Separator , Rounded ,e Circle cada conjunto de classes do estilo BoxView propriedades com valores
específicos.
O Rotated classe de estilo tem uma TargetType dos VisualElement , que significa que ele só pode ser aplicado a
VisualElement instâncias. No entanto, sua ApplyToDerivedTypes estiver definida como true , que garante que ele
pode ser aplicado a todos os controles que derivam VisualElement , como BoxView . Para obter mais informações
sobre como aplicar um estilo a um tipo derivado, consulte aplicar um estilo a tipos derivados.
O código C# equivalente é:

var separatorBoxViewStyle = new Style(typeof(BoxView))


{
Class = "Separator",
Setters =
{
new Setter
{
Property = VisualElement.BackgroundColorProperty,
Value = Color.FromHex("#CCCCCC")
},
new Setter
{
{
Property = VisualElement.HeightRequestProperty,
Value = 1
}
}
};

var roundedBoxViewStyle = new Style(typeof(BoxView))


{
Class = "Rounded",
Setters =
{
new Setter
{
Property = VisualElement.BackgroundColorProperty,
Value = Color.FromHex("#1FAECE")
},
new Setter
{
Property = View.HorizontalOptionsProperty,
Value = LayoutOptions.Start
},
new Setter
{
Property = BoxView.CornerRadiusProperty,
Value = 10
}
}
};

var circleBoxViewStyle = new Style(typeof(BoxView))


{
Class = "Circle",
Setters =
{
new Setter
{
Property = VisualElement.BackgroundColorProperty,
Value = Color.FromHex("#1FAECE")
},
new Setter
{
Property = VisualElement.WidthRequestProperty,
Value = 100
},
new Setter
{
Property = VisualElement.HeightRequestProperty,
Value = 100
},
new Setter
{
Property = View.HorizontalOptionsProperty,
Value = LayoutOptions.Start
},
new Setter
{
Property = BoxView.CornerRadiusProperty,
Value = 50
}
}
};

var rotatedVisualElementStyle = new Style(typeof(VisualElement))


{
Class = "Rotated",
ApplyToDerivedTypes = true,
Setters =
{
new Setter
new Setter
{
Property = VisualElement.RotationProperty,
Value = 45
}
}
};

Resources = new ResourceDictionary


{
separatorBoxViewStyle,
roundedBoxViewStyle,
circleBoxViewStyle,
rotatedVisualElementStyle
};

Consumir classes de estilo


Classes de estilo que podem ser consumidas, definindo o StyleClass propriedade do controle, que é do tipo
IList<string> , para obter uma lista dos nomes de classe de estilo. As classes de estilo serão aplicadas, desde que
o tipo do controle corresponde a TargetType das classes de estilo.
O exemplo a seguir mostra três BoxView instâncias, cada conjunto às classes de estilo diferente:

<ContentPage ...>
<ContentPage.Resources>
...
</ContentPage.Resources>
<StackLayout Margin="20">
<BoxView StyleClass="Separator" />
<BoxView WidthRequest="100"
HeightRequest="100"
HorizontalOptions="Center"
StyleClass="Rounded, Rotated" />
<BoxView HorizontalOptions="Center"
StyleClass="Circle" />
</StackLayout>
</ContentPage>

Neste exemplo, a primeira BoxView estilo é feito para ser um separador de linha, enquanto o terceiro BoxView é
circular. O segundo BoxView tem duas classes do estilo aplicado a ele, que dê cantos arredondado de it e girá-lo 45
graus:
IMPORTANT
Várias classes de estilo podem ser aplicadas a um controle porque o StyleClass propriedade é do tipo IList<string> .
Quando isso ocorre, as classes de estilo são aplicadas na lista ordem crescente. Portanto, quando várias classes de estilo
define as propriedades idênticas, a propriedade na classe de estilo que está em posição mais elevada lista terá precedência.

O código C# equivalente é:

...
Content = new StackLayout
{
Children =
{
new BoxView { StyleClass = new [] { "Separator" } },
new BoxView { WidthRequest = 100, HeightRequest = 100, HorizontalOptions = LayoutOptions.Center,
StyleClass = new [] { "Rounded", "Rotated" } },
new BoxView { HorizontalOptions = LayoutOptions.Center, StyleClass = new [] { "Circle" } }
}
};

Links relacionados
Estilos básicos (amostra)
Aplicar estilo a aplicativos xamarin. Forms usando
folhas de estilo em cascata (CSS)
12/04/2019 • 23 minutes to read

baixar o exemplo
Xamarin. Forms dá suporte a elementos visuais de estilo usando folhas de estilo em cascata (CSS ).
Aplicativos xamarin. Forms podem ser estilizados usando CSS. Uma folha de estilos consiste em uma lista de
regras, com cada regra consiste em um bloco de declaração e um ou mais dos seletores. Um bloco de declaração
consiste em uma lista de declarações entre chaves, com cada declaração consiste em uma propriedade, dois-
pontos e um valor. Quando há várias declarações em um bloco, uma ponto e vírgula é inserida como um
separador. O exemplo de código a seguir mostra o CSS em conformidade com xamarin. Forms:
navigationpage {
-xf-bar-background-color: lightgray;
}

^contentpage {
background-color: lightgray;
}

#listView {
background-color: lightgray;
}

stacklayout {
margin: 20;
}

.mainPageTitle {
font-style: bold;
font-size: medium;
}

.mainPageSubtitle {
margin-top: 15;
}

.detailPageTitle {
font-style: bold;
font-size: medium;
text-align: center;
}

.detailPageSubtitle {
text-align: center;
font-style: italic;
}

listview image {
height: 60;
width: 60;
}

stacklayout>image {
height: 200;
width: 200;
}

No xamarin. Forms, folhas de estilo CSS são analisadas e avaliadas em tempo de execução, em vez de tempo de
compilação e folhas de estilo são analisadas novamente em uso.

NOTE
Atualmente, todos os estilos que são possíveis com estilo de XAML não podem ser executados com CSS. No entanto, os
estilos XAML podem ser usados para complementar o CSS para propriedades que não são atualmente suportadas pelo
xamarin. Forms. Para obter mais informações sobre estilos XAML, consulte estilos aplicativos xamarin. Forms usando os
estilos XAML.

O MonkeyAppCSS exemplo demonstra como usar CSS para definir o estilo de um aplicativo simples e é
mostrado nas capturas de tela seguir:
Consumindo uma folha de estilos
O processo para adicionar uma folha de estilos a uma solução é da seguinte maneira:
1. Adicione um arquivo CSS vazio ao seu projeto de biblioteca .NET Standard.
2. Defina a ação de compilação do arquivo CSS para EmbeddedResource.
Carregando uma folha de estilos
Há várias abordagens que podem ser usados para carregar uma folha de estilos.
XAML
Uma folha de estilos pode ser carregada e analisada com o StyleSheet classe antes de serem adicionados a um
ResourceDictionary :

<Application ...>
<Application.Resources>
<StyleSheet Source="/Assets/styles.css" />
</Application.Resources>
</Application>

O StyleSheet.Source propriedade especifica a folha de estilos como um URI relativo ao local do arquivo XAML
delimitador ou relativa à raiz do projeto se o URI começa com um / .
WARNING
O arquivo CSS não carregará se sua ação de compilação não está definida como EmbeddedResource.

Como alternativa, uma folha de estilos pode ser carregada e analisada com o StyleSheet classe antes de serem
adicionados a um ResourceDictionary , por inlining-lo em um CDATA seção:

<ContentPage ...>
<ContentPage.Resources>
<StyleSheet>
<![CDATA[
^contentpage {
background-color: lightgray;
}
]]>
</StyleSheet>
</ContentPage.Resources>
...
</ContentPage>

Para obter mais informações sobre dicionários de recursos, consulte dicionários de recursos.
C#
No C#, uma folha de estilos pode ser carregada como um recurso inserido e adicionada a um ResourceDictionary
:

public partial class MyPage : ContentPage


{
public MyPage()
{
InitializeComponent();

this.Resources.Add(StyleSheet.FromAssemblyResource(
IntrospectionExtensions.GetTypeInfo(typeof(MyPage)).Assembly,
"MyProject.Assets.styles.css"));
}
}

O primeiro argumento para o StyleSheet.FromAssemblyResource método é o assembly que contém a folha de


estilos, enquanto o segundo argumento é um string que representa o identificador de recurso. O identificador
de recurso pode ser obtido de propriedades janela quando o arquivo CSS está selecionado.
Como alternativa, uma folha de estilos pode ser carregada de um StringReader e adicionado a um
ResourceDictionary :

public partial class MyPage : ContentPage


{
public MyPage()
{
InitializeComponent();

using (var reader = new StringReader("^contentpage { background-color: lightgray; }"))


{
this.Resources.Add(StyleSheet.FromReader(reader));
}
}
}
O argumento para o StyleSheet.FromReader método é o TextReader que leu a folha de estilos.

Selecionando elementos e aplicação de propriedades


O CSS usa seletores para determinar quais elementos de destino. Estilos com correspondência seletores são
aplicados consecutivamente, na ordem de definição. Os estilos definidos em um item específico são sempre
aplicados pela última vez. Para obter mais informações sobre os seletores com suporte, consulte seletor de
referência.
O CSS usa propriedades para definir o estilo de um elemento selecionado. Cada propriedade tem um conjunto
de valores possíveis, e algumas propriedades podem afetar qualquer tipo de elemento, enquanto outras se
aplicam a grupos de elementos. Para obter mais informações sobre as propriedades com suporte, consulte
referência de propriedade.
Seleção de elementos por tipo
Elementos na árvore visual podem ser selecionados por tipo com maiusculas e minúsculas element seletor:

stacklayout {
margin: 20;
}

Este seletor identifica qualquer StackLayout elementos nas páginas que consomem a folha de estilos e define
suas margens para uma espessura uniforme de 20.

NOTE
O element seletor não identifica as subclasses do tipo especificado.

Selecionando elementos pela classe base


Elementos na árvore visual podem ser selecionados pela classe base com maiusculas e minúsculas ^base seletor:

^contentpage {
background-color: lightgray;
}

Este seletor identifica qualquer ContentPage elementos que consomem a folha de estilos e define seu plano de
fundo de cor para lightgray .

NOTE
O ^base seletor é específico ao xamarin. Forms e não faz parte da especificação do CSS.

Seleção de um elemento por nome


Elementos individuais da árvore visual podem ser selecionados com o diferencia maiusculas de minúsculas #id
seletor:

#listView {
background-color: lightgray;
}

Este seletor identifica o elemento cujos StyleId estiver definida como listView . No entanto, se o StyleId não
está definida, o seletor de fará o fallback para usar o x:Name do elemento. Portanto, no exemplo XAML a seguir, o
#listView seletor identificará a ListView cujo x:Name atributo é definido como listView e definirá a cor do
plano de fundo como lightgray .

<ContentPage ...>
<ContentPage.Resources>
<StyleSheet Source="/Assets/styles.css" />
</ContentPage.Resources>
<StackLayout>
<ListView x:Name="listView" ...>
...
</ListView>
</StackLayout>
</ContentPage>

Selecionar elementos com um atributo de classe específica


Elementos com um atributo de classe específica podem ser selecionados com o diferencia maiusculas de
minúsculas .class seletor:

.detailPageTitle {
font-style: bold;
font-size: medium;
text-align: center;
}

.detailPageSubtitle {
text-align: center;
font-style: italic;
}

Uma classe CSS pode ser atribuída a um elemento XAML, definindo o StyleClass propriedade do elemento a
ser o nome da classe CSS. Portanto, no exemplo XAML a seguir, os estilos definidos pelo .detailPageTitle classe
são atribuídos à primeira Label , enquanto os estilos definidos pelo .detailPageSubtitle classe são atribuídos ao
segundo Label .

<ContentPage ...>
<ContentPage.Resources>
<StyleSheet Source="/Assets/styles.css" />
</ContentPage.Resources>
<ScrollView>
<StackLayout>
<Label ... StyleClass="detailPageTitle" />
<Label ... StyleClass="detailPageSubtitle"/>
...
</StackLayout>
</ScrollView>
</ContentPage>

Selecionando elementos filho


Elementos filho na árvore visual podem ser selecionados com maiusculas e minúsculas element element seletor:

listview image {
height: 60;
width: 60;
}

Este seletor identifica qualquer Image elementos que são filhos do ListView elementos e define sua altura e
largura para 60. Portanto, no exemplo XAML a seguir, o listview image seletor identificará as Image que é um
filho do ListView e define sua altura e largura para 60.

<ContentPage ...>
<ContentPage.Resources>
<StyleSheet Source="/Assets/styles.css" />
</ContentPage.Resources>
<StackLayout>
<ListView ...>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
...
<Image ... />
...
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>

NOTE
O element element seletor não exige o elemento filho a ser uma direto filho do pai – o elemento filho pode ter um pai
diferente. Seleção ocorre desde que um ancestral seja o primeiro elemento especificado.

Selecionar os elementos filho direto


Direcionar a elementos filho na árvore visual podem ser selecionados com maiusculas e minúsculas
element>element seletor:

stacklayout>image {
height: 200;
width: 200;
}

Este seletor identifica qualquer Image direcionam de elementos que são filhos do StackLayout elementos e
define sua altura e largura para 200. Portanto, no exemplo XAML a seguir, o stacklayout>image seletor
identificará as Image que é um filho direto do StackLayout e define sua altura e largura para 200.

<ContentPage ...>
<ContentPage.Resources>
<StyleSheet Source="/Assets/styles.css" />
</ContentPage.Resources>
<ScrollView>
<StackLayout>
...
<Image ... />
...
</StackLayout>
</ScrollView>
</ContentPage>

NOTE
O element>element seletor requer que o elemento filho é um direto filho do pai.
Referência do seletor
Os seguintes seletores CSS são suportados pelo xamarin. Forms:

SELETOR EXEMPLO DESCRIÇÃO

.class .header Seleciona todos os elementos com o


StyleClass propriedade contendo
'header'. Observe que este seletor é
diferencia maiusculas de minúsculas.

#id #email Seleciona todos os elementos com


StyleId definido como email . Se
StyleId não for definido, o retorno
ao x:Name . Ao usar XAML, x:Name é
preferível StyleId . Observe que este
seletor é diferencia maiusculas de
minúsculas.

* * Seleciona todos os elementos.

element label Seleciona todos os elementos do tipo


Label , mas não as subclasses.
Observe que este seletor é diferencia
maiusculas de minúsculas.

^base ^contentpage Seleciona todos os elementos com


ContentPage como a classe base,
incluindo ContentPage em si. Observe
que este seletor diferencia maiusculas
de minúsculas e não faz parte da
especificação do CSS.

element,element label,button Seleciona todos os Button elementos


e todos os Label elementos. Observe
que este seletor é diferencia maiusculas
de minúsculas.

element element stacklayout label Seleciona todos os Label elementos


dentro de um StackLayout . Observe
que este seletor é diferencia maiusculas
de minúsculas.

element>element stacklayout>label Seleciona todos os Label elementos


com StackLayout como um pai
direto. Observe que este seletor é
diferencia maiusculas de minúsculas.

element+element label+entry Seleciona todos os Entry elementos


diretamente após um Label . Observe
que este seletor é diferencia maiusculas
de minúsculas.

element~element label~entry Seleciona todos os Entry elementos


precedido por um Label . Observe
que este seletor é diferencia maiusculas
de minúsculas.
Estilos com correspondência seletores são aplicados consecutivamente, na ordem de definição. Os estilos
definidos em um item específico são sempre aplicados pela última vez.

TIP
Seletores podem ser combinadas sem limitação, tais como StackLayout>ContentView>label.email .

Os seguintes seletores são atualmente suportados:


[attribute]
@media e @supports
: e ::

NOTE
Não há suporte a especificidade e substituições de especificidade.

Referência de propriedade
As propriedades CSS a seguir têm suporte pelo xamarin. Forms (na valores tipos de coluna, são itálico, enquanto
os literais de cadeia de caracteres são gray ):

PROPRIEDADE APLICA-SE A VALORES EXEMPLO

align-content FlexLayout stretch | center | align-content: space-


start | end | between;

spacebetween |
spacearound |
spaceevenly |
flex-start | flex-end |
space-between |
space-around | initial

align-items FlexLayout stretch | center | align-items: flex-


start;
start | end |
flex-start | flex-end |
initial

align-self VisualElement auto | stretch | align-self: flex-end;


center | start | end |
flex-start | flex-end |
initial

background-color VisualElement Cor | initial background-color:


springgreen;

background-image Page cadeia de caracteres | background-image:


initial bg.png;

border-color Button , Frame , Cor | initial border-color: #9acd32;


ImageButton
PROPRIEDADE APLICA-SE A VALORES EXEMPLO

border-radius BoxView , Button , Double | initial border-radius: 10;


Frame , ImageButton

border-width Button , ImageButton Double | initial border-width: .5;

color ActivityIndicator , Cor | initial color: rgba(255, 0, 0,


BoxView , Button , 0.3);

DatePicker , Editor ,
Entry , Label , Picker ,
ProgressBar , SearchBar ,
Switch , TimePicker

column-gap Grid Double | initial column-gap: 9;

direction VisualElement ltr | rtl | inherit | direction: rtl;


initial

flex-direction FlexLayout column | columnreverse | flex-direction: column-


row | rowreverse | reverse;

row-reverse |
column-reverse |
initial

flex-basis VisualElement float | auto | initial . flex-basis: 25%;


Além disso, uma
porcentagem no intervalo
de 0 a 100% pode ser
especificada com o % sinal.

flex-grow VisualElement float | initial flex-grow: 1.5;

flex-shrink VisualElement float | initial flex-shrink: 1;

flex-wrap VisualElement nowrap | wrap | flex-wrap: wrap-


reverse | wrap-reverse | reverse;

initial

font-family Button , DatePicker , cadeia de caracteres | font-family: Consolas;


Editor , Entry , Label , initial
Picker , SearchBar ,
TimePicker , Span

font-size Button , DatePicker , duplo | namedsize | font-size: 12;


Editor , Entry , Label , initial
Picker , SearchBar ,
TimePicker , Span

font-style Button , DatePicker , bold | italic | initial font-style: bold;


Editor , Entry , Label ,
Picker , SearchBar ,
TimePicker , Span
PROPRIEDADE APLICA-SE A VALORES EXEMPLO

height VisualElement Double | initial min-height: 250;

justify-content FlexLayout start | center | end | justify-content: flex-


spacebetween | end;

spacearound |
spaceevenly |
flex-start | flex-end |
space-between |
space-around | initial

line-height Label , Span Double | initial line-height: 1.8;

margin View Espessura | initial margin: 6 12;

margin-left View Espessura | initial margin-left: 3;

margin-top View Espessura | initial margin-top: 2;

margin-right View Espessura | initial margin-right: 1;

margin-bottom View Espessura | initial margin-bottom: 6;

max-lines Label int | initial max-lines: 2;

min-height VisualElement Double | initial min-height: 50;

min-width VisualElement Double | initial min-width: 112;

opacity VisualElement Double | initial opacity: .3;

order VisualElement int | initial order: -1;

padding Button , ImageButton , Espessura | initial padding: 6 12 12;


Layout , Page

padding-left Button , ImageButton , Double | initial padding-left: 3;


Layout , Page

padding-top Button , ImageButton , Double | initial padding-top: 4;


Layout , Page

padding-right Button , ImageButton , Double | initial padding-right: 2;


Layout , Page

padding-bottom Button , ImageButton , Double | initial padding-bottom: 6;


Layout , Page

position FlexLayout relative | absolute | position: absolute;


initial
PROPRIEDADE APLICA-SE A VALORES EXEMPLO

row-gap Grid Double | initial row-gap: 12;

text-align Entry , EntryCell , left | top | right | text-align: right;


Label , SearchBar | start |
bottom
| middle | end |
center
initial . left e right
devem ser evitadas em
ambientes da direita para
esquerda.

text-decoration Label , Span none | underline | text-decoration:


strikethrough | underline, line-
through;
line-through | initial

transform VisualElement none , rotate , rotateX , transform: rotate(180),


rotateY , scale , scaleX(2.5);

scaleX , scaleY ,
translate , translateX ,
translateY , initial

transform-origin VisualElement duplo, duplo | initial transform-origin: 7.5,


12.5;

vertical-align Label left | top | right | vertical-align: bottom;


bottom | start |
center | middle | end |
initial

visibility VisualElement true | visible | false visibility: hidden;


| hidden | collapse |
initial

width VisualElement Double | initial min-width: 320;

Também há suporte para as seguintes propriedades CSS específicas do xamarin. Forms (na valores tipos de
coluna, são itálico, enquanto os literais de cadeia de caracteres são gray ):

PROPRIEDADE APLICA-SE A VALORES EXEMPLO

-xf-placeholder Entry , Editor , texto entre aspas | -xf-placeholder: Enter


SearchBar initial name;

-xf-placeholder-color Entry , Editor , Cor | initial -xf-placeholder-color:


SearchBar green;

-xf-max-length Entry , Editor int | initial -xf-max-length: 20;

-xf-bar-background- NavigationPage , Cor | initial -xf-bar-background-


color TabbedPage color: teal;

-xf-bar-text-color NavigationPage , Cor | initial -xf-bar-text-color:


TabbedPage gray
PROPRIEDADE APLICA-SE A VALORES EXEMPLO

-xf-orientation ScrollView , horizontal| vertical | -xf-orientation:


StackLayout | initial . both
both horizontal;

só é compatível com um
ScrollView .

-xf-horizontal-scroll- ScrollView default | always | -xf-horizontal-scroll-


bar-visibility never | initial bar-visibility: never;

-xf-vertical-scroll- ScrollView default | always | -xf-vertical-scroll-


bar-visibility never | initial bar-visibility: always;

-xf-min-track-color Slider Cor | initial -xf-min-track-color:


yellow;

-xf-max-track-color Slider Cor | initial -xf-max-track-color:


red;

-xf-thumb-color Slider Cor | initial -xf-thumb-color:


limegreen;

-xf-spacing StackLayout Double | initial -xf-spacing: 8;

NOTE
initial é um valor válido para todas as propriedades. Limpa o valor (redefine como padrão) que foi definido de outro
estilo.

As propriedades a seguir têm suportadas no momento:


all: initial.
Propriedades de layout (caixa ou grade).
Propriedades de forma abreviada, como font ,e border .
Além disso, não há nenhum inherit herança de valor e, portanto, não é suportada. Portanto, você não pode, por
exemplo, defina a font-size propriedade em um layout e esperar que todos os Label instâncias no layout para
herdar o valor. A única exceção é o direction propriedade, que tem um valor padrão de inherit .
Cor
O seguinte color valores têm suporte:
X11 cores, que corresponde ao cores CSS, cores predefinidas do UWP e xamarin. Forms cores. Observe que
esses valores de cor diferenciam maiusculas de minúsculas.
Hex cores: #rgb , #argb , #rrggbb , #aarrggbb
as cores RGB: rgb(255,0,0) , rgb(100%,0%,0%) . Valores estão no intervalo 0 a 255, ou 0 a 100%.
cores RGBA: rgba(255, 0, 0, 0.8) , rgba(100%, 0%, 0%, 0.8) . O valor de opacidade está no intervalo 0,0 1,0.
cores HSL: hsl(120, 100%, 50%) . O valor h está no intervalo de 0 a 360, embora a s e l sejam no intervalo de 0
a 100%.
cores de hsla: hsla(120, 100%, 50%, .8) . O valor de opacidade está no intervalo 0,0 1,0.
Espessura
Um, dois, três ou quatro thickness há suporte para valores, cada um separado por espaço em branco:
Um único valor indica a espessura uniforme.
Dois valores indicam a espessura vertical e horizontal.
Três valores indicam a parte superior, em seguida, horizontal (left e right) e espessura da parte inferior.
Quatro valores indicam superior, seguido de à direita, em seguida, inferior e espessura à esquerda.

NOTE
CSS thickness valores diferentes de XAML Thickness valores. Por exemplo, em XAML, um valor de dois Thickness
indica a espessura horizontal e vertical, enquanto um valor de quatro Thickness indica à esquerda, em seguida, superior e
direita, inferior, em seguida, espessura. Além disso, o XAML Thickness valores são delimitados por vírgula.

NamedSize
O seguinte diferencia maiusculas de minúsculas namedsize valores têm suporte:
default
micro
small
medium
large

O significado exato de cada namedsize valor é dependente de plataforma e dependente do modo de exibição.

CSS no xamarin. Forms com Xamarin.University


Xamarin. Forms 3.0 CSS, por Xamarin University

Links relacionados
MonkeyAppCSS (amostra)
Dicionários de recurso
Aplicar estilo a aplicativos do Xamarin.Forms usando os estilos XAML
Modo de tabela do xamarin. Forms
12/04/2019 • 10 minutes to read

Baixar o exemplo
TableView é um modo de exibição de lista rolável de dados ou opções em que existem linhas que não
compartilham o mesmo modelo. Diferentemente ListView, TableView não tem o conceito de um ItemsSource ,
portanto, os itens devem ser adicionados como filhos.

Casos de uso
TableView é útil quando:
apresentar uma lista de configurações,
coleta de dados em um formulário, ou
mostrando dados que são apresentados diferente da linha a linha (por exemplo, números, porcentagens e
imagens).
TableView manipula a rolagem e layout de linhas nas seções atraentes, uma necessidade comum para os
cenários acima. O TableView usa o controle de exibição equivalente quando estiverem disponíveis, criar uma
aparência nativa para cada plataforma de base de cada plataforma.

Estrutura
Elementos em uma TableView são organizados em seções. Na raiz do TableView é o TableRoot , que é o pai
de um ou mais TableSection instâncias. Cada TableSection consiste em um título e um ou mais ViewCell
instâncias:
<TableView Intent="Settings">
<TableRoot>
<TableSection Title="Ring">
<SwitchCell Text="New Voice Mail" />
<SwitchCell Text="New Mail" On="true" />
</TableSection>
</TableRoot>
</TableView>

O código C# equivalente é:

Content = new TableView


{
Root = new TableRoot
{
new TableSection("Ring")
{
// TableSection constructor takes title as an optional parameter
new SwitchCell { Text = "New Voice Mail" },
new SwitchCell { Text = "New Mail", On = true }
}
},
Intent = TableIntent.Settings
};

Aparência
TableView expõe o Intent propriedade, que pode ser definida para qualquer um dos TableIntent membros
de enumeração:
Data – para uso ao exibir entradas de dados. Observe que ListView pode ser uma opção melhor para listas
de dados de rolagem.
Form – para uso quando o modo de tabela está agindo como um formulário.
Menu – para uso ao apresentar um menu das seleções.
Settings – para uso ao exibir uma lista de definições de configuração.

O TableIntent valor escolhido pode afetar como o TableView aparece em cada plataforma. Mesmo que haja
não limpará as diferenças, é uma prática recomendada para selecionar o TableIntent que mais se aproxima
como você pretende usar a tabela.
Além disso, a cor do texto exibida para cada TableSection pode ser alterado definindo o TextColor
propriedade a um Color .

Células internas
Xamarin. Forms é fornecido com células internas para coletar e exibir informações. Embora ListView e
TableView pode usar todas as células mesmas, SwitchCell e EntryCell são mais relevantes para um
TableView cenário.

Ver aparência de célula do ListView para obter uma descrição detalhada dos TextCell e ImageCell.
SwitchCell
SwitchCell é o controle a ser usado para apresentar e capturar um ligado/desligado ou true / false estado.
Ele define as propriedades a seguir:
Text – texto a ser exibido ao lado do comutador.
On – Se a opção é exibida como em ou desativado.
OnColor – o Color do comutador quando ele está em posição de ligado.

Todas essas propriedades são associáveis.


SwitchCell também expõe o OnChanged evento, permitindo que você responda às alterações no estado da
célula.

EntryCell
EntryCell é útil quando você precisa exibir dados de texto que o usuário pode editar. Ele define as
propriedades a seguir:
Keyboard – O teclado para exibir durante a edição. Há opções para coisas como valores numéricos, email,
números de telefone, etc. Consulte os documentos de API.
Label – O texto de rótulo a ser exibida à esquerda do campo de entrada de texto.
LabelColor – A cor do texto do rótulo.
Placeholder – Texto exibido no campo de entrada quando ele é nulo ou vazio. Esse texto desaparece quando
a entrada de texto começa.
Text – O texto no campo de entrada.
HorizontalTextAlignment – O alinhamento horizontal do texto. Pode ser centro, esquerdo ou direito
alinhado. Consulte os documentos de API.
EntryCell também expõe o Completed evento, que é disparado quando o usuário pressiona o botão
'concluído' no teclado durante a edição de texto.
Células personalizadas
Quando as células internas não forem suficientes, células personalizadas podem ser usadas para apresentar e
capturar dados da maneira que faça sentido para seu aplicativo. Por exemplo, você talvez queira apresentar um
controle deslizante para permitir ao usuário escolher a opacidade de uma imagem.
Todas as células personalizadas devem derivar de ViewCell , a mesma classe base que todos os internos célula
tipos de uso.
Este é um exemplo de uma célula personalizada:
O exemplo a seguir mostra o XAML usado para criar o TableView nas capturas de tela acima:

<?xml version="1.0" encoding="UTF-8"?>


<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DemoTableView.TablePage"
Title="TableView">
<TableView Intent="Settings">
<TableRoot>
<TableSection Title="Getting Started">
<ViewCell>
<StackLayout Orientation="Horizontal">
<Image Source="bulb.png" />
<Label Text="left"
TextColor="#f35e20" />
<Label Text="right"
HorizontalOptions="EndAndExpand"
TextColor="#503026" />
</StackLayout>
</ViewCell>
</TableSection>
</TableRoot>
</TableView>
</ContentPage>

O código C# equivalente é:
var table = new TableView();
table.Intent = TableIntent.Settings;
var layout = new StackLayout() { Orientation = StackOrientation.Horizontal };
layout.Children.Add (new Image() { Source = "bulb.png"});
layout.Children.Add (new Label()
{
Text = "left",
TextColor = Color.FromHex("#f35e20"),
VerticalOptions = LayoutOptions.Center
});
layout.Children.Add (new Label ()
{
Text = "right",
TextColor = Color.FromHex ("#503026"),
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.EndAndExpand
});
table.Root = new TableRoot ()
{
new TableSection("Getting Started")
{
new ViewCell() {View = layout}
}
};
Content = table;

O elemento raiz sob o TableView é o TableRoot e há um TableSection imediatamente abaixo o TableRoot . O


ViewCell é definido diretamente sob o TableSection e um StackLayout é usado para gerenciar o layout da
célula personalizada, embora qualquer layout pode ser usado aqui.

NOTE
Diferentemente ListView , TableView não exige que personalizado (ou qualquer) as células são definidas em um
ItemTemplate .

Altura da linha
O TableView classe tem duas propriedades que podem ser usadas para alterar a altura da linha de células:
RowHeight – Define a altura de cada linha para um int .
HasUnevenRows – linhas têm diferentes alturas se definido como true . Observe que, ao definir essa
propriedade como true , as alturas das linhas automaticamente serão calculadas e aplicadas pelo xamarin.
Forms.
Quando a altura do conteúdo em uma célula em uma TableView for alterado, a linha de altura é atualizada
implicitamente no Android e Universal Windows Platform (UWP ). No entanto, no iOS ele deve ser forçado a
atualizar definindo a HasUnevenRows propriedade true e chamando o Cell.ForceUpdateSize método.
A exemplo XAML a seguir mostra uma TableView que contém um ViewCell :
<ContentPage ...>
<TableView ...
HasUnevenRows="true">
<TableRoot>
...
<TableSection ...>
...
<ViewCell x:Name="_viewCell"
Tapped="OnViewCellTapped">
<Grid Margin="15,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Text="Tap this cell." />
<Label x:Name="_target"
Grid.Row="1"
Text="The cell has changed size."
IsVisible="false" />
</Grid>
</ViewCell>
</TableSection>
</TableRoot>
</TableView>
</ContentPage>

Quando o ViewCell é tocado, o OnViewCellTapped manipulador de eventos é executado:

void OnViewCellTapped(object sender, EventArgs e)


{
_target.IsVisible = !_target.IsVisible;
_viewCell.ForceUpdateSize();
}

O OnViewCellTapped manipulador de eventos mostra ou oculta a segunda Label no ViewCell e atualiza


explicitamente o tamanho da célula, chamando o Cell.ForceUpdateSize método.
As capturas de tela a seguir mostram a célula antes da que está sendo tocado após:

Capturas de tela as seguir mostram a célula depois sendo tocado após:

IMPORTANT
Há uma grande possibilidade de degradação do desempenho se esse recurso está sendo usado em excesso.

Links relacionados
Modo de tabela (amostra)
Texto no xamarin. Forms
12/04/2019 • 3 minutes to read

baixar o exemplo
Usando o xamarin. Forms para inserir ou exibir texto.
Xamarin. Forms tem três modos de exibição primários para trabalhar com texto:
Rótulo — para a apresentação de texto único ou várias linha. Pode mostrar o texto com várias opções de
formatação na mesma linha.
Entrada — para inserção de texto que é apenas uma linha. Entrada tem um modo de senha.
Editor — para inserção de texto que pode levar mais de uma linha.
Aparência do texto pode ser alterada usando internas ou personalizadas estilos e alguns controles oferecem
suporte personalizado fontes.

Rótulo
O Label exibição é usada para exibir o texto. Ele pode mostrar várias linhas de texto ou uma única linha de texto.
Label pode apresentar texto com várias opções de formatação usadas em embutido. O modo de exibição do
rótulo pode encapsular ou truncar o texto quando ela não couber em uma única linha.

Consulte a rótulo do artigo para obter mais informações.


Para obter informações sobre como personalizar a fonte usada em um rótulo, consulte fontes.
Entry
Entry é usado para aceitar a entrada de texto de linha única. Entry controle de ofertas sobre fontes e cores.
Entry tem um modo de senha e pode mostrar o texto de espaço reservado até que o texto é inserido.

Consulte a entrada artigo para obter mais informações.


Observe que, diferentemente Label , Entry não pode ter configurações de fonte personalizado.

Editor
Editor é usado para aceitar a entrada de texto de várias linhas. Editor controle de ofertas sobre fontes e cores.
Consulte a Editor artigo para obter mais informações.

Fontes
Muitos controles oferecem suporte a configurações de fonte diferente usando as fontes internas em cada
plataforma, ou fontes personalizadas, incluídas com o seu aplicativo. Consulte a fontes do artigo para obter mais
informações.

Estilos
Consulte a trabalhar com estilos para saber como configurar a fonte, core outras propriedades de exibição que se
aplicam a vários controles.

Links relacionados
Texto (exemplo)
Rótulo do xamarin. Forms
12/04/2019 • 18 minutes to read

baixar o exemplo
Exibir o texto no xamarin. Forms
O Label exibição é usada para exibir o texto, único e de várias linha. Rótulos podem ter as decorações de texto,
texto colorido e usar fontes personalizadas (famílias, tamanhos e opções).

Decorações de texto
Decorações de texto sublinhado e tachado podem ser aplicadas a Label instâncias, definindo o
Label.TextDecorations propriedade a um ou mais TextDecorations membros de enumeração:

None
Underline
Strikethrough

O exemplo XAML a seguir demonstra a configuração de Label.TextDecorations propriedade:

<Label Text="This is underlined text." TextDecorations="Underline" />


<Label Text="This is text with strikethrough." TextDecorations="Strikethrough" />
<Label Text="This is underlined text with strikethrough." TextDecorations="Underline, Strikethrough" />

O código C# equivalente é:

var underlineLabel = new Label { Text = "This is underlined text.", TextDecorations =


TextDecorations.Underline };
var strikethroughLabel = new Label { Text = "This is text with strikethrough.", TextDecorations =
TextDecorations.Strikethrough };
var bothLabel = new Label { Text = "This is underlined text with strikethrough.", TextDecorations =
TextDecorations.Underline | TextDecorations.Strikethrough };

As capturas de tela a seguir mostram os TextDecorations aplicados a membros da enumeração Label


instâncias:

NOTE
Decorações de texto também podem ser aplicadas a Span instâncias. Para obter mais informações sobre o Span classe,
consulte texto formatado em.

Cores
Rótulos podem ser definidos para usar uma cor de texto personalizado por meio de associável TextColor
propriedade.
Cuidado especial é necessário para garantir que as cores poderá ser usadas em cada plataforma. Como cada
plataforma tem diferentes padrões de cores de plano de fundo e texto, você precisará ter cuidado para escolher
um padrão que funciona em cada um.
O exemplo XAML a seguir define a cor do texto de um Label :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="TextSample.LabelPage"
Title="Label Demo">
<StackLayout Padding="5,10">
<Label TextColor="#77d065" FontSize = "20" Text="This is a green label." />
</StackLayout>
</ContentPage>

O código C# equivalente é:

public partial class LabelPage : ContentPage


{
public LabelPage ()
{
InitializeComponent ();

var layout = new StackLayout { Padding = new Thickness(5,10) };


var label = new Label { Text="This is a green label.", TextColor = Color.FromHex("#77d065"), FontSize
= 20 };
layout.Children.Add(label);
this.Content = layout;
}
}

As capturas de tela a seguir mostram o resultado da configuração de TextColor propriedade:

Para obter mais informações sobre as cores, consulte cores.

Fontes
Para obter mais informações sobre como especificar fontes em uma Label , consulte fontes.

Truncamento e quebra automática


Rótulos podem ser definidos para lidar com o texto que não cabe em uma linha em uma das várias maneiras,
expostas pelo LineBreakMode propriedade. LineBreakMode é uma enumeração com os seguintes valores:
HeadTruncation – trunca o cabeçalho do texto, mostrando o final.
CharacterWrap – quebra o texto em uma nova linha em um limite de caractere.
MiddleTruncation – exibe o início e fim do texto, com a substituição do meio por reticências.
NoWrap – não quebra o texto, exibindo somente texto como pode cabe em uma linha.
TailTruncation – mostra o início do texto, truncando final.
WordWrap – quebra o texto no limite de palavra.
Exibindo um número específico de linhas
O número de linhas exibidas por um Label pode ser especificada definindo o Label.MaxLines propriedade para
um int valor:
Quando MaxLines é 0, o Label respeita o valor da LineBreakMode propriedade como mostram apenas uma
linha, possivelmente truncada, ou todas as linhas com todo o texto.
Quando MaxLines for 1, o resultado é idêntico à configuração de LineBreakMode propriedade a ser NoWrap ,
HeadTruncation , MiddleTruncation , ou TailTruncation . No entanto, o Label respeitará o valor da
LineBreakMode propriedade em relação ao posicionamento de reticências, se aplicável.
Quando MaxLines é maior que 1, o Label exibirá até o número especificado de linhas, respeitando o valor da
LineBreakMode propriedade em relação ao posicionamento de reticências, se aplicável. No entanto, definir a
MaxLines propriedade para um valor maior que 1 não tem nenhum efeito se o LineBreakMode estiver definida
como NoWrap .

O exemplo XAML a seguir demonstra a configuração de MaxLines propriedade em um Label :

<Label Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. In facilisis nulla eu felis fringilla
vulputate. Nullam porta eleifend lacinia. Donec at iaculis tellus."
LineBreakMode="WordWrap"
MaxLines="2" />

O código C# equivalente é:

var label =
{
Text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In facilisis nulla eu felis fringilla
vulputate. Nullam porta eleifend lacinia. Donec at iaculis tellus.", LineBreakMode = LineBreakMode.WordWrap,
MaxLines = 2
};

As capturas de tela a seguir mostram o resultado da configuração de MaxLines propriedade como 2, quando o
texto é longo o suficiente para ocupar mais de 2 linhas:

Texto formatado
Rótulos de expõem uma FormattedText propriedade que permite que a apresentação de texto com várias fontes
e cores na mesma exibição.
O FormattedText propriedade é do tipo FormattedString , que consiste em um ou mais Span instâncias,
definidas por meio de Spans propriedade . O seguinte Span propriedades podem ser usadas para definir a
aparência visual:
BackgroundColor – a cor do plano de fundo span.
Font – a fonte do texto no trecho.
FontAttributes – os atributos de fonte para o texto no trecho.
FontFamily – a família de fontes ao qual pertence a fonte do texto no trecho.
FontSize – o tamanho da fonte para o texto no trecho.
ForegroundColor – a cor do texto no trecho. Essa propriedade está obsoleta e foi substituída pelo TextColor
propriedade.
LineHeight -o multiplicador para aplicar a altura de linha padrão da extensão. Para obter mais informações,
consulte altura da linha.
Text – o estilo a ser aplicado para o período.
Text – o texto da marca span.
TextColor – a cor do texto no trecho.
TextDecorations -as decorações para aplicar ao texto no trecho. Para obter mais informações, consulte
decorações de texto.

NOTE
O BackgroundColor , Text , e Text propriedades vinculáveis têm um modo de associação padrão do OneWay . Para
obter mais informações sobre esse modo de associação, consulte o modo de associação padrão na modo de associação
guia.

Além disso, o GestureRecognizers propriedade pode ser usada para definir uma coleção dos reconhecedores de
gestos que irá responder a gestos no Span .
O exemplo XAML a seguir demonstra uma FormattedText propriedade consiste em três Span instâncias:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="TextSample.LabelPage"
Title="Label Demo - XAML">
<StackLayout Padding="5,10">
...
<Label LineBreakMode="WordWrap">
<Label.FormattedText>
<FormattedString>
<Span Text="Red Bold, " TextColor="Red" FontAttributes="Bold" />
<Span Text="default, " Style="{DynamicResource BodyStyle}">
<Span.GestureRecognizers>
<TapGestureRecognizer Command="{Binding TapCommand}" />
</Span.GestureRecognizers>
</Span>
<Span Text="italic small." FontAttributes="Italic" FontSize="Small" />
</FormattedString>
</Label.FormattedText>
</Label>
</StackLayout>
</ContentPage>

O código C# equivalente é:
public class LabelPageCode : ContentPage
{
public LabelPageCode ()
{
var layout = new StackLayout{ Padding = new Thickness (5, 10) };
...
var formattedString = new FormattedString ();
formattedString.Spans.Add (new Span{ Text = "Red bold, ", ForegroundColor = Color.Red, FontAttributes
= FontAttributes.Bold });

var span = new Span { Text = "default, " };


span.GestureRecognizers.Add(new TapGestureRecognizer { Command = new Command(async () => await
DisplayAlert("Tapped", "This is a tapped Span.", "OK")) });
formattedString.Spans.Add(span);
formattedString.Spans.Add (new Span { Text = "italic small.", FontAttributes = FontAttributes.Italic,
FontSize = Device.GetNamedSize(NamedSize.Small, typeof(Label)) });

layout.Children.Add (new Label { FormattedText = formattedString });


this.Content = layout;
}
}

IMPORTANT
O Text propriedade de um Span pode ser definido por meio da vinculação de dados. Para obter mais informações,
consulte associação de dados.

Observe que um Span também pode responder a qualquer gestos que são adicionados para o período
GestureRecognizers coleção. Por exemplo, uma TapGestureRecognizer foi adicionada à segunda Span nos
exemplos de código acima. Portanto, quando isso Span é tocado a TapGestureRecognizer responderá executando
o ICommand definido pelo Command propriedade. Para obter mais informações sobre os reconhecedores de
gestos, consulte xamarin. Forms gestos.
As capturas de tela a seguir mostram o resultado da configuração de FormattedString propriedade para três
Span instâncias:

Altura da linha
A altura vertical de um Label e uma Span pode ser personalizado definindo o Label.LineHeight propriedade
ou Span.LineHeight para um double valor. No iOS e Android, esses valores são multiplicadores da altura da
linha original e na plataforma Universal de Windows (UWP ) o Label.LineHeight valor da propriedade é um
multiplicador de tamanho da fonte do rótulo.
NOTE
No iOS, o Label.LineHeight e Span.LineHeight propriedades alterar a altura da linha de texto que cabem em uma
única linha e o texto que é quebrada em várias linhas.
No Android, o Label.LineHeight e Span.LineHeight propriedades apenas alterar a altura da linha de texto que é
quebrada em várias linhas.
Na UWP, o Label.LineHeight propriedade altera a altura da linha de texto que é quebrada em várias linhas, e o
Span.LineHeight propriedade não tem nenhum efeito.

O exemplo XAML a seguir demonstra a configuração de LineHeight propriedade em uma Label :

<Label Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. In facilisis nulla eu felis fringilla
vulputate. Nullam porta eleifend lacinia. Donec at iaculis tellus."
LineBreakMode="WordWrap"
LineHeight="1.8" />

O código C# equivalente é:

var label =
{
Text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In facilisis nulla eu felis fringilla
vulputate. Nullam porta eleifend lacinia. Donec at iaculis tellus.", LineBreakMode = LineBreakMode.WordWrap,
LineHeight = 1.8
};

As capturas de tela a seguir mostram o resultado da configuração de Label.LineHeight propriedade para o 1.8:

O exemplo XAML a seguir demonstra a configuração de LineHeight propriedade em uma Span :

<Label LineBreakMode="WordWrap">
<Label.FormattedText>
<FormattedString>
<Span Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. In a tincidunt sem.
Phasellus mollis sit amet turpis in rutrum. Sed aliquam ac urna id scelerisque. "
LineHeight="1.8"/>
<Span Text="Nullam feugiat sodales elit, et maximus nibh vulputate id."
LineHeight="1.8" />
</FormattedString>
</Label.FormattedText>
</Label>

O código C# equivalente é:
var formattedString = new FormattedString();
formattedString.Spans.Add(new Span
{
Text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In a tincidunt sem. Phasellus mollis sit
amet turpis in rutrum. Sed aliquam ac urna id scelerisque. ",
LineHeight = 1.8
});
formattedString.Spans.Add(new Span
{
Text = "Nullam feugiat sodales elit, et maximus nibh vulputate id.",
LineHeight = 1.8
});
var label = new Label
{
FormattedText = formattedString,
LineBreakMode = LineBreakMode.WordWrap
};

As capturas de tela a seguir mostram o resultado da configuração de Span.LineHeight propriedade para o 1.8:

Hiperlinks
O texto exibido pelo Label e Span instâncias podem ser transformadas em hiperlinks com a seguinte
abordagem:
1. Defina as TextColor e TextDecoration propriedades da Label ou Span .
2. Adicionar um TapGestureRecognizer para o GestureRecognizers coleção do Label ou Span , cuja Command
propriedade associa a um ICommand e cujo CommandParameter propriedade contém a URL para abrir.
3. Definir as ICommand que será executado pelo TapGestureRecognizer .
4. Escrever o código que será executado pelo ICommand .

O exemplo de código a seguir, extraído o demonstrações de hiperlink exemplo mostra um Label cujo conteúdo
é definido de vários Span instâncias:
<Label>
<Label.FormattedText>
<FormattedString>
<Span Text="Alternatively, click " />
<Span Text="here"
TextColor="Blue"
TextDecorations="Underline">
<Span.GestureRecognizers>
<TapGestureRecognizer Command="{Binding TapCommand}"
CommandParameter="https://docs.microsoft.com/xamarin/" />
</Span.GestureRecognizers>
</Span>
<Span Text=" to view Xamarin documentation." />
</FormattedString>
</Label.FormattedText>
</Label>

Neste exemplo, o primeiro e terceiro Span instâncias abrangem o texto, enquanto o segundo Span representa
um hiperlink tappable. Ele tem a sua cor de texto definido como azul e tem uma decoração de texto sublinhado.
Isso cria a aparência de um hiperlink, conforme mostrado nas capturas de tela seguir:

Quando o hiperlink é tocado, o TapGestureRecognizer responderá executando o ICommand definidas pelo seu
Command propriedade. Além disso, a URL especificada o CommandParameter propriedade será passada para o
ICommand como um parâmetro.

O code-behind da página XAML contém o TapCommand implementação:

public partial class MainPage : ContentPage


{
public ICommand TapCommand => new Command<string>(OpenBrowser);

public MainPage()
{
InitializeComponent();
BindingContext = this;
}

void OpenBrowser(string url)


{
Device.OpenUri(new Uri(url));
}
}
O TapCommand executa o OpenBrowser método, passando a TapGestureRecognizer.CommandParameter valor da
propriedade como um parâmetro. Por sua vez, esse método chama o Device.OpenUri método para abrir a URL
em um navegador da web. Portanto, o efeito geral é que quando o hiperlink é tocado na página, aparece um
navegador da web e navega para a URL associada no hiperlink.
Criando uma classe reutilizável de hiperlink
A abordagem anterior para criar um hiperlink requer escrevendo código repetitivo toda vez que você precisar de
um hiperlink em seu aplicativo. No entanto, ambos os Label e Span classes podem ser uma subclasse para criar
HyperlinkLabel e HyperlinkSpan classes, com o código de formatação de texto e o reconhecedor de gestos
adicionado lá.
O exemplo de código a seguir, extraído o hiperlink demonstrações exemplo mostra um HyperlinkSpan classe:

public class HyperlinkSpan : Span


{
public static readonly BindableProperty UrlProperty =
BindableProperty.Create(nameof(Url), typeof(string), typeof(HyperlinkSpan), null);

public string Url


{
get { return (string)GetValue(UrlProperty); }
set { SetValue(UrlProperty, value); }
}

public HyperlinkSpan()
{
TextDecorations = TextDecorations.Underline;
TextColor = Color.Blue;
GestureRecognizers.Add(new TapGestureRecognizer
{
Command = new Command(() => Device.OpenUri(new Uri(Url)))
});
}
}

O HyperlinkSpan classe define um Url propriedade e respectivos BindableProperty , e o construtor define a


aparência de hiperlink e o TapGestureRecognizer que responderá Quando o hiperlink é tocado. Quando um
HyperlinkSpan é tocado, o TapGestureRecognizer responderá executando o Device.OpenUri método para abrir a
URL especificada pelo Url propriedade, em um navegador da web.
O HyperlinkSpan classe pode ser consumido pela adição de uma instância da classe para o XAML:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:HyperlinkDemo"
x:Class="HyperlinkDemo.MainPage">
<StackLayout>
...
<Label>
<Label.FormattedText>
<FormattedString>
<Span Text="Alternatively, click " />
<local:HyperlinkSpan Text="here"
Url="https://docs.microsoft.com/appcenter/" />
<Span Text=" to view AppCenter documentation." />
</FormattedString>
</Label.FormattedText>
</Label>
</StackLayout>
</ContentPage>
Estilo de rótulos
As seções anteriores coberto configuração Label e Span propriedades em uma base por instância. No entanto,
os conjuntos de propriedades podem ser agrupados em um estilo que é aplicado consistentemente a um ou
vários modos de exibição. Isso pode aumentar a legibilidade do código e fazer alterações de design mais fácil de
implementar. Para obter mais informações, consulte estilos.

Links relacionados
Texto (exemplo)
Hiperlinks (amostra)
Criação de aplicativos móveis com xamarin. Forms, capítulo 3
API de rótulo
API de alcance
Entrada do xamarin. Forms
12/04/2019 • 17 minutes to read

baixar o exemplo
Texto de linha única ou de entrada de senha
O xamarin. Forms Entry é usado para entrada de texto de linha única. O Entry , como o Editor exibir, dá
suporte a vários tipos de teclado. Além disso, o Entry pode ser usado como um campo de senha.

Personalização da exibição
Definir e ler texto
O Entry , assim como outras exibições de apresentação de texto, expõe o Text propriedade. Essa propriedade
pode ser usada para definir e ler o texto apresentado pelo Entry . O exemplo a seguir demonstra a configuração
de Text propriedade em XAML:

<Entry Text="I am an Entry" />

No C#:

var MyEntry = new Entry { Text = "I am an Entry" };

Para ler o texto, acessar o Text propriedade em c#:

var text = MyEntry.Text;

Definir o texto de espaço reservado


O Entry pode ser definido para mostrar o texto de espaço reservado quando ele não está armazenando a
entrada do usuário. Isso é feito definindo a Placeholder propriedade como um string e geralmente é usado
para indicar o tipo de conteúdo que é apropriado para o Entry . Além disso, a cor do texto de espaço reservado
pode ser controlada definindo a PlaceholderColor propriedade como um Color :

<Entry Placeholder="Username" PlaceholderColor="Olive" />

var entry = new Entry { Placeholder = "Username", PlaceholderColor = Color.Olive };

NOTE
A largura de uma Entry pode ser definida ao configurar seu WidthRequest propriedade. Não dependem da largura de
uma Entry que está sendo definida com base no valor de seu Text propriedade.

Impedindo a entrada de texto


Os usuários podem ser impedidos de modificar o texto em uma Entry definindo a IsReadOnly propriedade, que
tem um valor padrão de false , para true :
<Entry Text="This is a read-only Entry"
IsReadOnly="true" />

var entry = new Entry { Text = "This is a read-only Entry", IsReadOnly = true });

NOTE
O IsReadonly propriedade não altera a aparência visual de um Entry , ao contrário o IsEnabled propriedade que
também altera a aparência visual do Entry em cinza.

Limitação de tamanho de entrada


O MaxLength propriedade pode ser usada para limitar o tamanho de entrada é permitido para o Entry . Essa
propriedade deve ser definida como um inteiro positivo:

<Entry ... MaxLength="10" />

var entry = new Entry { ... MaxLength = 10 };

Um MaxLength valor de propriedade de 0 indica que nenhuma entrada será permitida e um valor de
int.MaxValue , que é o valor padrão para um Entry , indica que não há nenhum limite efetivo no número de
caracteres que podem ser inseridos.
Campos de senha
Entry fornece o IsPassword propriedade. Quando IsPassword é true , o conteúdo do campo será apresentado
como círculos pretos:
No XAML:

<Entry IsPassword="true" />

No C#:

var MyEntry = new Entry { IsPassword = true };


Os espaços reservados podem ser usados com instâncias de Entry que são configurados como campos de
senha:
No XAML:

<Entry IsPassword="true" Placeholder="Password" />

No C#:

var MyEntry = new Entry { IsPassword = true, Placeholder = "Password" };


Definindo a posição do Cursor e o comprimento da seleção de texto
O CursorPosition propriedade pode ser usada para retornar ou definir a posição em que o próximo caractere
será inserido na cadeia de caracteres armazenada em do Text propriedade:

<Entry Text="Cursor position set" CursorPosition="5" />

var entry = new Entry { Text = "Cursor position set", CursorPosition = 5 };

O valor padrão de CursorPosition propriedade é 0, que indica que o texto será inserido no início do Entry .
Além disso, o SelectionLength propriedade pode ser usada para retornar ou definir o comprimento da seleção
de texto dentro de Entry :

<Entry Text="Cursor position and selection length set" CursorPosition="2" SelectionLength="10" />

var entry = new Entry { Text = "Cursor position and selection length set", CursorPosition = 2,
SelectionLength = 10 };

O valor padrão de SelectionLength propriedade é 0, que indica que nenhum texto estiver selecionado.
Personalizando o teclado
O teclado que é apresentado quando os usuários interagem com um Entry podem ser definidas
programaticamente por meio dos Keyboard propriedade a uma das seguintes propriedades do Keyboard classe:
Chat – usado para mandar um texto e locais em que o emoji são úteis.
Default – o teclado padrão.
Email – usado ao inserir endereços de email.
Numeric – usado ao inserir números.
Plain – usado ao inserir texto, sem nenhuma KeyboardFlags especificado.
Telephone – usado ao inserir números de telefone.
Text – usado ao inserir texto.
Url – usado para inserir caminhos de arquivo & endereços da web.

Isso pode ser feito no XAML da seguinte maneira:

<Entry Keyboard="Chat" />

O código c# equivalente é:

var entry = new Entry { Keyboard = Keyboard.Chat };

Exemplos de cada teclado podem ser encontrados em nossa receitas repositório.


O Keyboard classe também tem uma Create método de fábrica que pode ser usado para personalizar um
teclado, especificando o comportamento de letras maiusculas, verificação ortográfica e sugestão. KeyboardFlags
valores de enumeração são especificados como argumentos para o método, com um personalizado Keyboard
que está sendo retornado. O KeyboardFlags enumeração contém os seguintes valores:
None – Não há recursos são adicionados ao teclado.
CapitalizeSentence – indica que a primeira letra da primeira palavra de cada frase inserida serão
automaticamente maiusculas.
Spellcheck – indica que essa verificação ortográfica será executada em texto digitado.
Suggestions – indica que o preenchimentos serão oferecidos em texto digitado.
CapitalizeWord – indica que a primeira letra de cada palavra serão automaticamente maiusculas.
CapitalizeCharacter – indica que todos os caracteres serão automaticamente maiusculas.
CapitalizeNone – indica que nenhum capitalização automática ocorrerá.
All – indica que a verificação ortográfica, preenchimentos de palavra e capitalização de frase serão ocorrer
em texto digitado.
O exemplo de código XAML a seguir mostra como personalizar o padrão Keyboard para oferecer
preenchimentos de palavra e tirar proveito de todos os caracteres inseridos:

<Entry Placeholder="Enter text here">


<Entry.Keyboard>
<Keyboard x:FactoryMethod="Create">
<x:Arguments>
<KeyboardFlags>Suggestions,CapitalizeCharacter</KeyboardFlags>
</x:Arguments>
</Keyboard>
</Entry.Keyboard>
</Entry>

O código c# equivalente é:

var entry = new Entry { Placeholder = "Enter text here" };


entry.Keyboard = Keyboard.Create(KeyboardFlags.Suggestions | KeyboardFlags.CapitalizeCharacter);
Personalizando a tecla Return
A aparência da chave retorno sobre o teclado virtual, que é exibido quando um Entry tem o foco, pode ser
personalizado definindo as ReturnType propriedade um valor de ReturnType enumeração:
Default – indica que nenhuma chave de retorno específico é necessário e que será usado o padrão de
plataforma.
Done – indica uma chave de retornada "Done".
Go – indica uma chave de retorno de "Ir".
Next – indica uma chave de retornada "Avançar".
Search – indica uma chave de retorno de "Pesquisar".
Send – indica uma chave de retorno de "Envio".

O exemplo XAML a seguir mostra como definir a chave de retornada:

<Entry ReturnType="Send" />

O código c# equivalente é:

var entry = new Entry { ReturnType = ReturnType.Send };

NOTE
A aparência exata da chave de retorno depende da plataforma. No iOS, a tecla return é um botão com base em texto. No
entanto, nas plataformas universais do Windows e Android, a tecla return é um botão de ícone.

Quando a tecla return é pressionada, o Completed evento é acionado e qualquer ICommand especificado pela
ReturnCommand propriedade é executada. Além disso, qualquer object especificado pelo ReturnCommandParameter
propriedade será passada para o ICommand como um parâmetro. Para obter mais informações sobre comandos,
consulte a Interface de comando.
Habilitar e desabilitar a verificação ortográfica
O IsSpellCheckEnabled propriedade controla se verificação ortográfica está habilitada. Por padrão, a propriedade
é definida como true . Enquanto o usuário insere texto, erros de ortografia são indicados.
No entanto, para alguns cenários de entrada de texto, como inserir um nome de usuário, verificação ortográfica
fornece uma experiência negativa e deve ser desabilitada definindo a IsSpellCheckEnabled propriedade false :

<Entry ... IsSpellCheckEnabled="false" />

var entry = new Entry { ... IsSpellCheckEnabled = false };

NOTE
Quando o IsSpellCheckEnabled estiver definida como false e um teclado personalizado não está sendo usado, o
verificador ortográfico nativo será desabilitado. No entanto, se um Keyboard tem sido conjunto que desabilita ortográfica
verificação, como Keyboard.Chat , o IsSpellCheckEnabled propriedade será ignorada. Portanto, a propriedade não
pode ser usada para habilitar a verificação ortográfica para um Keyboard que desabilita explicitamente a ele.

Habilitando e desabilitando a previsão de texto


O IsTextPredictionEnabled propriedade controla se a previsão de texto e automático correção de texto está
habilitada. Por padrão, a propriedade é definida como true . Enquanto o usuário insere texto, previsões do word
são apresentados.
No entanto, para alguns cenários de entrada de texto, como inserir um nome de usuário, a previsão de texto e o
texto automático correção fornece uma experiência negativa e deve ser desabilitada definindo a
IsTextPredictionEnabled propriedade false :

<Entry ... IsTextPredictionEnabled="false" />

var entry = new Entry { ... IsTextPredictionEnabled = false };

NOTE
Quando o IsTextPredictionEnabled estiver definida como false , e um teclado personalizado não está sendo usado, a
previsão de texto e automático correção de texto está desabilitada. No entanto, se um Keyboard tiver sido definido que
desabilita a previsão de texto, o IsTextPredictionEnabled propriedade será ignorada. Portanto, a propriedade não pode
ser usada para habilitar a previsão de texto para um Keyboard que desabilita explicitamente a ele.

Cores
Pode ser configurada para usar um plano de fundo personalizado e as cores de texto por meio das seguintes
propriedades vinculáveis:
TextColor – define a cor do texto.
BackgroundColor – define a cor mostrada atrás do texto.
Cuidado especial é necessário para garantir que as cores poderá ser usadas em cada plataforma. Como cada
plataforma tem diferentes padrões de cores de plano de fundo e texto, geralmente você precisará definir ambos
se você definir um.
Use o código a seguir para definir a cor do texto de uma entrada:
No XAML:

<Entry TextColor="Green" />

No C#:

var entry = new Entry();


entry.TextColor = Color.Green;
Observe que o espaço reservado não é afetado pela especificado TextColor .
Para definir a cor do plano de fundo no XAML:

<Entry BackgroundColor="#2c3e50" />

No C#:

var entry = new Entry();


entry.BackgroundColor = Color.FromHex("#2c3e50");
Tenha cuidado para certificar-se de que as cores de plano de fundo e texto que você escolher podem ser usados
em cada plataforma e não ocultam qualquer texto de espaço reservado.

Eventos e interatividade
Entrada expõe dois eventos:
TextChanged – gerado quando o texto é alterado na entrada. Fornece o texto antes e após a alteração.
Completed – gerado quando o usuário terminou entrada pressionando a tecla return no teclado.

NOTE
O VisualElement classe da qual Entry herda, também tem Focused e Unfocused eventos.

Concluído
O Completed evento é usado para responder à realização de uma interação com uma entrada. Completed é
gerado quando o usuário encerra a entrada com um campo, pressionando a tecla return no teclado. O
manipulador para o evento é um manipulador de eventos genéricos, levando o remetente e EventArgs :

void Entry_Completed (object sender, EventArgs e)


{
var text = ((Entry)sender).Text; //cast sender to access the properties of the Entry
}

O evento concluído pode ser assinado em XAML:


<Entry Completed="Entry_Completed" />

e o c#:

var entry = new Entry ();


entry.Completed += Entry_Completed;

Após o Completed evento é acionado, qualquer ICommand especificado pela ReturnCommand propriedade for
executada, com o object especificado pelo ReturnCommandParameter propriedade que está sendo passada para o
ICommand .

TextChanged
O TextChanged evento é usado para responder a uma alteração no conteúdo de um campo.
TextChanged é gerado sempre que o Text do Entry alterações. O manipulador para o evento usa uma instância
de TextChangedEventArgs . TextChangedEventArgs fornece acesso aos valores novos e antigos do Entry Text por
meio de OldTextValue e NewTextValue propriedades:

void Entry_TextChanged (object sender, TextChangedEventArgs e)


{
var oldText = e.OldTextValue;
var newText = e.NewTextValue;
}

O TextChanged eventos podem ser assinados em XAML:

<Entry TextChanged="Entry_TextChanged" />

e o c#:

var entry = new Entry ();


entry.TextChanged += Entry_TextChanged;

Links relacionados
Texto (exemplo)
Entrada de API
Editor do xamarin. Forms
12/04/2019 • 14 minutes to read

baixar o exemplo
Entrada de texto de várias linhas
O Editor controle é usado para aceitar a entrada de várias linha. Este artigo aborda:
Personalização – opções de teclado e cor.
Interatividade – eventos que podem ser escutados para fornecer interatividade.

Personalização
Definir e ler texto
O Editor , assim como outras exibições de apresentação de texto, expõe o Text propriedade. Essa propriedade
pode ser usada para definir e ler o texto apresentado pelo Editor . O exemplo a seguir demonstra a configuração
de Text propriedade em XAML:

<Editor Text="I am an Editor" />

No C#:

var MyEditor = new Editor { Text = "I am an Editor" };

Para ler o texto, acessar o Text propriedade em c#:

var text = MyEditor.Text;

Definir o texto de espaço reservado


O Editor pode ser definido para mostrar o texto de espaço reservado quando ele não está armazenando a
entrada do usuário. Isso é feito definindo a Placeholder propriedade como um string e geralmente é usado
para indicar o tipo de conteúdo que é apropriado para o Editor . Além disso, a cor do texto de espaço reservado
pode ser controlada definindo a PlaceholderColor propriedade como um Color :

<Editor Placeholder="Enter text here" PlaceholderColor="Olive" />

var editor = new Editor { Placeholder = "Enter text here", PlaceholderColor = Color.Olive };

Impedindo a entrada de texto


Os usuários podem ser impedidos de modificar o texto em uma Editor definindo a IsReadOnly propriedade,
que tem um valor padrão de false , para true :

<Editor Text="This is a read-only Editor"


IsReadOnly="true" />
var editor= new Editor { Text = "This is a read-only Editor", IsReadOnly = true });

NOTE
O IsReadonly propriedade não altera a aparência visual de um Editor , ao contrário o IsEnabled propriedade que
também altera a aparência visual do Editor em cinza.

Limitação de tamanho de entrada


O MaxLength propriedade pode ser usada para limitar o tamanho de entrada é permitido para o Editor . Essa
propriedade deve ser definida como um inteiro positivo:

<Editor ... MaxLength="10" />

var editor = new Editor { ... MaxLength = 10 };

Um MaxLength valor de propriedade de 0 indica que nenhuma entrada será permitida e um valor de
int.MaxValue , que é o valor padrão para um Editor , indica que não há nenhum limite efetivo no número de
caracteres que podem ser inseridos.
Um Editor de dimensionamento automático
Uma Editor podem ser feitas para dimensionar automaticamente ao seu conteúdo, definindo o
Editor.AutoSize propriedade TextChanges , que é um valor da EditoAutoSizeOption enumeração. Esta
enumeração tem dois valores:
Disabled indica que o redimensionamento automático está desabilitado e é o valor padrão.
TextChanges indica que o redimensionamento automático está habilitado.

Isso pode ser feito no código da seguinte maneira:

<Editor Text="Enter text here" AutoSize="TextChanges" />

var editor = new Editor { Text = "Enter text here", AutoSize = EditorAutoSizeOption.TextChanges };

Quando o redimensionamento automático está habilitado, a altura do Editor aumentarão quando o usuário
preenche com texto e a altura diminuirá conforme o usuário exclui texto.

NOTE
Uma Editor será tamanho automático não se o HeightRequest propriedade foi definida.

Personalizando o teclado
O teclado que é apresentado quando os usuários interagem com um Editor podem ser definidas
programaticamente por meio dos Keyboard propriedade a uma das seguintes propriedades do Keyboard classe:
Chat – usado para mandar um texto e locais em que o emoji são úteis.
Default – o teclado padrão.
Email – usado ao inserir endereços de email.
Numeric – usado ao inserir números.
Plain – usado ao inserir texto, sem nenhuma KeyboardFlags especificado.
Telephone – usado ao inserir números de telefone.
Text – usado ao inserir texto.
Url – usado para inserir caminhos de arquivo & endereços da web.

Isso pode ser feito no XAML da seguinte maneira:

<Editor Keyboard="Chat" />

O código c# equivalente é:

var editor = new Editor { Keyboard = Keyboard.Chat };

Exemplos de cada teclado podem ser encontrados em nossa receitas repositório.


O Keyboard classe também tem uma Create método de fábrica que pode ser usado para personalizar um
teclado, especificando o comportamento de letras maiusculas, verificação ortográfica e sugestão. KeyboardFlags
valores de enumeração são especificados como argumentos para o método, com um personalizado Keyboard
que está sendo retornado. O KeyboardFlags enumeração contém os seguintes valores:
None – Não há recursos são adicionados ao teclado.
CapitalizeSentence – indica que a primeira letra da primeira palavra de cada frase inserida serão
automaticamente maiusculas.
Spellcheck – indica que essa verificação ortográfica será executada em texto digitado.
Suggestions – indica que o preenchimentos serão oferecidos em texto digitado.
CapitalizeWord – indica que a primeira letra de cada palavra serão automaticamente maiusculas.
CapitalizeCharacter – indica que todos os caracteres serão automaticamente maiusculas.
CapitalizeNone – indica que nenhum capitalização automática ocorrerá.
All – indica que a verificação ortográfica, preenchimentos de palavra e capitalização de frase serão ocorrer
em texto digitado.
O exemplo de código XAML a seguir mostra como personalizar o padrão Keyboard para oferecer
preenchimentos de palavra e tirar proveito de todos os caracteres inseridos:

<Editor>
<Editor.Keyboard>
<Keyboard x:FactoryMethod="Create">
<x:Arguments>
<KeyboardFlags>Suggestions,CapitalizeCharacter</KeyboardFlags>
</x:Arguments>
</Keyboard>
</Editor.Keyboard>
</Editor>

O código c# equivalente é:

var editor = new Editor();


editor.Keyboard = Keyboard.Create(KeyboardFlags.Suggestions | KeyboardFlags.CapitalizeCharacter);

Habilitar e desabilitar a verificação ortográfica


O IsSpellCheckEnabled propriedade controla se verificação ortográfica está habilitada. Por padrão, a propriedade
é definida como true . Enquanto o usuário insere texto, erros de ortografia são indicados.
No entanto, para alguns cenários de entrada de texto, como inserir um nome de usuário, verificação ortográfica
fornece uma experiência negativa e, portanto, devem ser desabilitados definindo a IsSpellCheckEnabled
propriedade false :

<Editor ... IsSpellCheckEnabled="false" />

var editor = new Editor { ... IsSpellCheckEnabled = false };

NOTE
Quando o IsSpellCheckEnabled estiver definida como false e um teclado personalizado não está sendo usado, o
verificador ortográfico nativo será desabilitado. No entanto, se um Keyboard tem sido conjunto que desabilita ortográfica
verificação, como Keyboard.Chat , o IsSpellCheckEnabled propriedade será ignorada. Portanto, a propriedade não
pode ser usada para habilitar a verificação ortográfica para um Keyboard que desabilita explicitamente a ele.

Habilitando e desabilitando a previsão de texto


O IsTextPredictionEnabled propriedade controla se a previsão de texto e automático correção de texto está
habilitada. Por padrão, a propriedade é definida como true . Enquanto o usuário insere texto, previsões do word
são apresentados.
No entanto, para alguns cenários de entrada de texto, como inserir um nome de usuário, a previsão de texto e o
texto automático correção fornece uma experiência negativa e deve ser desabilitada definindo a
IsTextPredictionEnabled propriedade para false :

<Editor ... IsTextPredictionEnabled="false" />

var editor = new Editor { ... IsTextPredictionEnabled = false };

NOTE
Quando o IsTextPredictionEnabled estiver definida como false , e um teclado personalizado não está sendo usado, a
previsão de texto e automático correção de texto está desabilitada. No entanto, se um Keyboard tiver sido definido que
desabilita a previsão de texto, o IsTextPredictionEnabled propriedade será ignorada. Portanto, a propriedade não pode
ser usada para habilitar a previsão de texto para um Keyboard que desabilita explicitamente a ele.

Cores
Editor pode ser definido para usar uma cor de plano de fundo personalizado por meio de BackgroundColor
propriedade. Cuidado especial é necessário para garantir que as cores poderá ser usadas em cada plataforma.
Como cada plataforma tem diferentes padrões de cor do texto, você talvez precise definir uma cor de plano de
fundo personalizado para cada plataforma. Ver trabalhando com ajustes de plataforma para obter mais
informações sobre como otimizar a interface do usuário para cada plataforma.
No C#:
public partial class EditorPage : ContentPage
{
public EditorPage ()
{
InitializeComponent ();
var layout = new StackLayout { Padding = new Thickness(5,10) };
this.Content = layout;
//dark blue on UWP & Android, light blue on iOS
var editor = new Editor { BackgroundColor = Device.RuntimePlatform == Device.iOS ?
Color.FromHex("#A4EAFF") : Color.FromHex("#2c3e50") };
layout.Children.Add(editor);
}
}

No XAML:

<?xml version="1.0" encoding="UTF-8"?>


<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="TextSample.EditorPage"
Title="Editor Demo">
<ContentPage.Content>
<StackLayout Padding="5,10">
<Editor>
<Editor.BackgroundColor>
<OnPlatform x:TypeArguments="x:Color">
<On Platform="iOS" Value="#a4eaff" />
<On Platform="Android, UWP" Value="#2c3e50" />
</OnPlatform>
</Editor.BackgroundColor>
</Editor>
</StackLayout>
</ContentPage.Content>
</ContentPage>
Certifique-se de que as cores de plano de fundo e texto que você escolher podem ser usados em cada plataforma
e não ocultam qualquer texto de espaço reservado.

Interatividade
Editor expõe dois eventos:
TextChanged – gerado quando o texto é alterado no editor. Fornece o texto antes e após a alteração.
Concluída – gerado quando o usuário terminou entrada pressionando a tecla return no teclado.

NOTE
O VisualElement classe da qual Entry herda, também tem Focused e Unfocused eventos.

Concluído
O Completed evento é usado para responder à realização de uma interação com um Editor . Completed é
gerado quando o usuário encerra a entrada com um campo, inserindo a tecla return no teclado. O manipulador
para o evento é um manipulador de eventos genéricos, levando o remetente e EventArgs :

void EditorCompleted (object sender, EventArgs e)


{
var text = ((Editor)sender).Text; // sender is cast to an Editor to enable reading the `Text` property of
the view.
}

O evento concluído pode ser assinado no código e XAML:


No C#:
public partial class EditorPage : ContentPage
{
public EditorPage ()
{
InitializeComponent ();
var layout = new StackLayout { Padding = new Thickness(5,10) };
this.Content = layout;
var editor = new Editor ();
editor.Completed += EditorCompleted;
layout.Children.Add(editor);
}
}

No XAML:

<?xml version="1.0" encoding="UTF-8"?>


<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="TextSample.EditorPage"
Title="Editor Demo">
<ContentPage.Content>
<StackLayout Padding="5,10">
<Editor Completed="EditorCompleted" />
</StackLayout>
</ContentPage.Content>
</Contentpage>

TextChanged
O TextChanged evento é usado para responder a uma alteração no conteúdo de um campo.
TextChanged é gerado sempre que o Text do Editor alterações. O manipulador para o evento usa uma
instância de TextChangedEventArgs . TextChangedEventArgs fornece acesso aos valores novos e antigos do Editor
Text por meio de OldTextValue e NewTextValue propriedades:

void EditorTextChanged (object sender, TextChangedEventArgs e)


{
var oldText = e.OldTextValue;
var newText = e.NewTextValue;
}

O evento concluído pode ser assinado no código e XAML:


No código:

public partial class EditorPage : ContentPage


{
public EditorPage ()
{
InitializeComponent ();
var layout = new StackLayout { Padding = new Thickness(5,10) };
this.Content = layout;
var editor = new Editor ();
editor.TextChanged += EditorTextChanged;
layout.Children.Add(editor);
}
}

No XAML:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="TextSample.EditorPage"
Title="Editor Demo">
<ContentPage.Content>
<StackLayout Padding="5,10">
<Editor TextChanged="EditorTextChanged" />
</StackLayout>
</ContentPage.Content>
</ContentPage>

Links relacionados
Texto (exemplo)
Editor de API
Fontes no xamarin. Forms
12/04/2019 • 11 minutes to read

baixar o exemplo
Este artigo descreve como o xamarin. Forms permite especificar atributos de fonte (incluindo o tamanho e
peso) em controles que exibem texto. Informações de fonte podem ser especificado no código ou especificado
no XAML. Ele tem ' também é possível usar um fonte personalizada, e exibir ícones de fonte.

Definir a fonte no código


Use as três propriedades de fonte de todos os controles que exibem texto:
FontFamily – o string nome da fonte.
FontSize – o tamanho da fonte como um double .
FontAttributes – especificando informações de estilo, como uma cadeia de caracteres itálico e negrito
(usando o FontAttributes enumeração em c#).

Este código mostra como criar um rótulo e especificar o tamanho da fonte e o peso para exibir:

var about = new Label {


FontSize = Device.GetNamedSize (NamedSize.Medium, typeof(Label)),
FontAttributes = FontAttributes.Bold,
Text = "Medium Bold Font"
};

Tamanho da fonte
O FontSize propriedade pode ser definida como um valor duplo, por exemplo:

label.FontSize = 24;

Você também pode usar o NamedSize enumeração que tem quatro opções internas; Xamarin. Forms escolhe o
melhor tamanho de cada plataforma.
Micro
Pequeno
Médio
Grande
O NamedSizeenumeração pode ser usado onde quer que um FontSize pode ser especificado usando o
Device.GetNamedSize método para converter o valor de um double :

label.FontSize = Device.GetNamedSize(NamedSize.Small, typeof(Label));

Atributos de fonte
Estilos de fonte, como negrito e itálico podem ser definidos na FontAttributes propriedade. Atualmente, há
suporte para os seguintes valores:
Nenhum
Negrito
Itálico
O FontAttribute enumeração pode ser usada da seguinte maneira (você pode especificar um único atributo
ou OR -los juntos):

label.FontAttributes = FontAttributes.Bold | FontAttributes.Italic;

Informações de fonte do conjunto por plataforma


Como alternativa, o Device.RuntimePlatform propriedade pode ser usada para definir os nomes de fontes
diferentes em cada plataforma, conforme demonstrado neste código:

label.FontFamily = Device.RuntimePlatform == Device.iOS ? "Lobster-Regular" :


Device.RuntimePlatform == Device.Android ? "Lobster-Regular.ttf#Lobster-Regular" :
"Assets/Fonts/Lobster-Regular.ttf#Lobster",
label.FontSize = Device.RuntimePlatform == Device.iOS ? 24 :
Device.RuntimePlatform == Device.Android ? Device.GetNamedSize(NamedSize.Medium, label) :
Device.GetNamedSize(NamedSize.Large, label);

É uma boa fonte de informações de fonte para iOS iosfonts.com.

Definir a fonte em XAML


Xamarin. Forms controla esse texto de exibição todas têm um FontSize propriedade que pode ser definida em
XAML. A maneira mais simples para definir a fonte em XAML é usar os valores de enumeração de tamanho,
conforme mostrado neste exemplo:

<Label Text="Login" FontSize="Large"/>


<Label Text="Instructions" FontSize="Small"/>

Não há um conversor interno para o FontSize propriedade que permite que todas as configurações de fonte
a ser expressa como um valor de cadeia de caracteres em XAML. Além disso, o FontAttributes propriedade
pode ser usada para especificar atributos de fonte:

<Label Text="Italics are supported" FontAttributes="Italic" />


<Label Text="Biggest NamedSize" FontSize="Large" />
<Label Text="Use size 72" FontSize="72" />

Device.RuntimePlatform também pode ser usado em XAML para renderizar uma fonte diferente em cada
plataforma. O exemplo a seguir usa uma face de fonte personalizada no iOS (MarkerFelt-finos) e especifica o
tamanho/atributos somente em outras plataformas:

<Label Text="Hello Forms with XAML">


<Label.FontFamily>
<OnPlatform x:TypeArguments="x:String">
<On Platform="iOS" Value="MarkerFelt-Thin" />
<On Platform="Android" Value="Lobster-Regular.ttf#Lobster-Regular" />
<On Platform="UWP" Value="Assets/Fonts/Lobster-Regular.ttf#Lobster" />
</OnPlatform>
</Label.FontFamily>
</Label>

Ao especificar uma face de fonte personalizado, é sempre uma boa ideia usar OnPlatform , que é difícil
encontrar uma fonte que está disponível em todas as plataformas.
Usar uma fonte personalizada
Usando uma fonte que não sejam de tipos internos requer alguma codificação específicos da plataforma. Esta
captura de tela mostra a fonte personalizada Lobster partir fontes de código-fonte aberto do Google
renderizado usando o xamarin. Forms.

As etapas necessárias para cada plataforma são descritas abaixo. Ao incluir arquivos de fonte personalizado
com um aplicativo, certifique-se de verificar que permite a licença da fonte para distribuição.
iOS
É possível exibir uma fonte personalizada primeiro garantir que ele é carregado e, em seguida, fazendo
referência a ele por nome usando o xamarin. Forms Font métodos. Siga as instruções em esta postagem de
blog:
1. Adicione o arquivo de fonte com ação de compilação: BundleResource, e
2. Atualização do Info. plist arquivo (fontes fornecidas pelo aplicativo, ou UIAppFonts , key), em seguida,
3. Fazer referência a ele por nome sempre que você definir uma fonte no xamarin. Forms!

new Label
{
Text = "Hello, Forms!",
FontFamily = Device.RuntimePlatform == Device.iOS ? "Lobster-Regular" : null // set only for iOS
}

Android
Xamarin. Forms para Android pode fazer referência a uma fonte personalizada que foi adicionada ao projeto
seguindo um padrão de nomenclatura específico. Primeiro, adicione o arquivo de fonte para o ativos pasta no
projeto de aplicativo e defina ação de compilação: AndroidAsset. Em seguida, use o caminho completo e nome
da fonte separados por um hash (#) como o nome da fonte no xamarin. Forms, como o trecho de código a
seguir demonstra:

new Label
{
Text = "Hello, Forms!",
FontFamily = Device.RuntimePlatform == Device.Android ? "Lobster-Regular.ttf#Lobster-Regular" : null //
set only for Android
}

Windows
Xamarin. Forms para plataformas do Windows pode fazer referência a uma fonte personalizada que foi
adicionada ao projeto seguindo um padrão de nomenclatura específico. Primeiro, adicione o arquivo de fonte
para o /Assets/fontes/ pasta no projeto de aplicativo e defina as compilar: conteúdo da ação. Em seguida, use
a fonte e o caminho do nome de arquivo completo, seguido por um hash (#) e o nome da fonte, como o trecho
de código a seguir demonstra:
new Label
{
Text = "Hello, Forms!",
FontFamily = Device.RuntimePlatform == Device.UWP ? "Assets/Fonts/Lobster-Regular.ttf#Lobster" : null
// set only for UWP apps
}

NOTE
Observe que o nome do arquivo de fonte e o nome da fonte podem ser diferentes. Para descobrir o nome da fonte no
Windows, clique no arquivo. ttf e selecione visualização. O nome da fonte pode ser determinado, em seguida, na janela
de visualização.

Agora o código comum para o aplicativo está concluído. O código de discagem do telefone específico da
plataforma agora será implementado como um DependencyService.
XAML
Você também pode usar Device.RuntimePlatform no XAML para renderizar uma fonte personalizada:

<Label Text="Hello Forms with XAML">


<Label.FontFamily>
<OnPlatform x:TypeArguments="x:String">
<On Platform="iOS" Value="Lobster-Regular" />
<On Platform="Android" Value="Lobster-Regular.ttf#Lobster-Regular" />
<On Platform="UWP" Value="Assets/Fonts/Lobster-Regular.ttf#Lobster" />
</OnPlatform>
</Label.FontFamily>
</Label>

Exibir ícones de fonte


Ícones de fonte podem ser exibidos por aplicativos xamarin. Forms, especificando os dados do ícone de fonte
em um FontImageSource objeto. Essa classe, que deriva de ImageSource de classe, tem as seguintes
propriedades:
Glyph – o valor do caractere unicode do ícone de fonte, especificado como um string .
Size – um double valor que indica o tamanho, em unidades independentes de dispositivo, do ícone de
fonte renderizada. O valor padrão é 30.
FontFamily – um string que representa a família de fontes ao qual pertence o ícone de fonte.
Color – um recurso opcional Color valor a ser usado ao exibir o ícone de fonte.

Esses dados são usados para criar um arquivo PNG, que pode ser exibido por qualquer exibição que pode
exibir um ImageSource . Essa abordagem permite que os ícones de fonte, como emojis, a ser exibido por vários
modos de exibição, em vez de limitar a exibição do ícone de fonte para um único texto apresentando o modo
de exibição, como um Label .

IMPORTANT
Ícones de fonte no momento somente podem ser especificados por sua representação de caractere unicode.

O exemplo XAML a seguir tem um ícone de fonte única que está sendo exibido por um Image exibição:
<Image BackgroundColor="#D1D1D1">
<Image.Source>
<FontImageSource Glyph="&#xf30c;"
FontFamily="{OnPlatform iOS=Ionicons, Android=ionicons.ttf#}"
Size="44" />
</Image.Source>
</Image>

Esse código exibe um ícone do XBox, da família de fonte Ionicons, em um Image exibição. Observe que,
enquanto o unicode, para esse ícone é de caractere \uf30c , ele tem que ser substituídos no XAML e portanto
se torna &#xf30c; . O código c# equivalente é:

Image image = new Image { BackgroundColor = Color.FromHex("#D1D1D1") };


image.Source = new FontImageSource
{
Glyph = "\uf30c",
FontFamily = Device.RuntimePlatform == Device.iOS ? "Ionicons" : "ionicons.ttf#",
Size = 44
};

Capturas de tela as seguir, do Layouts associável de exemplo, mostrar vários ícones de fonte que está sendo
exibidos por um layout associável:

Links relacionados
FontsSample
Texto (exemplo)
Layouts associáveis (amostra)
Layouts Associáveis
Estilos de texto do xamarin. Forms
12/04/2019 • 4 minutes to read

baixar o exemplo
Estilo do texto no xamarin. Forms
Estilos podem ser usados para ajustar a aparência de rótulos, entradas e editores. Estilos podem ser definidos
uma vez e usados por muitas exibições, mas um estilo só pode ser usado com modos de exibição de um tipo.
Estilos podem ser fornecidos um Key e aplicadas seletivamente usando um controle específico Style
propriedade.

Estilos internos
Xamarin. Forms inclui vários internos estilos para cenários comuns:
BodyStyle
CaptionStyle
ListItemDetailTextStyle
ListItemTextStyle
SubtitleStyle
TitleStyle

Para aplicar um dos estilos internos, use o DynamicResource extensão de marcação para especificar o estilo:

<Label Text="I'm a Title" Style="{DynamicResource TitleStyle}"/>

No c#, os estilos internos são selecionados de Device.Styles :

label.Style = Device.Styles.TitleStyle;
Estilos personalizados
Estilos consistem em setters e setters consistem em propriedades e os valores de propriedades serão definidos
como.
No c#, um estilo personalizado para um rótulo com texto vermelho de tamanho 30 seria definido da seguinte
maneira:

var LabelStyle = new Style (typeof(Label)) {


Setters = {
new Setter {Property = Label.TextColorProperty, Value = Color.Red},
new Setter {Property = Label.FontSizeProperty, Value = 30}
}
};

var label = new Label { Text = "Check out my style.", Style = LabelStyle };

No XAML:
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="LabelStyle" TargetType="Label">
<Setter Property="TextColor" Value="Red"/>
<Setter Property="FontSize" Value="30"/>
</Style>
</ResourceDictionary>
</ContentPage.Resources>

<ContentPage.Content>
<StackLayout>
<Label Text="Check out my style." Style="{StaticResource LabelStyle}" />
</StackLayout>
</ContentPage.Content>

Observe que os recursos (incluindo todos os estilos) são definidos dentro ContentPage.Resources , que é um irmão
de mais familiar ContentPage.Content elemento.

Aplicando estilos
Quando um estilo tiver sido criado, ele pode ser aplicado a qualquer correspondência de exibição seu TargetType .
No XAML, estilos personalizados são aplicados aos modos de exibição, fornecendo seus Style propriedade com
um StaticResource referenciando o estilo desejado de extensão de marcação:

<Label Text="Check out my style." Style="{StaticResource LabelStyle}" />

No c#, estilos podem ser aplicados diretamente a um modo de exibição ou adicionados ao e recuperados de uma
página ResourceDictionary . Para adicionar diretamente:
var label = new Label { Text = "Check out my style.", Style = LabelStyle };

Para adicionar e recuperar a partir da página ResourceDictionary :

this.Resources.Add ("LabelStyle", LabelStyle);


label.Style = (Style)Resources["LabelStyle"];

Estilos internos são aplicados de forma diferente, pois eles precisam responder às configurações de acessibilidade.
Para aplicar estilos internos em XAML, o DynamicResource extensão de marcação é usada:

<Label Text="I'm a Title" Style="{DynamicResource TitleStyle}"/>

No c#, os estilos internos são selecionados de Device.Styles :

label.Style = Device.Styles.TitleStyle;

Acessibilidade
Os estilos internos existem para tornar mais fácil respeitar as preferências de acessibilidade. Ao usar qualquer um
dos estilos internos, tamanhos de fonte aumentará automaticamente se um usuário define suas preferências de
acessibilidade adequadamente.
Considere o exemplo a seguir da mesma página de modos de exibição estilizada com os estilos internos com as
configurações de acessibilidade habilitados e desabilitados:
Desabilitado:
Habilitado:

Para garantir a acessibilidade, certifique-se de que os estilos internos são usados como base para todos os estilos
relacionada ao texto dentro de seu aplicativo e que você está usando estilos de forma consistente. Ver estilos para
obter mais detalhes sobre a extensão e trabalhar com estilos, em geral.

Links relacionados
Criação de aplicativos móveis com xamarin. Forms, capítulo 12
Estilos
Texto (exemplo)
Estilo
Temas do xamarin. Forms
12/04/2019 • 3 minutes to read

baixar o exemplo

Temas do xamarin. Forms foram lançados no Evolve 2016 e estão disponíveis como uma visualização para que
os clientes experimentar e fornecer comentários.
Um tema é adicionado a um aplicativo xamarin. Forms, incluindo o Xamarin.Forms.Theme.Base de pacote
do Nuget, além de um pacote adicional que define um tema específico (por exemplo.
Xamarin.Forms.Theme.Light) ou outro um tema local pode ser definido para o aplicativo.
Consulte a tema claro e tema escuro páginas para obter instruções sobre como adicioná-los a um aplicativo ou
fazer check-out a tema personalizado de exemplo.
IMPORTANTE: você também deve seguir as etapas a serem carregar assemblies de tema (abaixo)
adicionando um código clichê para o iOS AppDelegate e Android MainActivity . Isso será melhorado em uma
versão de visualização futura.

Aparência do controle
O Light e escuro ambos os temas definem uma aparência visual específica para os controles padrão. Depois
que você adiciona um tema para o dicionário de recursos do aplicativo, a aparência dos controles padrão será
alterado.
A marcação XAML a seguir mostra alguns controles comuns:

<StackLayout Padding="40">
<Label Text="Regular label" />
<Entry Placeholder="type here" />
<Button Text="OK" />
<BoxView Color="Yellow" />
<Switch />
</StackLayout>

Essas capturas de tela mostram esses controles com:


Nenhum tema aplicado
Tema claro (apenas diferenças sutis que devem não ter nenhum tema)
Tema escuro
StyleClass
O StyleClass propriedade permite que a aparência do modo de exibição a ser alterado de acordo com uma
definição fornecida por um tema.
O Light e escuro ambos os temas definem três aparências diferentes para um BoxView : HorizontalRule ,
Circle , e Rounded . Essa marcação mostra três diferentes BoxView s com classes diferentes de estilo aplicadas:

<StackLayout Padding="40">
<BoxView StyleClass="HorizontalRule" />
<BoxView StyleClass="Circle" />
<BoxView StyleClass="Rounded" />
</StackLayout>

Isso renderiza com claro e escuro da seguinte maneira:

Classes internas
Além de definir o estilo automaticamente comum controla a luz e temas escuros atualmente suportam as
seguintes classes que podem ser aplicadas, definindo o StyleClass nesses controles:
BoxView
HorizontalRule
Círculo
Arredondado
Image
Círculo
Arredondado
Miniatura
Button
Padrão
Primária
Êxito
Info
Aviso
Perigo
Link
Pequeno
Grande
Rótulo
Cabeçalho
Subcabeçalho
Corpo
Link
Inverso

Solução de problemas
Não foi possível carregar arquivo ou assembly 'Xamarin.Forms.Theme.Light' ou uma de suas dependências
Na versão de visualização, temas podem não ser capazes de carregar no tempo de execução. Adicione o código
mostrado abaixo nos projetos relevantes para corrigir esse erro.
iOS
No AppDelegate.cs adicione as seguintes linhas depois de LoadApplication

var x = typeof(Xamarin.Forms.Themes.DarkThemeResources);
x = typeof(Xamarin.Forms.Themes.LightThemeResources);
x = typeof(Xamarin.Forms.Themes.iOS.UnderlineEffect);

Android
No MainActivity.cs adicione as seguintes linhas depois de LoadApplication

var x = typeof(Xamarin.Forms.Themes.DarkThemeResources);
x = typeof(Xamarin.Forms.Themes.LightThemeResources);
x = typeof(Xamarin.Forms.Themes.Android.UnderlineEffect);

Links relacionados
Exemplo de ThemesDemo
Tema claro do xamarin. Forms
12/04/2019 • 2 minutes to read

NOTE
Temas exigem a versão de visualização do xamarin. Forms 2.3. Verifique as dicas de solução de problemas se ocorrerem
erros.

Para usar o tema de luz:

1. Adicionar pacotes Nuget


Xamarin.Forms.Theme.Base
Xamarin.Forms.Theme.Light

2. Adicionar ao dicionário de recursos


No App. XAML arquivo de adicionar um novo personalizado xmlns do tema e, em seguida, verifique se os
recursos do tema são mesclados com o dicionário de recursos do aplicativo. Um exemplo de arquivo XAML é
mostrado abaixo:

<?xml version="1.0" encoding="utf-8"?>


<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="EvolveApp.App"
xmlns:light="clr-namespace:Xamarin.Forms.Themes;assembly=Xamarin.Forms.Theme.Light">
<Application.Resources>
<ResourceDictionary MergedWith="light:LightThemeResources" />
</Application.Resources>
</Application>

3. Classes de tema de carga


Siga esse etapa de solução de problemas e adicione o código necessário no iOS e projetos de aplicativo Android.

4. Usar StyleClass
Aqui está um exemplo de botões e rótulos no tema claro, juntamente com a marcação que produz-los.
<StackLayout Padding="20">
<Button Text="Button Default" />
<Button Text="Button Class Default" StyleClass="Default" />
<Button Text="Button Class Primary" StyleClass="Primary" />
<Button Text="Button Class Success" StyleClass="Success" />
<Button Text="Button Class Info" StyleClass="Info" />
<Button Text="Button Class Warning" StyleClass="Warning" />
<Button Text="Button Class Danger" StyleClass="Danger" />
<Button Text="Button Class Link" StyleClass="Link" />
<Button Text="Button Class Default Small" StyleClass="Small" />
<Button Text="Button Class Default Large" StyleClass="Large" />
</StackLayout>

O uma lista completa de classes internas mostra quais estilos disponíveis para alguns controles comuns.
Tema escuro do xamarin. Forms
12/04/2019 • 2 minutes to read

NOTE
Temas exigem a versão de visualização do xamarin. Forms 2.3. Verifique as dicas de solução de problemas se ocorrerem
erros.

Para usar o tema escuro:

1. Adicionar pacotes Nuget


Xamarin.Forms.Theme.Base
Xamarin.Forms.Theme.Dark

2. Adicionar ao dicionário de recursos


No App. XAML arquivo de adicionar um novo personalizado xmlns do tema e, em seguida, verifique se os
recursos do tema são mesclados com o dicionário de recursos do aplicativo. Um exemplo de arquivo XAML é
mostrado abaixo:

<?xml version="1.0" encoding="utf-8"?>


<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="EvolveApp.App"
xmlns:dark="clr-namespace:Xamarin.Forms.Themes;assembly=Xamarin.Forms.Theme.Dark">
<Application.Resources>
<ResourceDictionary MergedWith="dark:DarkThemeResources" />
</Application.Resources>
</Application>

3. Classes de tema de carga


Siga esse etapa de solução de problemas e adicione o código necessário no iOS e projetos de aplicativo Android.

4. Usar StyleClass
Aqui está um exemplo de botões e rótulos no tema escuro, juntamente com a marcação que produz-los.
<StackLayout Padding="20">
<Button Text="Button Default" />
<Button Text="Button Class Default" StyleClass="Default" />
<Button Text="Button Class Primary" StyleClass="Primary" />
<Button Text="Button Class Success" StyleClass="Success" />
<Button Text="Button Class Info" StyleClass="Info" />
<Button Text="Button Class Warning" StyleClass="Warning" />
<Button Text="Button Class Danger" StyleClass="Danger" />
<Button Text="Button Class Link" StyleClass="Link" />

<Button Text="Button Class Default Small" StyleClass="Small" />


<Button Text="Button Class Default Large" StyleClass="Large" />
</StackLayout>

O uma lista completa de classes internas mostra quais estilos disponíveis para alguns controles comuns.
Criando um tema personalizado xamarin. Forms
12/04/2019 • 4 minutes to read

Além de adicionar um tema de um pacote Nuget (como o Light e escuro temas), você pode criar seus próprios
recursos temas de dicionário que podem ser referenciados em seu aplicativo.

Exemplo
Os três BoxView s mostrada na página de temas são denominados de acordo com as três classes definidas nos
dois temas para download.
Para entender como eles funcionam, a marcação a seguir cria um estilo equivalente que você poderá adicionar
diretamente para seu App. XAML.
Observe a Class atributo Style (em oposição à x:Key atributo disponível em versões anteriores do xamarin.
Forms).

<ResourceDictionary>
<!-- DEFINE ANY CONSTANTS -->
<Color x:Key="SeparatorLineColor">#CCCCCC</Color>
<Color x:Key="iOSDefaultTintColor">#007aff</Color>
<Color x:Key="AndroidDefaultAccentColorColor">#1FAECE</Color>
<OnPlatform x:TypeArguments="Color" x:Key="AccentColor">
<On Platform="iOS" Value="{StaticResource iOSDefaultTintColor}" />
<On Platform="Android" Value="{StaticResource AndroidDefaultAccentColorColor}" />
</OnPlatform>
<!-- BOXVIEW CLASSES -->
<Style TargetType="BoxView" Class="HorizontalRule">
<Setter Property="BackgroundColor" Value="{ StaticResource SeparatorLineColor }" />
<Setter Property="HeightRequest" Value="1" />
</Style>

<Style TargetType="BoxView" Class="Circle">


<Setter Property="BackgroundColor" Value="{ StaticResource AccentColor }" />
<Setter Property="WidthRequest" Value="34"/>
<Setter Property="HeightRequest" Value="34"/>
<Setter Property="HorizontalOptions" Value="Start" />

<Setter Property="local:ThemeEffects.Circle" Value="True" />


</Style>

<Style TargetType="BoxView" Class="Rounded">


<Setter Property="BackgroundColor" Value="{ StaticResource AccentColor }" />
<Setter Property="HorizontalOptions" Value="Start" />
<Setter Property="BackgroundColor" Value="{ StaticResource AccentColor }" />

<Setter Property="local:ThemeEffects.CornerRadius" Value="4" />


</Style>
</ResourceDictionary>

Você observará que o Rounded classe se refere a um efeito personalizado CornerRadius . O código para esse efeito
é fornecido abaixo - referenciá-lo corretamente um personalizado xmlns deve ser adicionado para o App.
XAMLdo elemento raiz:

xmlns:local="clr-namespace:ThemesDemo;assembly=ThemesDemo"

Código c# no projeto compartilhado ou projeto de biblioteca .NET Standard


O código para a criação de um canto de round BoxView usa efeitos. O raio do canto é aplicado usando um
BindableProperty e é implementado pela aplicação de uma efeito. O efeito requer código específico da plataforma
na iOS e Android projetos (mostrados abaixo).

namespace ThemesDemo
{
public static class ThemeEffects
{
public static readonly BindableProperty CornerRadiusProperty =
BindableProperty.CreateAttached("CornerRadius", typeof(double), typeof(ThemeEffects), 0.0,
propertyChanged: OnChanged<CornerRadiusEffect, double>);
private static void OnChanged<TEffect, TProp>(BindableObject bindable, object oldValue, object newValue)
where TEffect : Effect, new()
{
if (!(bindable is View view))
{
return;
}

if (EqualityComparer<TProp>.Equals(newValue, default(TProp)))
{
var toRemove = view.Effects.FirstOrDefault(e => e is TEffect);
if (toRemove != null)
{
view.Effects.Remove(toRemove);
}
}
else
{
view.Effects.Add(new TEffect());
}

}
public static void SetCornerRadius(BindableObject view, double radius)
{
view.SetValue(CornerRadiusProperty, radius);
}

public static double GetCornerRadius(BindableObject view)


{
return (double)view.GetValue(CornerRadiusProperty);
}

private class CornerRadiusEffect : RoutingEffect


{
public CornerRadiusEffect()
: base("Xamarin.CornerRadiusEffect")
{
}
}
}
}

Código c# no projeto do iOS


using System;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using CoreGraphics;
using Foundation;
using XFThemes;

namespace ThemesDemo.iOS
{
public class CornerRadiusEffect : PlatformEffect
{
private nfloat _originalRadius;

protected override void OnAttached()


{
if (Container != null)
{
_originalRadius = Container.Layer.CornerRadius;
Container.ClipsToBounds = true;

UpdateCorner();
}
}

protected override void OnDetached()


{
if (Container != null)
{
Container.Layer.CornerRadius = _originalRadius;
Container.ClipsToBounds = false;
}
}

protected override void OnElementPropertyChanged(System.ComponentModel.PropertyChangedEventArgs args)


{
base.OnElementPropertyChanged(args);

if (args.PropertyName == ThemeEffects.CornerRadiusProperty.PropertyName)
{
UpdateCorner();
}
}

private void UpdateCorner()


{
Container.Layer.CornerRadius = (nfloat)ThemeEffects.GetCornerRadius(Element);
}
}
}

Código c# no projeto do Android


using System;
using Xamarin.Forms.Platform;
using Xamarin.Forms.Platform.Android;
using Android.Views;
using Android.Graphics;

namespace ThemesDemo.Droid
{
public class CornerRadiusEffect : BaseEffect
{
private ViewOutlineProvider _originalProvider;

protected override bool CanBeApplied()


{
return Container != null && Android.OS.Build.VERSION.SdkInt >=
Android.OS.BuildVersionCodes.Lollipop;
}

protected override void OnAttachedInternal()


{
_originalProvider = Container.OutlineProvider;
Container.OutlineProvider = new CornerRadiusOutlineProvider(Element);
Container.ClipToOutline = true;
}

protected override void OnDetachedInternal()


{
Container.OutlineProvider = _originalProvider;
Container.ClipToOutline = false;
}

protected override void OnElementPropertyChanged(System.ComponentModel.PropertyChangedEventArgs args)


{
base.OnElementPropertyChanged(args);

if (!Attached)
{
return;
}

if (args.PropertyName == ThemeEffects.CornerRadiusProperty.PropertyName)
{
Container.Invalidate();
}
}

private class CornerRadiusOutlineProvider : ViewOutlineProvider


{
private Xamarin.Forms.Element _element;

public CornerRadiusOutlineProvider(Xamarin.Forms.Element element)


{
_element = element;
}

public override void GetOutline(Android.Views.View view, Outline outline)


{
var pixels =
(float)ThemeEffects.GetCornerRadius(_element) *
view.Resources.DisplayMetrics.Density;

outline.SetRoundRect(new Rect(0, 0, view.Width, view.Height), (int)pixels);


}
}
}
}
Resumo
Um tema personalizado pode ser criado com a definição de estilos para cada controle que exige a aparência
personalizada. Vários estilos para um controle devem ser diferenciados por diferentes Class atributos no
dicionário de recursos e, em seguida, aplicada definindo o StyleClass atributo no controle.
Também pode utilizar um estilo efeitos para personalizar ainda mais a aparência de um controle.
Estilos implícitos (sem qualquer um uma x:Key ou Style atributo) continuam a ser aplicado a todos os controles
que correspondam a TargetType .
Xamarin. Forms TimePicker
12/04/2019 • 9 minutes to read

baixar o exemplo
Uma exibição do xamarin. Forms que permite que o usuário selecione uma hora.
O xamarin. Forms TimePicker invoca o controle de seletor de tempo da plataforma e permite que o usuário
selecione uma hora. TimePicker Define as propriedades a seguir:
Time do tipo TimeSpan , o tempo selecionado, que assume como padrão um TimeSpan igual a 0. O TimeSpan
tipo indica uma duração de tempo desde a meia-noite.
Format do tipo string , um padrão ou personalizado .NET formatação de cadeia de caracteres, cujo padrão é
"t", o padrão de hora abreviada.
TextColor do tipo Color , a cor usada para exibir o tempo selecionado, cujo padrão é Color.Default .
FontAttributes do tipo FontAttributes , cujo padrão é FontAtributes.None .
FontFamily do tipo string , cujo padrão é null .
FontSize do tipo double , cujo padrão é de -1,0.

Todas essas propriedades têm o respaldo BindableProperty objetos, o que significa que eles podem ser
estilizados e as propriedades podem ser alvos de vinculações de dados. O Time propriedade tem um modo de
associação padrão de BindingMode.TwoWay , que significa que ele pode ser um destino de associação de dados em
um aplicativo que usa o Model-View -ViewModel (MVVM ) arquitetura.
O TimePicker não inclui um evento para indicar um novo selecionado Time valor. Se você precisar ser notificado
sobre isso, você pode adicionar um manipulador para o PropertyChanged eventos.

Inicializando a propriedade de tempo


No código, você pode inicializar o Time propriedade para um valor do tipo TimeSpan :

TimePicker timePicker = new TimePicker


{
Time = new TimeSpan(4, 15, 26) // Time set to "04:15:26"
};

Quando o Time propriedade é especificada no XAML, o valor é convertido em um TimeSpan e validadas para
garantir que o número de milissegundos é maior que ou igual a 0 e o número de horas é menor que 24. Os
componentes de tempo devem ser separados por dois-pontos:

<TimePicker Time="4:15:26" />

Se o BindingContext propriedade do TimePicker é definido como uma instância de um ViewModel que contém
uma propriedade de tipo TimeSpan chamado SelectedTime (por exemplo), você pode criar uma instância o
TimePicker semelhante a esta:

<TimePicker Time="{Binding SelectedTime}" />

Neste exemplo, o Time propriedade é inicializada para o SelectedTime propriedade no ViewModel. Porque o
Time propriedade tem um modo de associação da TwoWay , qualquer novo tempo em que o usuário selecionar
será propagado automaticamente para o ViewModel.
Se o TimePicker não contém uma associação em seu Time propriedade, um aplicativo deve anexar um
manipulador para o PropertyChanged eventos para ser informado quando o usuário seleciona um novo tempo.
Para obter informações sobre como definir propriedades de fonte, consulte fontes.

TimePicker e layout
É possível usar uma opção de layout horizontal irrestrito, como Center , Start , ou End com TimePicker :

<TimePicker ···
HorizontalOptions="Center"
··· />

No entanto, isso não é recomendado. Dependendo da configuração do Format propriedade, selecionada vezes
podem exigir que as larguras de exibição diferentes. Por exemplo, a cadeia de caracteres de formato "T" faz com
que o TimePicker exibir para exibir os tempos de em um formato longo e ": 15:26 4AM" requer uma maior
largura de exibição do formato de hora abreviada ("t") da ": 15 4AM". Dependendo da plataforma, essa diferença
pode causar a TimePicker exibição para alterar a largura de layout, ou para a exibição a ser truncado.

TIP
É melhor usar o padrão HorizontalOptions configuração do Fill com TimePicker e não deve usar uma largura de
Auto ao colocar TimePicker em um Grid célula.

TimePicker em um aplicativo
O SetTimer exemplo inclui TimePicker , Entry , e Switch modos de exibição em sua página. O TimePicker
pode ser usado para selecionar uma hora, e quando de tempo que ocorre uma caixa de diálogo de alerta é exibida
que lembra o usuário do texto na Entry , fornecido o Switch é ativado. Aqui está o arquivo XAML:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:SetTimer"
x:Class="SetTimer.MainPage">
<StackLayout>
...
<Entry x:Name="_entry"
Placeholder="Enter event to be reminded of" />
<Label Text="Select the time below to be reminded at." />
<TimePicker x:Name="_timePicker"
Time="11:00:00"
Format="T"
PropertyChanged="OnTimePickerPropertyChanged" />
<StackLayout Orientation="Horizontal">
<Label Text="Enable timer:" />
<Switch x:Name="_switch"
HorizontalOptions="EndAndExpand"
Toggled="OnSwitchToggled" />
</StackLayout>
</StackLayout>
</ContentPage>

O permite que você insira o texto de lembrete que será exibido quando ocorre o tempo selecionado. O
Entry
TimePicker é atribuído um Format propriedade de "T" para o formato de hora longa. Ele tem um manipulador
de eventos anexado à PropertyChanged eventos e o Switch tem um manipulador anexado ao seu Toggled
eventos. Esses manipuladores de eventos estão no arquivo code-behind e chamada o SetTriggerTime método:

public partial class MainPage : ContentPage


{
DateTime _triggerTime;

public MainPage()
{
InitializeComponent();

Device.StartTimer(TimeSpan.FromSeconds(1), OnTimerTick);
}

bool OnTimerTick()
{
if (_switch.IsToggled && DateTime.Now >= _triggerTime)
{
_switch.IsToggled = false;
DisplayAlert("Timer Alert", "The '" + _entry.Text + "' timer has elapsed", "OK");
}
return true;
}

void OnTimePickerPropertyChanged(object sender, PropertyChangedEventArgs args)


{
if (args.PropertyName == "Time")
{
SetTriggerTime();
}
}

void OnSwitchToggled(object sender, ToggledEventArgs args)


{
SetTriggerTime();
}

void SetTriggerTime()
{
if (_switch.IsToggled)
{
_triggerTime = DateTime.Today + _timePicker.Time;
if (_triggerTime < DateTime.Now)
{
_triggerTime += TimeSpan.FromDays(1);
}
}
}
}

O SetTriggerTime método calcula um tempo de timer com base no DateTime.Today o valor da propriedade e o
TimeSpan valor retornado da TimePicker . Isso é necessário porque o DateTime.Today propriedade retorna um
DateTime que indica a data atual, mas com um tempo de meia-noite. Se já tiver passado tempo o temporizador
hoje em dia, em seguida, supõe-se para ser amanhã.
Os tiques do temporizador cada segundo, executando o OnTimerTick método que verifica se o Switch é sobre
como e se a hora atual é maior que ou igual ao tempo de temporizador. Quando ocorre o tempo de timer, o
DisplayAlert método apresenta uma caixa de diálogo de alerta para o usuário como um lembrete.

Quando o exemplo é executado pela primeira vez, o TimePicker exibição é inicializada como às 11h. Tocar o
TimePicker invoca o seletor de tempo de plataforma. As plataformas de implementam o seletor de hora em duas
maneiras diferentes, mas cada abordagem é familiar aos usuários da plataforma:
TIP
No Android, o TimePicker caixa de diálogo pode ser personalizada substituindo o CreateTimePickerDialog método em
um renderizador personalizado. Isso permite, por exemplo, botões adicionais a serem adicionados à caixa de diálogo.

Depois de selecionar uma hora, o tempo selecionado é exibido na TimePicker :

Desde que o Switch seja alternado para a posição ligada, o aplicativo exibe uma caixa de diálogo alerta lembrar o
usuário do texto no Entry quando ocorre o tempo selecionado:
Assim que a caixa de diálogo de alerta é exibida, o Switch seja alternado para a posição off.

Links relacionados
Exemplo de SetTimer
TimePicker API
Visual do xamarin. Forms
12/04/2019 • 2 minutes to read

Material do xamarin. Forms Visual


Material do xamarin. Forms Visual pode ser usado para criar aplicativos xamarin. Forms que se parecem idênticos
ou praticamente idênticas, no iOS e Android.

Criar um renderizador Visual do xamarin. Forms


Visual do xamarin. Forms permite que os renderizadores ser aplicadas seletivamente ao VisualElement objetos,
sem ter de exibições do xamarin. Forms subclasse.
Material do xamarin. Forms Visual
12/04/2019 • 8 minutes to read

Baixar o exemplo
Design de material é um sistema de design "teimosa" criado pelo Google, que determina o tamanho, cor,
espaçamento e outros aspectos de como layouts e modos de exibição devem parecer e se comportam.
Material do xamarin. Forms Visual pode ser usado para aplicar regras de Design de Material para aplicativos
xamarin. Forms, criação de aplicativos que se parecem idênticos ou praticamente idênticas, no iOS e Android.
Quando o Visual de Material é habilitado, modos de exibição com suporte adotam a mesmo design
multiplataforma, criando uma aparência unificada. Isso é obtido com processadores de material, que se aplicam as
regras de Design de Material.
O processo para habilitar o xamarin. Forms Material Visual em seu aplicativo é:
1. Adicione a Xamarin.Forms.Visual.Material pacote do NuGet para seus projetos de plataforma Android e iOS.
Este pacote NuGet entrega otimizados renderizadores de Design de Material em iOS e Android. No iOS, o
pacote fornece a dependência transitiva Xamarin.iOS.MaterialComponents, que é um C# associação do Google
componentes do Material para iOS. No Android, o pacote fornece destinos de compilação para garantir que
seu TargetFramework está configurado corretamente.
2. Inicialize os renderizadores de material em cada projeto de plataforma. Para obter mais informações, consulte
inicializar renderizadores materiais.
3. Consumir os renderizadores de material, definindo o Visual propriedade Material em todas as páginas que
devem adotar as regras de Design de Material. Para obter mais informações, consulte consumir renderizadores
materiais.
4. [opcional] Personalize os renderizadores de material. Para obter mais informações, consulte personalizar
renderizadores materiais.

IMPORTANT
No Android, os renderizadores de material exigem a versão mínima do 5.0 (API 21) ou superior e um TargetFramework da
versão 9.0 (28 de API). Além disso, seu projeto de plataforma requer bibliotecas de suporte do Android 28.0.0 ou superior, e
seu tema precisa herdar de um tema de Material componentes ou continuar herdar de um tema AppCompat. Para obter
mais informações, consulte Introdução aos componentes de Material para Android.

Renderizadores de material atualmente estão incluídos na Xamarin.Forms.Visual.Material pacote do NuGet para


as exibições a seguir:
Button
Entry
Frame
ProgressBar
DatePicker
TimePicker
Picker
ActivityIndicator
Editor
Slider
Stepper

Funcionalmente, os renderizadores de material não são diferentes para os renderizadores de padrão.

Inicializar os renderizadores de material


Depois de instalar o Xamarin.Forms.Visual.Material de pacote do NuGet, o material renderizadores devem ser
inicializados em cada projeto de plataforma.
IOS, isso deve ocorrer AppDelegate.cs invocando o FormsMaterial.Init método após o
Xamarin.Forms.Forms.Init método:

global::Xamarin.Forms.Forms.Init();
FormsMaterial.Init();

No Android, isso deve ocorrer no MainActivity.cs invocando o FormsMaterial.Init método após o


Xamarin.Forms.Forms.Init método:

global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
FormsMaterial.Init(this, savedInstanceState);

Consumir os renderizadores de material


Aplicativos podem optarem por usar os renderizadores de material, definindo o VisualElement.Visual
propriedade em uma página, layout ou modo de exibição, para Material :

<ContentPage Visual="Material"
...>
...
</ContentPage>

O código C# equivalente é:

ContentPage contentPage = new ContentPage();


contentPage.Visual = VisualMarker.Material;

O Visual propriedade pode ser definida como qualquer tipo que implemente IVisual , com o VisualMarker
classe que fornece o seguinte IVisual propriedades:
Default – indica que o modo de exibição deve ser renderizados usando o renderizador padrão.
MatchParent – indica que o modo de exibição deve usar o renderizador do mesmo como pai direto.
Material – indica que o modo de exibição deve ser renderizados usando um renderizador de material.

IMPORTANT
O Visual propriedade está definida no VisualElement classe, com modos de exibição herdando a Visual valor da
propriedade de seus pais. Portanto, definir a Visual propriedade em um ContentPage garante que todas as exibições
com suporte na página usarão esse elemento Visual. Além disso, o Visual propriedade pode ser substituída em uma
exibição.

As capturas de tela a seguir mostram uma interface do usuário renderizada usando os processadores de padrão:
As capturas de tela a seguir mostram a mesma interface do usuário renderizado usando os processadores de
materiais:

As principais diferenças visíveis entre os renderizadores de material, mostrados aqui e o renderizadores padrão
são os renderizadores de material em maiuscula Button texto e arredondar os cantos do Frame bordas. No
entanto, os renderizadores de material usam controles nativos e, portanto, ainda pode haver diferenças de
interface de usuário entre plataformas para áreas como sombras, fontes, cores e elevação.

NOTE
Componentes de Design de material risca diretrizes do Google. Como resultado, os renderizadores de Design de Material são
mais adequados para dimensionamento e o comportamento. Quando você precisar de maior controle dos estilos ou
comportamento, você ainda pode criar seus próprios efeito, comportamento, ou renderizador personalizado para alcançar o
detalhe que você precisa.

Personalizar os renderizadores de material


Os renderizadores de material, opcionalmente, podem ser personalizados, assim como os renderizadores de
padrão, as seguintes classes de base por meio de:
MaterialButtonRenderer
MaterialEntryRenderer
MaterialFrameRenderer
MaterialProgressBarRenderer
MaterialDatePickerRenderer
MaterialTimePickerRenderer
MaterialPickerRenderer
MaterialActivityIndicatorRenderer
MaterialEditorRenderer
MaterialSliderRenderer
MaterialStepperRenderer

O código a seguir mostra um exemplo de como personalizar o MaterialProgressBarRenderer classe:

using Xamarin.Forms.Material.Android;

[assembly: ExportRenderer(typeof(ProgressBar), typeof(CustomMaterialProgressBarRenderer), new[] {


typeof(VisualMarker.MaterialVisual) })]
namespace MyApp.Android
{
public class CustomMaterialProgressBarRenderer : MaterialProgressBarRenderer
{
...
}
}

Neste exemplo, o ExportRendererAttribute Especifica que o CustomMaterialProgressBarRenderer classe será usada


para renderizar o ProgressBar exibição, com o IVisual tipo registrado como o terceiro argumento.

NOTE
Um renderizador que especifica um IVisual tipo, como parte da sua ExportRendererAttribute , será usado para
renderizar aceitado modos de exibição, em vez do renderizador padrão. Em tempo de seleção do renderizador, o Visual
propriedade do modo de exibição é inspecionada e incluída no processo de seleção do renderizador.

Para obter mais informações sobre renderizadores personalizados, consulte renderizadores personalizados.

Links relacionados
Material Visual (amostra)
Criar um renderizador Visual do xamarin. Forms
Renderizadores personalizados
Criar um renderizador Visual do xamarin. Forms
12/04/2019 • 6 minutes to read

Baixar o exemplo
Visual do xamarin. Forms permite renderizadores seja criada e aplicada seletivamente VisualElement objetos, sem
ter de exibições do xamarin. Forms subclasse. Um renderizador que especifica um IVisual tipo, como parte da
sua ExportRendererAttribute , será usado para renderizar aceitado modos de exibição, em vez do renderizador
padrão. Em tempo de seleção do renderizador, o Visual propriedade do modo de exibição é inspecionada e
incluída no processo de seleção do renderizador.

IMPORTANT
Atualmente, o Visual propriedade não pode ser alterada depois que o modo de exibição foi renderizado, mas isso será
alterado em uma versão futura.

O processo para criar e consumir um renderizador Visual do xamarin. Forms é:


1. Crie renderizadores de plataforma para a exibição necessária. Para obter mais informações, consulte criar
renderizadores.
2. Criar um tipo que deriva de IVisual . Para obter mais informações, consulte criar um tipo IVisual.
3. Registre-se a IVisual tipo como parte do ExportRendererAttribute que decora os renderizadores. Para obter
mais informações, consulte registrar o tipo de IVisual.
4. Consumir o renderizador Visual, definindo o Visual propriedade no modo de exibição para o IVisual nome.
Para obter mais informações, consulte consumir o renderizador Visual.
5. [opcional] Registrar um nome para o IVisual tipo. Para obter mais informações, consulte registrar um nome
para o tipo de IVisual.

Criar renderizadores de plataforma


Para obter informações sobre como criar uma classe de renderizador, consulte renderizadores personalizados. No
entanto, observe que um renderizador Visual do xamarin. Forms é aplicado a um modo de exibição sem precisar
subclasse o modo de exibição.
As classes de renderizador descritas aqui implementam um personalizado Button que exibe seu texto com uma
sombra.
iOS
O exemplo de código a seguir mostra o renderizador do botão para iOS:
public class CustomButtonRenderer : ButtonRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
{
base.OnElementChanged(e);

if (e.OldElement != null)
{
// Cleanup
}

if (e.NewElement != null)
{
Control.TitleShadowOffset = new CoreGraphics.CGSize(1, 1);
Control.SetTitleShadowColor(Color.Black.ToUIColor(), UIKit.UIControlState.Normal);
}
}
}

Android
O exemplo de código a seguir mostra o renderizador do botão para Android:

public class CustomButtonRenderer : Xamarin.Forms.Platform.Android.AppCompat.ButtonRenderer


{
public CustomButtonRenderer(Context context) : base(context)
{
}

protected override void OnElementChanged(ElementChangedEventArgs<Button> e)


{
base.OnElementChanged(e);

if (e.OldElement != null)
{
// Cleanup
}

if (e.NewElement != null)
{
Control.SetShadowLayer(5, 3, 3, Color.Black.ToAndroid());
}
}
}

Criar um tipo de IVisual


Em sua biblioteca de plataforma cruzada, criar um tipo que deriva de IVisual :

public class CustomVisual : IVisual


{
}

O CustomVisual tipo, em seguida, pode ser registrado em classes de renderizador, permitindo Button objetos a
serem optarem por usar os renderizadores.

Registrar o tipo de IVisual


Em projetos da plataforma, Decore as classes de renderizador com o ExportRendererAttribute :
[assembly: ExportRenderer(typeof(Xamarin.Forms.Button), typeof(CustomButtonRenderer), new[] {
typeof(CustomVisual) })]
public class CustomButtonRenderer : ButtonRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
{
...
}
}

Neste exemplo, o ExportRendererAttribute Especifica que o CustomButtonRenderer classe será usada para
renderizar consumindo Button objetos, com o IVisual tipo registrado como o terceiro argumento. Um
renderizador que especifica um IVisual tipo, como parte da sua ExportRendererAttribute , será usado para
renderizar aceitado modos de exibição, em vez do renderizador padrão.

Consumir o renderizador Visual


Um Button pode aceitar o objeto usando as classes de renderizador definindo seu Visual propriedade Custom :

<Button Visual="Custom"
Text="CUSTOM BUTTON"
BackgroundColor="{StaticResource PrimaryColor}"
TextColor="{StaticResource SecondaryTextColor}"
HorizontalOptions="FillAndExpand" />

NOTE
No XAML, um conversor de tipo remove a necessidade de incluir o sufixo "Visual" na Visual valor da propriedade. No
entanto, o nome de tipo completo também pode ser especificado.

O código c# equivalente é:

Button button = new Button { Text = "CUSTOM BUTTON", ... };


button.Visual = new CustomVisual();

Em tempo de seleção do renderizador, o Visual propriedade o Button é inspecionado e incluídos no processo de


seleção do renderizador. Se um renderizador não for localizado, será usado o renderizador padrão do xamarin.
Forms.
As capturas de tela a seguir mostram o renderizado Button , que exibe seu texto com uma sombra:

Registrar um nome para o tipo de IVisual


O VisualAttribute pode ser usado para, opcionalmente, registrar um nome diferente para o IVisual tipo. Essa
abordagem pode ser usada para resolver conflitos de nomes entre diferentes bibliotecas do Visual ou em
situações em que você apenas deseja se referir a um elemento Visual por um nome diferente de seu nome de tipo.
O VisualAttribute devem ser definidos no nível de assembly na biblioteca multiplataforma ou no projeto de
plataforma:

[assembly: Visual("MyVisual", typeof(CustomVisual))]

O IVisual tipo pode ser consumido por meio de seu nome registrado:

<Button Visual="MyVisual"
... />

NOTE
Ao consumir um Visual por meio de seu nome registrado, qualquer sufixo "Visual" deve ser incluído.

Links relacionados
Material Visual (amostra)
Material do xamarin. Forms Visual
Renderizadores personalizados
O xamarin. Forms Visual State Manager
12/04/2019 • 27 minutes to read

baixar o exemplo
Use o Gerenciador de estado Visual para fazer alterações em elementos XAML com base em estados visuais
definido no código.
O Gerenciador de VSM (Visual State) é nova no xamarin. Forms 3.0. O VSM fornece uma maneira estruturada
para fazer alterações visual para a interface do usuário do código. Na maioria dos casos, a interface do usuário
do aplicativo é definida em XAML, e este XAML inclui a marcação que descreve como o Gerenciador de estado
Visual afeta os visuais da interface do usuário.
O VSM apresenta o conceito de estados visuais. Um modo de exibição do xamarin. Forms, como um Button
pode ter várias aparências diferentes dependendo do seu estado subjacente — se ele estiver desabilitado, ou
pressionado ou se tem o foco de entrada. Esses são os estados do botão.
Estados visuais são coletados no grupos de estado visual. Todos os estados visuais dentro de um grupo de
estado visual são mutuamente exclusivos. Estados visuais e grupos de estado visual são identificados por
cadeias de caracteres de texto simples.
O Gerenciador de estado Visual do xamarin. Forms define um grupo de estado visual chamado
"CommonStates" com três estados visuais:
"Normal"
"Desabilitado"
"Com foco"
Há suporte para esse grupo de estados visuais para todas as classes que derivam de VisualElement , que é a
classe base para View e Page .
Você também pode definir seus próprios grupos de estado visual e os estados visuais, como este artigo irá
demonstrar.

NOTE
Os desenvolvedores de xamarin. Forms familiarizados com gatilhos estão cientes de que os gatilhos também podem fazer
alterações aos visuais na interface do usuário com base em alterações em Propriedades da exibição ou o acionamento de
eventos. No entanto, usando gatilhos para lidar com várias combinações dessas alterações pode se tornar bastante
confuso. Historicamente, o Gerenciador de estado Visual foi introduzido em ambientes baseados em XAML do Windows
para minimizar a confusão resultante de combinações de estados visuais. Os estados visuais dentro de um grupo de
estado visual com o VSM, sempre são mutuamente exclusivos. A qualquer momento, apenas um estado em cada grupo é
o estado atual.

Os estados comuns
O Gerenciador de estado Visual permite que você inclua seções no arquivo XAML que pode alterar a aparência
visual de um modo de exibição, se o modo de exibição é normal ou desabilitado ou se tiver o foco de entrada.
Eles são conhecidos como o estados comuns.
Por exemplo, suponha que você tenha um Entry modo de exibição em sua página, e você deseja que a
aparência visual do Entry alterar das seguintes maneiras:
O Entry deve ter uma rosa em segundo plano quando o Entry está desabilitado.
O Entry deve ter um plano de fundo verde-limão normalmente.
O Entry deve expandir para duas vezes sua altura normal quando ele tem foco de entrada.
Você pode anexar a marcação VSM a uma exibição individual, ou você pode defini-la em um estilo se apliquem
a vários modos de exibição. As duas próximas seções descrevem essas abordagens.
Marcação VSM em uma exibição
Anexar marcação VSM para um Entry exibir, primeiro separe o Entry nas marcas de início e término:

<Entry FontSize="18">

</Entry>

Isso tenha dado a um tamanho de fonte explícito porque um dos Estados usará o FontSize propriedade para
dobrar o tamanho do texto no Entry .
Em seguida, inserir VisualStateManager.VisualStateGroups marcas entre essas marcas:

<Entry FontSize="18">
<VisualStateManager.VisualStateGroups>

</VisualStateManager.VisualStateGroups>
</Entry>

VisualStateGroups é uma propriedade associável anexada definida pelo VisualStateManager classe. (Para obter
mais informações sobre propriedades vinculáveis anexadas, consulte o artigo propriedades anexadas.) Isso é
como o VisualStateGroups propriedade está anexada a Entry objeto.
O VisualStateGroups propriedade é do tipo VisualStateGroupList , que é uma coleção de VisualStateGroup
objetos. Dentro de VisualStateManager.VisualStateGroups marcas, inserir um par de VisualStateGroup marcas
para cada grupo de estados visuais que deseja incluir:

<Entry FontSize="18">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">

</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Entry>

Observe que o VisualStateGroup marca tem um x:Name atributo que indica o nome do grupo. O
VisualStateGroup classe define um Name propriedade que você pode usar em vez disso:

<VisualStateGroup Name="CommonStates">

Você pode usar tanto x:Name ou Name , mas não ambos no mesmo elemento.
O VisualStateGroup classe define uma propriedade chamada States , que é uma coleção de VisualState
objetos. States é o propriedade de conteúdo dos VisualStateGroups para que você possa incluir o
VisualState marcas diretamente entre o VisualStateGroup marcas. ( Conteúdo de propriedades são discutidas
no artigo sintaxe de XAML essencial.)
A próxima etapa é incluir um par de marcas para cada estado visual nesse grupo. Eles também podem ser
identificados usando x:Name ou Name :
<Entry FontSize="18">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">

</VisualState>

<VisualState x:Name="Focused">

</VisualState>

<VisualState x:Name="Disabled">

</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Entry>

VisualStatedefine uma propriedade chamada Setters , que é uma coleção de Setter objetos. Essas são as
mesmas Setter objetos que podem ser usados em um Style objeto.
Setters está não a propriedade content de VisualState , portanto, é necessário incluir marcas de elemento de
propriedade para o Setters propriedade:

<Entry FontSize="18">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>

</VisualState.Setters>
</VisualState>

<VisualState x:Name="Focused">
<VisualState.Setters>

</VisualState.Setters>
</VisualState>

<VisualState x:Name="Disabled">
<VisualState.Setters>

</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Entry>

Agora você pode inserir um ou mais Setter objetos entre cada par de Setters marcas. Esses são os Setter
objetos que definem os estados visuais descritos anteriormente:
<Entry FontSize="18">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Lime" />
</VisualState.Setters>
</VisualState>

<VisualState x:Name="Focused">
<VisualState.Setters>
<Setter Property="FontSize" Value="36" />
</VisualState.Setters>
</VisualState>

<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Pink" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Entry>

Cada Setter marca indica o valor de uma propriedade específica quando esse estado é atual. Qualquer
propriedade referenciada por uma Setter objeto deve ser feito por uma propriedade associável.
Marcação semelhante a esta é a base para o VSM na exibição página na VsmDemos programa de exemplo.
A página inclui três Entry modos de exibição, mas apenas um segundo tem a marcação VSM anexada a ele:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:VsmDemos"
x:Class="VsmDemos.MainPage"
Title="VSM Demos">

<StackLayout>
<StackLayout.Resources>
<Style TargetType="Entry">
<Setter Property="Margin" Value="20, 0" />
<Setter Property="FontSize" Value="18" />
</Style>

<Style TargetType="Label">
<Setter Property="Margin" Value="20, 30, 20, 0" />
<Setter Property="FontSize" Value="Large" />
</Style>
</StackLayout.Resources>

<Label Text="Normal Entry:" />

<Entry />

<Label Text="Entry with VSM: " />

<Entry>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">

<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Lime" />
</VisualState.Setters>
</VisualState>

<VisualState x:Name="Focused">
<VisualState.Setters>
<Setter Property="FontSize" Value="36" />
</VisualState.Setters>
</VisualState>

<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Pink" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>

<Entry.Triggers>
<DataTrigger TargetType="Entry"
Binding="{Binding Source={x:Reference entry3},
Path=Text.Length}"
Value="0">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Entry.Triggers>
</Entry>

<Label Text="Entry to enable 2nd Entry:" />

<Entry x:Name="entry3"
Text=""
Placeholder="Type something to enable 2nd Entry" />
</StackLayout>
</ContentPage>
Observe que a segunda Entry também tem um DataTrigger como parte de seu Trigger coleção. Isso faz
com que o Entry será desabilitada até que algo seja digitado à terceira Entry . Aqui está a página na
inicialização em execução no iOS, Android e Universal Windows Platform (UWP ):

O estado visual atual é "Disabled" para que o plano de fundo do segundo Entry é rosa em telas de Android e
iOS. A implementação de UWP do Entry não permite definir o plano de fundo de cor quando o Entry está
desabilitado.
Quando você digitar um texto à terceira Entry , o segundo Entry alterna para o estado "Normal" e o plano de
fundo agora está verde-limão:

Quando você tocar o segundo Entry , ele obtém o foco de entrada. Ele muda para o estado de "Focalizado" e se
expande para duas vezes sua altura:
Observe que o Entry não retém o plano de fundo verde-limão quando ele recebe o foco de entrada. Como o
Gerenciador de estado Visual alterna entre os estados visuais, as propriedades definidas pelo estado anterior
são não definidas. Tenha em mente que os estados visuais são mutuamente exclusivos. O estado "Normal" não
significa apenas que o Entry está habilitado. Isso significa que o Entry está habilitado e não tem o foco de
entrada.
Se você quiser que o Entry para ter um plano de fundo verde-limão em estado "Focalizado", adicione outro
Setter para que o estado visual:

<VisualState x:Name="Focused">
<VisualState.Setters>
<Setter Property="FontSize" Value="36" />
<Setter Property="BackgroundColor" Value="Lime" />
</VisualState.Setters>
</VisualState>

Para que eles Setter objetos funcione corretamente, um VisualStateGroup deve conter VisualState objetos
para todos os estados no grupo. Se não houver um estado visual que não tem nenhum Setter objetos, incluí-
lo mesmo assim como uma marca vazia:

<VisualState x:Name="Normal" />

Marcação de Gerenciador de estado visual em um estilo


Ele geralmente é necessário compartilhar a mesma marcação de Gerenciador de estado Visual entre dois ou
mais exibições. Nesse caso, você desejará colocar a marcação em um Style definição.
Aqui está implícita existente Style para o Entry elementos na VSM no modo de exibição página:

<Style TargetType="Entry">
<Setter Property="Margin" Value="20, 0" />
<Setter Property="FontSize" Value="18" />
</Style>

Adicione Setter marcas para o VisualStateManager.VisualStateGroups propriedade associável anexada:


<Style TargetType="Entry">
<Setter Property="Margin" Value="20, 0" />
<Setter Property="FontSize" Value="18" />
<Setter Property="VisualStateManager.VisualStateGroups">

</Setter>
</Style>

A propriedade de conteúdo para Setter está Value , portanto, o valor da Value propriedade pode ser
especificada diretamente dentro de marcas. Se a propriedade é do tipo VisualStateGroupList :

<Style TargetType="Entry">
<Setter Property="Margin" Value="20, 0" />
<Setter Property="FontSize" Value="18" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>

</VisualStateGroupList>
</Setter>
</Style>

Dentro dessas marcas, você pode incluir um ou mais VisualStateGroup objetos:

<Style TargetType="Entry">
<Setter Property="Margin" Value="20, 0" />
<Setter Property="FontSize" Value="18" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">

</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>

O restante da marcação VSM é o mesmo de antes.


Aqui está o VSM em estilo página mostrando a marcação VSM completa:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="VsmDemos.VsmInStylePage"
Title="VSM in Style">
<StackLayout>
<StackLayout.Resources>
<Style TargetType="Entry">
<Setter Property="Margin" Value="20, 0" />
<Setter Property="FontSize" Value="18" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">

<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Lime" />
</VisualState.Setters>
</VisualState>

<VisualState x:Name="Focused">
<VisualState.Setters>
<Setter Property="FontSize" Value="36" />
<Setter Property="BackgroundColor" Value="Lime" />
</VisualState.Setters>
</VisualState>

<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Pink" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>

<Style TargetType="Label">
<Setter Property="Margin" Value="20, 30, 20, 0" />
<Setter Property="FontSize" Value="Large" />
</Style>
</StackLayout.Resources>

<Label Text="Normal Entry:" />

<Entry />

<Label Text="Entry with VSM: " />

<Entry>
<Entry.Triggers>
<DataTrigger TargetType="Entry"
Binding="{Binding Source={x:Reference entry3},
Path=Text.Length}"
Value="0">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Entry.Triggers>
</Entry>

<Label Text="Entry to enable 2nd Entry:" />

<Entry x:Name="entry3"
Text=""
Placeholder="Type something to enable 2nd Entry" />
</StackLayout>
</ContentPage>
Agora todos os Entry exibições nesta página respondem da mesma maneira para seus estados visuais.
Observe também que o estado "Focalizado" inclui agora uma segunda Setter que dá a cada Entry um verde-
limão em segundo plano também quando ele tem o foco de entrada:

Definindo seus próprios estados visuais


Cada classe que deriva de VisualElement dá suporte a três estados comuns "Normal", "Voltada para" e
"Disabled". Internamente, o VisualElement classe detecta quando ele está se tornando habilitado ou
desabilitado, ou focalizado ou sem foco e chama estático VisualStateManager.GoToState método:

VisualStateManager.GoToState(this, "Focused");

Isso é o único código do Gerenciador de estado Visual que você encontrará o VisualElement classe. Porque
GoToState é chamado para cada objeto com base em cada classe que deriva de VisualElement , você pode usar
o Gerenciador de estado Visual com qualquer VisualElement objeto para responder a essas alterações.
Curiosamente, o nome do grupo de estados visuais "CommonStates" não é explicitamente referenciado nos
VisualElement . O nome do grupo não é parte da API para o Gerenciador de estado Visual. Dentro de um a
dois programa de exemplo mostrado até agora, você pode alterar o nome do grupo de "CommonStates" para
qualquer outra coisa, e o programa ainda funcionará. O nome do grupo é meramente uma descrição geral dos
estados no grupo. É implicitamente entendido que os estados visuais em qualquer grupo são mutuamente
exclusivos: uma e apenas um estado é atual a qualquer momento.
Se você quiser implementar seus próprios estados visuais, você precisará chamar
VisualStateManager.GoToState do código. Geralmente, você fará essa chamada do arquivo code-behind da sua
classe de página.
O VSM validação página de VsmDemos exemplo mostra como usar o Gerenciador de estado Visual em
conexão com a validação de entrada. O arquivo XAML consiste em dois Label elementos, uma Entry , e
Button :
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="VsmDemos.VsmValidationPage"
Title="VSM Validation">
<StackLayout Padding="10, 10">

<Label Text="Enter a U.S. phone number:"


FontSize="Large" />

<Entry Placeholder="555-555-5555"
FontSize="Large"
Margin="30, 0, 0, 0"
TextChanged="OnTextChanged" />

<Label x:Name="helpLabel"
Text="Phone number must be of the form 555-555-5555, and not begin with a 0 or 1">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="ValidityStates">

<VisualState Name="Valid">
<VisualState.Setters>
<Setter Property="TextColor" Value="Transparent" />
</VisualState.Setters>
</VisualState>

<VisualState Name="Invalid" />

</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Label>

<Button x:Name="submitButton"
Text="Submit"
FontSize="Large"
Margin="0, 20"
VerticalOptions="Center"
HorizontalOptions="Center">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="ValidityStates">

<VisualState Name="Valid" />

<VisualState Name="Invalid">
<VisualState.Setters>
<Setter Property="IsEnabled" Value="False" />
</VisualState.Setters>
</VisualState>

</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Button>
</StackLayout>
</ContentPage>

Marcação VSM está anexada à segunda Label (chamado helpLabel ) e o Button (chamado submitButton ). Há
dois estados mutuamente exclusivas, chamados de "Válido" e "Inválido". Observe que cada um dos dois grupos
de "ValidationState" contém VisualState marcas para "Válido" e "Inválido", embora um deles está vazio em
cada caso.
Se o Entry não contém um número de telefone válido, em seguida, o estado atual é "Inválido" e, portanto, a
segunda Label está visível e o Button está desabilitado:
Quando um número de telefone válido for inserido, em seguida, o estado atual se torna "Válido". A segunda
Entry desaparece e a Button agora está habilitado:

O arquivo code-behind é responsável para a manipulação de TextChanged eventos do Entry . O manipulador


usa uma expressão regular para determinar se a cadeia de caracteres de entrada é válida ou não. O método em
que o arquivo code-behind chamado GoToState chama estático VisualStateManager.GoToState método para
ambos helpLabel e submitButton :
public partial class VsmValidationPage : ContentPage
{
public VsmValidationPage ()
{
InitializeComponent ();

GoToState(false);
}

void OnTextChanged(object sender, TextChangedEventArgs args)


{
bool isValid = Regex.IsMatch(args.NewTextValue, @"^[2-9]\d{2}-\d{3}-\d{4}$");
GoToState(isValid);
}

void GoToState(bool isValid)


{
string visualState = isValid ? "Valid" : "Invalid";
VisualStateManager.GoToState(helpLabel, visualState);
VisualStateManager.GoToState(submitButton, visualState);
}
}

Observe também que o GoToState método é chamado de construtor para inicializar o estado. Sempre deve
haver um estado atual. Mas não no código há qualquer referência ao nome do grupo de estados visuais,
embora ela é referenciada no XAML como "ValidationStates" para fins de clareza.
Observe que o arquivo code-behind deve levar em conta todos os objetos na página que é afetada por esses
estados visuais e chamar VisualStateManager.GoToState para cada um desses objetos. Neste exemplo, ele é
apenas dois objetos (o Label e o Button ), mas poderia ser vários mais.
Você talvez esteja se perguntando: se o arquivo code-behind deve fazer referência a todos os objetos na página
que é afetado por esses estados visuais, por que não o arquivo code-behind simplesmente acessar os objetos
diretamente? Obviamente, foi possível. No entanto, a vantagem de usar o VSM é que você pode controlar os
elementos visuais como reagir a estado diferente inteiramente em XAML, que mantém todos o design de
interface do usuário em um único local. Isso evita a aparência visual de configuração por meio de acessar
elementos visuais diretamente no code-behind.
Pode ser tentador considere derivar uma classe de Entry e talvez definindo uma propriedade que você pode
definir uma função externa de validação. A classe que deriva de Entry , em seguida, pode chamar o
VisualStateManager.GoToState método. Esse esquema funcionaria bem, mas somente se o Entry foram o único
objeto afetado pelos estados visuais diferentes. Neste exemplo, uma Label e um Button também são
afetados. Não é possível para marcação VSM anexados a um Entry para controlar outros objetos na página e
nenhuma maneira para marcação VSM anexados a esses outros objetos para fazer referência a uma alteração
de estado visual de outro objeto.

Usando o Gerenciador de estado Visual para o layout adaptável


Um xamarin. Forms aplicativo em execução em um telefone geralmente pode ser exibido em um retrato ou
paisagem taxa de proporção e um programa de xamarin. Forms em execução na área de trabalho pode ser
redimensionada para assumir muitos tamanhos diferentes e taxas de proporção. Um aplicativo bem projetado
pode exibir seu conteúdo diferentes para esses vários fatores de formulário de página ou janela.
Às vezes, essa técnica é conhecida como adaptável layout. Como layout adaptável envolve apenas elementos
visuais de um programa, ele é um aplicativo ideal do Gerenciador de estado Visual.
Um exemplo simples é um aplicativo que exibe uma pequena coleção de botões que afetam o conteúdo do
aplicativo. No modo retrato, esses botões podem ser exibidos em uma linha horizontal na parte superior da
página:

No modo paisagem, a matriz de botões pode ser movida para um lado e exibida em uma coluna:

De cima para baixo, o programa está em execução a plataforma Universal do Windows, Android e iOS.
O Layout adaptável do VSM página de VsmDemos exemplo define um grupo chamado "OrientationStates"
com dois estados visuais denominados "Retrato" e "Paisagem". (Uma abordagem mais complexa pode ser
baseada em várias larguras de página ou janela diferentes).
Marcação VSM ocorre em quatro lugares no arquivo XAML. O StackLayout nomeado mainStack contém o
menu e o conteúdo, que é um Image elemento. Isso StackLayout deve ter uma orientação vertical no modo
retrato e uma orientação horizontal no modo paisagem:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="VsmDemos.VsmAdaptiveLayoutPage"
Title="VSM Adaptive Layout">

<StackLayout x:Name="mainStack">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="OrientationStates">

<VisualState Name="Portrait">
<VisualState.Setters>
<Setter Property="Orientation" Value="Vertical" />
</VisualState.Setters>
</VisualState>

<VisualState Name="Landscape">
<VisualState.Setters>
<Setter Property="Orientation" Value="Horizontal" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>

<ScrollView x:Name="menuScroll">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="OrientationStates">

<VisualState Name="Portrait">
<VisualState.Setters>
<Setter Property="Orientation" Value="Horizontal" />
</VisualState.Setters>
</VisualState>

<VisualState Name="Landscape">
<VisualState.Setters>
<Setter Property="Orientation" Value="Vertical" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>

<StackLayout x:Name="menuStack">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="OrientationStates">

<VisualState Name="Portrait">
<VisualState.Setters>
<Setter Property="Orientation" Value="Horizontal" />
</VisualState.Setters>
</VisualState>

<VisualState Name="Landscape">
<VisualState.Setters>
<Setter Property="Orientation" Value="Vertical" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>

<StackLayout.Resources>
<Style TargetType="Button">
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup Name="OrientationStates">

<VisualState Name="Portrait">
<VisualState Name="Portrait">
<VisualState.Setters>
<Setter Property="HorizontalOptions" Value="CenterAndExpand" />
<Setter Property="Margin" Value="10, 5" />
</VisualState.Setters>
</VisualState>

<VisualState Name="Landscape">
<VisualState.Setters>
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="Margin" Value="10" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
</StackLayout.Resources>

<Button Text="Banana"
Command="{Binding SelectedCommand}"
CommandParameter="Banana.jpg" />

<Button Text="Face Palm"


Command="{Binding SelectedCommand}"
CommandParameter="FacePalm.jpg" />

<Button Text="Monkey"
Command="{Binding SelectedCommand}"
CommandParameter="monkey.png" />

<Button Text="Seated Monkey"


Command="{Binding SelectedCommand}"
CommandParameter="SeatedMonkey.jpg" />
</StackLayout>
</ScrollView>

<Image x:Name="image"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand" />
</StackLayout>
</ContentPage>

Interno ScrollView nomeado menuScroll e o StackLayout denominada menuStack implementar o menu de


botões. A orientação desses layouts é o oposto de mainStack . O menu deve ser horizontal no modo retrato e
vertical no modo paisagem.
A quarta seção de marcação VSM está em um estilo implícito para os botões em si. Essa marcação define
VerticalOptions , HorizontalOptions , e Margin propriedades específicas para as orientações portait e
paisagem.
Os conjuntos de arquivos de lógica de BindingContext propriedade de menuStack para implementar Button
dos comandos e também anexa um manipulador para o SizeChanged eventos da página:
public partial class VsmAdaptiveLayoutPage : ContentPage
{
public VsmAdaptiveLayoutPage ()
{
InitializeComponent ();

SizeChanged += (sender, args) =>


{
string visualState = Width > Height ? "Landscape" : "Portrait";
VisualStateManager.GoToState(mainStack, visualState);
VisualStateManager.GoToState(menuScroll, visualState);
VisualStateManager.GoToState(menuStack, visualState);

foreach (View child in menuStack.Children)


{
VisualStateManager.GoToState(child, visualState);
}
};

SelectedCommand = new Command<string>((filename) =>


{
image.Source = ImageSource.FromResource("VsmDemos.Images." + filename);
});

menuStack.BindingContext = this;
}

public ICommand SelectedCommand { private set; get; }


}

O SizeChangedchamadas do manipulador VisualStateManager.GoToState para os dois StackLayout e


ScrollView elementos e, em seguida, executa um loop pelos filhos de menuStack chamar
VisualStateManager.GoToState para o Button elementos.

Pode parecer como se o arquivo code-behind pode lidar com alterações de orientação mais diretamente,
definindo as propriedades dos elementos no arquivo XAML, mas o Gerenciador de estado Visual é
definitivamente uma abordagem mais estruturada. Todos os elementos visuais são mantidos no arquivo XAML,
onde eles se tornam mais fácil de examinar, manutenção e modificar.

Gerenciador de estado visual com Xamarin.University


Xamarin. Forms 3.0 Visual State Manager, por Xamarin University

Links relacionados
VsmDemos
WebView do xamarin. Forms
12/04/2019 • 18 minutes to read

baixar o exemplo
WebView é um modo de exibição da web e o conteúdo HTML em seu aplicativo. Diferentemente OpenUri , que
leva o usuário para o navegador da web no dispositivo, WebView exibe o conteúdo HTML dentro de seu
aplicativo.

Conteúdo
WebView suporta os seguintes tipos de conteúdo:
Sites HTML e CSS – WebView tem suporte completo para sites da Web escritos usando HTML e CSS,
incluindo suporte a JavaScript.
Documentos – como WebView é implementado usando componentes nativos em cada plataforma, WebView
é capaz de mostrar os documentos que podem ser exibidos em cada plataforma. Isso significa que os arquivos
PDF funcionam no iOS e Android.
Cadeias de caracteres HTML – WebView pode mostrar cadeias de caracteres HTML da memória.
Arquivos locais – WebView pode apresentar qualquer um dos tipos de conteúdo acima inserido no aplicativo.

NOTE
WebView no Windows não oferece suporte do Silverlight, Flash ou todos os controles ActiveX, mesmo se eles são
suportados pelo Internet Explorer nessa plataforma.

Sites
Para exibir um site da internet, defina as WebView do Source propriedade como uma cadeia de caracteres de URL:
var browser = new WebView
{
Source = "http://xamarin.com"
};

NOTE
URLs devem ser totalmente formadas com o protocolo especificado (ou seja, ele deve ter "http://" ou "https://" acrescentado
a ele).

iOS e ATS
Desde a versão 9, iOS só permitirá que seu aplicativo para se comunicar com servidores que implementam as
práticas recomendadas de segurança por padrão. Valores devem ser definidos Info.plist para habilitar a
comunicação com servidores inseguros.

NOTE
Se seu aplicativo requer uma conexão em um site inseguro, você sempre deve inserir o domínio como uma exceção usando
NSExceptionDomains em vez de como o ATS desativar completamente usando NSAllowsArbitraryLoads .
NSAllowsArbitraryLoads só deve ser usado em situações extremas de emergências.

O exemplo a seguir demonstra como habilitar um domínio específico (em xamarin.com neste caso) para ignorar
os requisitos de ATS:

<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>xamarin.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSTemporaryExceptionMinimumTLSVersion</key>
<string>TLSv1.1</string>
</dict>
</dict>
</dict>
...
</key>

É uma prática recomendada para permitir que somente alguns domínios ignorar a ATS, permitindo que você use
sites confiáveis enquanto se beneficia com a segurança adicional em domínios não confiáveis. O exemplo a seguir
demonstra o método menos seguro de desabilitar o ATS para o aplicativo:

<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads </key>
<true/>
</dict>
...
</key>

Ver segurança de transporte de aplicativo para obter mais informações sobre esse novo recurso no iOS 9.
Cadeias de caracteres HTML
Se você quiser apresentar uma cadeia de caracteres de HTML definida dinamicamente no código, você precisará
criar uma instância do HtmlWebViewSource :

var browser = new WebView();


var htmlSource = new HtmlWebViewSource();
htmlSource.Html = @"<html><body>
<h1>Xamarin.Forms</h1>
<p>Welcome to WebView.</p>
</body></html>";
browser.Source = htmlSource;

No código acima, @ é usado para marcar o HTML como uma cadeia de caracteres literal, o que significa que
todos os caracteres de escape comuns são ignorados.
Conteúdo HTML local
WebView pode exibir o conteúdo do HTML, CSS e Javascript inserido dentro do aplicativo. Por exemplo:

<html>
<head>
<title>Xamarin Forms</title>
</head>
<body>
<h1>Xamrin.Forms</h1>
<p>This is an iOS web page.</p>
<img src="XamarinLogo.png" />
</body>
</html>

CSS:
html,body {
margin:0;
padding:10;
}
body,p,h1 {
font-family: Chalkduster;
}

Observe que as fontes especificadas no CSS acima precisará ser personalizado para cada plataforma, pois nem
todas as plataforma tem as mesmas fontes.
Para exibição local conteúdo usando um WebView , você precisará abrir o arquivo HTML como qualquer outro e,
em seguida, carregar o conteúdo como uma cadeia de caracteres para o Html propriedade de um
HtmlWebViewSource . Para obter mais informações sobre a abertura de arquivos, consulte trabalhando com
arquivos.
As capturas de tela a seguir mostram o resultado de exibição de conteúdo local em cada plataforma:

Embora a primeira página é carregada, o WebView não tem conhecimento de onde veio o HTML. Isso é um
problema ao lidar com páginas que fazem referência a recursos locais. Quando o link de páginas locais aos
outros, uma página faz uso de um arquivo JavaScript separado ou uma página contém links para uma folha de
estilos CSS são exemplos de quando isso pode acontecer.
Para resolver isso, você precisa informar o WebView onde localizar os arquivos no sistema de arquivos. Fazer isso
definindo a BaseUrl propriedade em de HtmlWebViewSource usado pelo WebView .
Como o sistema de arquivos em cada um dos sistemas operacionais é diferente, você precisa determinar essa
URL em cada plataforma. Xamarin. Forms expõe a DependencyService para resolução de dependências em tempo
de execução em cada plataforma.
Para usar o DependencyService , primeiro defina uma interface que pode ser implementada em cada plataforma:

public interface IBaseUrl { string Get(); }

Observe que, até que a interface é implementada em cada plataforma, o aplicativo não será executado. No projeto
comuns, certifique-se de que você se lembrar de definir a BaseUrl usando o DependencyService :

var source = new HtmlWebViewSource();


source.BaseUrl = DependencyService.Get<IBaseUrl>().Get();

Implementações da interface para cada plataforma, em seguida, devem ser fornecidas.


iOS
No iOS, o conteúdo da web deve estar localizado no diretório raiz do projeto ou recursos diretório com a ação de
build BundleResource, conforme demonstrado a seguir:
Visual Studio
Visual Studio para Mac

O BaseUrl deve ser definido como o caminho do pacote principal:


[assembly: Dependency (typeof (BaseUrl_iOS))]
namespace WorkingWithWebview.iOS
{
public class BaseUrl_iOS : IBaseUrl
{
public string Get()
{
return NSBundle.MainBundle.BundlePath;
}
}
}

Android
No Android, coloque o HTML, CSS e imagens na pasta ativos com a ação de build AndroidAsset como
demonstrado a seguir:
Visual Studio
Visual Studio para Mac

No Android, o BaseUrl deve ser definido como "file:///android_asset/" :

[assembly: Dependency (typeof(BaseUrl_Android))]


namespace WorkingWithWebview.Android
{
public class BaseUrl_Android : IBaseUrl
{
public string Get()
{
return "file:///android_asset/";
}
}
}

No Android, arquivos de ativos pasta também pode ser acessada por meio do contexto Android atual, que é
exposto pelo MainActivity.Instance propriedade:

var assetManager = MainActivity.Instance.Assets;


using (var streamReader = new StreamReader (assetManager.Open ("local.html")))
{
var html = streamReader.ReadToEnd ();
}

Plataforma Universal do Windows


Em projetos de plataforma Universal do Windows (UWP ), colocar HTML, CSS e imagens na raiz do projeto com
a ação de build definida como conteúdo.
O BaseUrl deve ser definido como "ms-appx-web:///" :

[assembly: Dependency(typeof(BaseUrl))]
namespace WorkingWithWebview.UWP
{
public class BaseUrl : IBaseUrl
{
public string Get()
{
return "ms-appx-web:///";
}
}
}

Navegação
WebView dá suporte à navegação por meio de vários métodos e propriedades que ele se torna disponível:
GoForward() – se CanGoForward for true, chamar GoForward navega para a próxima página visitada.
GoBack() – se CanGoBack for true, chamar GoBack navegará para a última página visitada.
CanGoBack – true se não houver páginas para navegar de volta para false se o navegador é a URL inicial.
CanGoForward – true se o usuário navegar para trás e avance até uma página que já foi visitada.

Em páginas, WebView não oferece suporte a gestos multitoque. É importante para garantir que o conteúdo é
otimizada para celular e é exibido sem a necessidade de aumentar o zoom.
É comum para aplicativos mostrar um link dentro de um WebView , em vez do navegador do dispositivo. Nessas
situações, é útil permitir a navegação normal, mas quando o usuário optou novamente enquanto estiverem no
link inicial, o aplicativo deve retornar ao modo de exibição normal do aplicativo.
Use as propriedades e métodos de navegação interna para habilitar esse cenário.
Comece criando a página para o modo de exibição do navegador:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="WebViewSample.InAppBrowserXaml"
Title="Browser">
<StackLayout Margin="20">
<StackLayout Orientation="Horizontal">
<Button Text="Back" HorizontalOptions="StartAndExpand" Clicked="OnBackButtonClicked" />
<Button Text="Forward" HorizontalOptions="EndAndExpand" Clicked="OnForwardButtonClicked" />
</StackLayout>
<!-- WebView needs to be given height and width request within layouts to render. -->
<WebView x:Name="webView" WidthRequest="1000" HeightRequest="1000" />
</StackLayout>
</ContentPage>

No code-behind:
public partial class InAppBrowserXaml : ContentPage
{
public InAppBrowserXaml(string URL)
{
InitializeComponent();
webView.Source = URL;
}

async void OnBackButtonClicked(object sender, EventArgs e)


{
if (webView.CanGoBack)
{
webView.GoBack();
}
else
{
await Navigation.PopAsync();
}
}

void OnForwardButtonClicked(object sender, EventArgs e)


{
if (webView.CanGoForward)
{
webView.GoForward();
}
}
}

É só isso!

Eventos
WebView aciona os eventos a seguir para ajudá-lo a responder a alterações no estado:
Navigating – Evento gerado quando o WebView começa a carregar uma nova página.
Navigated – Evento gerado quando a página é carregada e navegação foi interrompido.
ReloadRequested – Evento gerado quando uma solicitação é feita para recarregar o conteúdo atual.
O WebNavigatingEventArgs objeto que acompanha o Navigating eventos tem quatro propriedades:
Cancel – Indica se deve ou não cancelar a navegação.
NavigationEvent – o evento de navegação que foi gerado.
Source – o elemento que executou a navegação.
Url – o destino de navegação.

O WebNavigatedEventArgs objeto que acompanha o Navigated eventos tem quatro propriedades:


NavigationEvent – o evento de navegação que foi gerado.
Result – Descreve o resultado do painel de navegação, usando um WebNavigationResult membro de
enumeração. Os valores válidos são Cancel , Failure , Success e Timeout .
Source – o elemento que executou a navegação.
Url – o destino de navegação.

Se você antecipar o uso de páginas da Web que levam muito tempo para carregar, considere usar o Navigating e
Navigated eventos para implementar um indicador de status. Por exemplo:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="WebViewSample.LoadingLabelXaml"
Title="Loading Demo">
<StackLayout>
<!--Loading label should not render by default.-->
<Label x:Name="labelLoading" Text="Loading..." IsVisible="false" />
<WebView HeightRequest="1000" WidthRequest="1000" Source="http://www.xamarin.com"
Navigated="webviewNavigated" Navigating="webviewNavigating" />
</StackLayout>
</ContentPage>

Os dois manipuladores de evento:

void webviewNavigating(object sender, WebNavigatingEventArgs e)


{
labelLoading.IsVisible = true;
}

void webviewNavigated(object sender, WebNavigatedEventArgs e)


{
labelLoading.IsVisible = false;
}

Isso resulta na seguinte saída (Carregando):


Carregamento concluído:
Recarregar conteúdo
WebView tem um Reload método que pode ser usado para recarregar o conteúdo atual:

var webView = new WebView();


...
webView.Reload();

Quando o Reload método é invocado o ReloadRequested evento é acionado, o que indica que uma solicitação foi
feita para recarregar o conteúdo atual.

Desempenho
Os navegadores da web populares agora adotam tecnologias, como a compilação de JavaScript e renderização
acelerada por hardware. No iOS, por padrão, o xamarin. Forms WebView é implementado pelo UIWebView classe e
várias dessas tecnologias não estão disponíveis nesta implementação. No entanto, um aplicativo pode participar
de uso do iOS WkWebView classe para implementar o xamarin. Forms WebView , que dá suporte à navegação mais
rápida. Isso pode ser feito adicionando o seguinte código para o AssemblyInfo.cs arquivo no projeto da
plataforma iOS para o aplicativo:

// Opt-in to using WkWebView instead of UIWebView.


[assembly: ExportRenderer(typeof(WebView), typeof(Xamarin.Forms.Platform.iOS.WkWebViewRenderer))]

WebView no Android por padrão é tão rápido quanto o navegador interno.


O UWP WebView usa o mecanismo de renderização do Microsoft Edge. Dispositivos de desktop e tablet devem
ver o mesmo desempenho quanto usar o próprio navegador Edge.

Permissões
Para que WebView para trabalhar, certifique-se de que as permissões são definidas para cada plataforma. Observe
que, em algumas plataformas, WebView funcionará no modo de depuração, mas não quando compilado para
versão. Isso ocorre porque algumas permissões, como aqueles para acesso à internet no Android, são definidos
por padrão pelo Visual Studio para Mac quando no modo de depuração.
UWP – exige a funcionalidade de Internet (cliente e servidor), ao exibir o conteúdo de rede.
Android – requer INTERNET apenas ao exibir o conteúdo da rede. Conteúdo local não requer nenhuma
permissão especial.
iOS – não exige nenhuma permissão especial.

Layout
Ao contrário da maioria dos outros modos de xamarin. Forms WebView exige que HeightRequest e WidthRequest
são especificados quando contido em StackLayout ou RelativeLayout. Se você não especificar essas propriedades,
o WebView não será renderizado.
Os exemplos a seguir demonstram os layouts que resultam em funcionamento, renderização WebView s:
StackLayout com WidthRequest & HeightRequest:
<StackLayout>
<Label Text="test" />
<WebView Source="http://www.xamarin.com/"
HeightRequest="1000"
WidthRequest="1000" />
</StackLayout>

RelativeLayout com WidthRequest & HeightRequest:

<RelativeLayout>
<Label Text="test"
RelativeLayout.XConstraint= "{ConstraintExpression
Type=Constant, Constant=10}"
RelativeLayout.YConstraint= "{ConstraintExpression
Type=Constant, Constant=20}" />
<WebView Source="http://www.xamarin.com/"
RelativeLayout.XConstraint="{ConstraintExpression Type=Constant,
Constant=10}"
RelativeLayout.YConstraint="{ConstraintExpression Type=Constant,
Constant=50}"
WidthRequest="1000" HeightRequest="1000" />
</RelativeLayout>

AbsoluteLayout sem WidthRequest & HeightRequest:

<AbsoluteLayout>
<Label Text="test" AbsoluteLayout.LayoutBounds="0,0,100,100" />
<WebView Source="http://www.xamarin.com/"
AbsoluteLayout.LayoutBounds="0,150,500,500" />
</AbsoluteLayout>

Grade sem WidthRequest & HeightRequest. A grade é um dos layouts de alguns que não exigem a especificação
de larguras e alturas solicitadas.:

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="100" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label Text="test" Grid.Row="0" />
<WebView Source="http://www.xamarin.com/" Grid.Row="1" />
</Grid>

Invocação de JavaScript
WebView inclui a capacidade de invocar uma função de JavaScript do C#e retornar qualquer resultado para a
chamada C# código. Isso é feito com o WebView.EvaluateJavaScriptAsync método, que é mostrado no exemplo a
seguir do WebView exemplo:

var numberEntry = new Entry { Text = "5" };


var resultLabel = new Label();
var webView = new WebView();
...

int number = int.Parse(numberEntry.Text);


string result = await webView.EvaluateJavaScriptAsync($"factorial({number})");
resultLabel.Text = $"Factorial of {number} is {result}.";
O WebView.EvaluateJavaScriptAsync método avalia o JavaScript que é especificado como o argumento e retorna
qualquer resultado como um string . Neste exemplo, o factorial função de JavaScript é chamada, que retorna
o fatorial de number como resultado. Esse JavaScript função é definida no HTML local do arquivo que o WebView
carrega e é mostrado no exemplo a seguir:

<html>
<body>
<script type="text/javascript">
function factorial(num) {
if (num === 0 || num === 1)
return 1;
for (var i = num - 1; i >= 1; i--) {
num *= i;
}
return num;
}
</script>
</body>
</html>

Links relacionados
Trabalhando com WebView (amostra)
WebView (amostra)
Recursos da plataforma xamarin. Forms
12/04/2019 • 2 minutes to read

Xamarin. Forms é extensível e permite que você incorpore recursos específicos à plataforma usando efeitos,
renderizadores personalizados, o DependencyService, o MessagingCentere muito mais.

Android
Este guia descreve as Android-especificidades da plataforma fornecidas pelo xamarin. Forms e como implementar
o Design de Material Atualizando aplicativos existentes do Android do xamarin. Forms.

Classe de dispositivo
Como usar o Device classe para criar o comportamento específico de plataforma em código compartilhado e a
interface do usuário (incluindo usando XAML ). Também aborda BeginInvokeOnMainThread que é essencial ao
modificar controles de interface do usuário de threads em segundo plano.

iOS
Este guia descreve as iOS -especificidades da plataforma fornecidas pelo xamarin. Forms e como executar
adicionais criando estilos por meio do iOS Info. plist e o UIAppearance API.

Formulários nativos
Formulários nativos permitem que o xamarin. Forms ContentPage -derivado de páginas a ser consumido por
projetos nativos do xamarin. IOS, xamarin. Android e plataforma Universal do Windows (UWP ).

Exibições nativas
Exibições nativas do iOS, Android e plataforma Universal do Windows podem ser referenciadas diretamente do
xamarin. Forms. Propriedades e os manipuladores de eventos podem ser definidos em exibições nativas e eles
podem interagir com exibições do xamarin. Forms.

Especificidades da plataforma
Especificidades da plataforma permitem que você consumir funcionalidade só está disponível em uma plataforma
específica, sem a necessidade de renderizadores personalizados ou efeitos. Além disso, os fornecedores podem
criar seus próprios itens específicos à plataforma com efeitos.

Windows
Este guia descreve as Windows-especificidades da plataforma fornecidas pelo xamarin. Forms e como adicionar
um projeto UWP a uma solução xamarin. Forms existente.
Recursos da plataforma Android
12/04/2019 • 5 minutes to read

Desenvolvimento de aplicativos xamarin. Forms para Android requer o Visual Studio. O página de requisitos
contém mais informações sobre os pré-requisitos.

Especificidades da plataforma
Especificidades da plataforma permitem que você consumir funcionalidade só está disponível em uma plataforma
específica, sem implementar renderizadores personalizados ou efeitos.
A seguinte funcionalidade específica da plataforma é fornecida para modos de exibição, páginas e layouts no
Android do xamarin. Forms:
Controlando a ordem Z dos elementos visuais para determinar a ordem de desenho. Para obter mais
informações, consulte VisualElement elevação no Android.
Desabilitar o modo de cor herdados em um com suporte VisualElement . Para obter mais informações,
consulte modo de cor VisualElement herdado no Android.
A seguinte funcionalidade específica da plataforma é fornecida para modos de exibição do xamarin. Forms no
Android:
Usando o preenchimento padrão e os valores de sombra dos botões do Android. Para obter mais informações,
consulte sombras no Android e o preenchimento do botão.
Configurando o método de entrada opções do editor para o teclado virtual para um Entry . Para obter mais
informações, consulte opções do Editor de método de entrada de entrada no Android.
Habilitando uma sombra em um ImageButton . Para obter mais informações, consulte ImageButton Drop
sombras no Android.
Habilitar a rolagem rápida em um ListView para obter mais informações, consulte ListView rolagem rápida
no Android.
Controlar se uma WebView pode exibir o conteúdo misto. Para obter mais informações, consulte WebView
misto conteúdo no Android.
A seguinte funcionalidade específica da plataforma é fornecida para páginas do xamarin. Forms no Android:
Definir a altura da barra de navegação em um NavigationPage . Para obter mais informações, consulte
NavigationPage altura da barra no Android.
Desabilitar animações de transição ao navegar entre páginas em um TabbedPage . Para obter mais
informações, consulte animações de transição de página TabbedPage no Android.
Habilitando o dedo entre páginas em um TabbedPage . Para obter mais informações, consulte TabbedPage
página passar o dedo no Android.
Definir o posicionamento da barra de ferramentas e a cor em um TabbedPage . Para obter mais informações,
consulte TabbedPage posicionamento de barra de ferramentas e a cor no Android.
A seguinte funcionalidade específica da plataforma é fornecida para o xamarin. Forms Application classe no
Android:
Definindo o modo de operação de um teclado virtual. Para obter mais informações, consulte reversível modo
de entrada de teclado no Android.
Desabilitando o Disappearing e Appearing página eventos de ciclo de vida em pausa e retomar,
respectivamente, para aplicativos que usam AppCompat. Para obter mais informações, consulte eventos de
ciclo de vida da página no Android.

Suporte de plataforma
Originalmente, o projeto do Android do xamarin. Forms padrão usado um estilo mais antigo de renderização de
controle do que era comum antes do Android 5.0. Aplicativos criados usando o modelo tem
FormsApplicationActivity como a classe base da sua atividade principal.

Design de material via AppCompat


Projetos do Android do xamarin. Forms enquanto, use FormsAppCompatActivity como a classe base da sua
atividade principal. Essa classe usa AppCompat recursos fornecidos pelo Android para implementar os temas de
Design de Material.
Para adicionar os temas de Design de Material ao seu projeto do Android do xamarin. Forms, execute o dar
suporte a instruções de instalação para AppCompat
Aqui está o Todo exemplo com o padrão FormsApplicationActivity :

E isso é o mesmo código depois de atualizar o projeto para usar FormsAppCompatActivity (e adicionar as
informações de tema adicionais):
NOTE
Ao usar FormsAppCompatActivity , o classes de base para alguns renderizadores personalizados Android será diferente.

Links relacionados
Adicionar suporte de Design de Material
Adicionando AppCompat e Design de Material
12/04/2019 • 4 minutes to read

Siga estas etapas para converter aplicativos existentes do Android do xamarin. Forms para usar AppCompat e
Design de Material

Visão geral
Estas instruções explicam como atualizar seus aplicativos existentes do Android do xamarin. Forms para usar a
biblioteca AppCompat e habilitar o Design de Material na versão Android de seus aplicativos xamarin. Forms.
1. Atualizar o xamarin. Forms
Certifique-se de que a solução está usando o xamarin. Forms 2.0 ou mais recente. Atualize o pacote Nuget do
xamarin. Forms para 2.0, se necessário.
2. Verificar a versão do Android
Verifique se a que estrutura de destino do projeto Android é o Android 6.0 (Marshmallow ). Verifique a projeto
Android > Opções > Build > geral configurações para garantir que o framework corrent está selecionada:

3. Adicionar novos temas para dar suporte a Design de Material


Crie três arquivos a seguir em seu projeto Android e cole no conteúdo abaixo. Google fornece um guia de estilo e
uma gerador da paleta de cores para ajudá-lo a escolher um esquema de cores alternativas ao especificado.
Resources/values/colors.xml

<resources>
<color name="primary">#2196F3</color>
<color name="primaryDark">#1976D2</color>
<color name="accent">#FFC107</color>
<color name="window_background">#F5F5F5</color>
</resources>

Resources/values/style.xml

<resources>
<style name="MyTheme" parent="MyTheme.Base">
</style>
<style name="MyTheme.Base" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">@color/primary</item>
<item name="colorPrimaryDark">@color/primaryDark</item>
<item name="colorAccent">@color/accent</item>
<item name="android:windowBackground">@color/window_background</item>
<item name="windowActionModeOverlay">true</item>
</style>
</resources>

Um estilo adicionais deve ser incluído na v21 valores pasta para aplicar as propriedades específicas ao executar
no Android Lollipop e mais recentes.
Resources/values-v21/style.xml

<resources>
<style name="MyTheme" parent="MyTheme.Base">
<!--If you are using MasterDetailPage you will want to set these, else you can leave them out-->
<!--<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>-->
</style>
</resources>

4. Update AndroidManifest.xml
Para garantir que esse novo tema informações são usado, definido tema na AndroidManifest arquivo
adicionando android:theme="@style/MyTheme" (deixe o restante do XML como ele era).
Properties/AndroidManifest.xml

...
<application android:label="AppName" android:icon="@drawable/icon"
android:theme="@style/MyTheme">
...

5. Forneça os layouts de barra de ferramentas e o guia


Crie Tabbar.axml e Toolbar.axml arquivos no recursos/layout diretório e colar em seu conteúdo de abaixo:
Resources/layout/Tabbar.axml

<android.support.design.widget.TabLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/sliding_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:tabIndicatorColor="@android:color/white"
app:tabGravity="fill"
app:tabMode="fixed" />

Algumas propriedades para as guias foram definidas incluindo a gravidade da guia para fill e o modo para
fixed . Se você tiver várias guias você talvez queira mudar isso para rolável - ler por meio do Android TabLayout
documentação para saber mais.
Resources/layout/Toolbar.axml

<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:layout_scrollFlags="scroll|enterAlways" />
Esses arquivos, estamos criando um tema específico para a barra de ferramentas que pode variar para seu
aplicativo. Consulte a barra de ferramentas Hello postagem de blog para saber mais.
6. Atualização do MainActivity

Em aplicativos do xamarin. Forms existentes a MainActivity.cs classe herda FormsApplicationActivity . Isso deve
ser substituído por FormsAppCompatActivity para habilitar a nova funcionalidade.
MainActivity.cs

public class MainActivity : FormsAppCompatActivity // was FormsApplicationActivity

Por fim, "conectar" novos layouts da etapa 5 no OnCreate método, conforme mostrado aqui:

protected override void OnCreate(Bundle bundle)


{
// set the layout resources first
FormsAppCompatActivity.ToolbarResource = Resource.Layout.Toolbar;
FormsAppCompatActivity.TabLayoutResource = Resource.Layout.Tabbar;

// then call base.OnCreate and the Xamarin.Forms methods


base.OnCreate(bundle);
Forms.Init(this, bundle);
LoadApplication(new App());
}
Preenchimento do botão e sombras no Android
12/04/2019 • 2 minutes to read

Baixar o exemplo
Este específicos da plataforma Android controla se os botões do xamarin. Forms usam o preenchimento padrão e
os valores de sombra dos botões do Android. Ele é consumido em XAML, definindo o Button.UseDefaultPadding e
Button.UseDefaultShadow propriedades para anexadas boolean valores:

<ContentPage ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core">
<StackLayout>
...
<Button ...
android:Button.UseDefaultPadding="true"
android:Button.UseDefaultShadow="true" />
</StackLayout>
</ContentPage>

Como alternativa, ele pode ser consumido de C# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...

button.On<Android>().SetUseDefaultPadding(true).SetUseDefaultShadow(true);

O Button.On<Android> método Especifica que este específicos da plataforma serão executado apenas no Android.
O Button.SetUseDefaultPadding e Button.SetUseDefaultShadow métodos, no
Xamarin.Forms.PlatformConfiguration.AndroidSpecific namespace, são usadas para controlar se os botões de
xamarin. Forms usam o padrão preenchimento e valores de sombra dos botões do Android. Além disso, o
Button.UseDefaultPadding e Button.UseDefaultShadow métodos podem ser usados para retornar se um botão usa o
padrão de preenchimento de valor e o valor padrão de sombra, respectivamente.
O resultado é que os botões de xamarin. Forms podem usar o preenchimento padrão e os valores de sombra dos
botões do Android:

Observe que, na captura de tela acima de cada Button tem definições idênticas, exceto que o direito Button usa o
preenchimento padrão e valores de sombra dos botões do Android.

Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
AndroidSpecific API
AndroidSpecific.AppCompat API
Opções do Editor de método de entrada de entrada
no Android
12/04/2019 • 3 minutes to read

Baixar o exemplo
Este específicos da plataforma Android define o método de entrada opções de IME (editor) para o teclado virtual
para um Entry . Isso inclui a definição no botão de ação do usuário no canto inferior do teclado virtual e as
interações com o Entry . Ele é consumido em XAML, definindo o Entry.ImeOptions propriedade anexada a um
valor da ImeFlags enumeração:

<ContentPage ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core">
<StackLayout ...>
<Entry ... android:Entry.ImeOptions="Send" />
...
</StackLayout>
</ContentPage>

Como alternativa, ele pode ser consumido de C# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...

entry.On<Android>().SetImeOptions(ImeFlags.Send);

O Entry.On<Android> método Especifica que este específicos da plataforma serão executado apenas no Android. O
Entry.SetImeOptions método, no Xamarin.Forms.PlatformConfiguration.AndroidSpecific namespace, é usado para
definir a opção de ação do método de entrada para o teclado virtual para o Entry , com o ImeFlags fornecendo
os seguintes valores de enumeração:
Default – indica que nenhuma chave de ação específica é necessária e que o controle subjacente produzirá o
seu próprio se possível. Isso será Next ou Done .
None – indica que nenhuma chave de ação será disponibilizado.
Go – indica que a chave de ação executará uma operação de "Ir", direcionando o usuário para o destino do
texto digitado.
Search – indica que a chave de ação executa uma operação de "Pesquisar", direcionando o usuário para os
resultados da pesquisa para o texto que tiver digitado.
Send – indica que a chave de ação executará uma operação de "Enviar", fornecendo o texto para seu destino.
Next – indica que a chave de ação executará uma operação de "next", direcionando o usuário para o próximo
campo que aceita texto.
Done – indica que a chave de ação executará uma operação de "done", fechando o teclado virtual.
Previous – indica que a chave de ação executará uma operação "anterior", direcionando o usuário para o
campo anterior que aceita texto.
ImeMaskAction – a máscara para selecionar opções de ação.
NoPersonalizedLearning – indica que o verificador ortográfico não saiba do usuário, nem sugerir correções com
base no qual o usuário tiver digitado anteriormente.
NoFullscreen – indica que a interface do usuário não deve estar em tela inteira.
NoExtractUi – indica que nenhuma interface do usuário será mostrada para texto extraído.
NoAccessoryAction – indica que nenhuma interface do usuário será exibido para ações personalizadas.

O resultado é que a especificada ImeFlags valor é aplicado para o teclado virtual para o Entry , que define o
método de entrada, as opções do editor:

Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
AndroidSpecific API
AndroidSpecific.AppCompat API
Sombras ImageButton no Android
12/04/2019 • 3 minutes to read

Baixar o exemplo
Este específicos da plataforma Android é usado para habilitar uma sombra em um ImageButton . Ele é consumido
em XAML, definindo o ImageButton.IsShadowEnabled para a propriedade associável true , junto com um número
opcional associável propriedades adicionais que controlam a sombra:

<ContentPage ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core">
<StackLayout Margin="20">
<ImageButton ...
Source="XamarinLogo.png"
BackgroundColor="GhostWhite"
android:ImageButton.IsShadowEnabled="true"
android:ImageButton.ShadowColor="Gray"
android:ImageButton.ShadowRadius="12">
<android:ImageButton.ShadowOffset>
<Size>
<x:Arguments>
<x:Double>10</x:Double>
<x:Double>10</x:Double>
</x:Arguments>
</Size>
</android:ImageButton.ShadowOffset>
</ImageButton>
...
</StackLayout>
</ContentPage>

Como alternativa, ele pode ser consumido de c# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...

var imageButton = new Xamarin.Forms.ImageButton { Source = "XamarinLogo.png", BackgroundColor =


Color.GhostWhite, ... };
imageButton.On<Android>()
.SetIsShadowEnabled(true)
.SetShadowColor(Color.Gray)
.SetShadowOffset(new Size(10, 10))
.SetShadowRadius(12);

IMPORTANT
Uma sombra é desenhada como parte do ImageButton em segundo plano e o plano de fundo é desenhada apenas se o
BackgroundColor propriedade está definida. Portanto, uma sombra não será desenhada se o
ImageButton.BackgroundColor propriedade não está definida.

O ImageButton.On<Android> método Especifica que este específicos da plataforma serão executado apenas no
Android. O ImageButton.SetIsShadowEnabled método, no Xamarin.Forms.PlatformConfiguration.AndroidSpecific
namespace, é usada para controlar se uma sombra está habilitada no ImageButton . Além disso, os métodos a
seguir podem ser invocados para controlar a sombra:
SetShadowColor – Define a cor da sombra. A cor padrão é Color.Default .
SetShadowOffset – Define o deslocamento da sombra. O deslocamento altera a direção da sombra é convertida
e é especificada como uma Size valor. O Size valores de estrutura são expressos em unidades
independentes de dispositivo, com o primeiro valor que está sendo a distância para a esquerda (valor negativo)
ou a direita (valor positivo) e o segundo valor sendo a distância acima (valor negativo) ou abaixo (valor
positivo) . O valor padrão dessa propriedade é (0,0, 0,0), que resulta na sombra que está sendo convertido em
torno de cada lado do ImageButton .
SetShadowRadius – Define o raio de desfoque usado para renderizar a sombra projetada. O valor de raio padrão
é 10.0.

NOTE
O estado de uma sombra pode ser consultado por meio da chamada a GetIsShadowEnabled , GetShadowColor ,
GetShadowOffset , e GetShadowRadius métodos.

O resultado é que uma sombra pode ser habilitada em um ImageButton :

Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
AndroidSpecific API
AndroidSpecific.AppCompat API
Fast de ListView, rolagem no Android
12/04/2019 • 2 minutes to read

Baixar o exemplo
Este específicos da plataforma Android é usado para habilitar a rolagem rápida por meio de dados em um
ListView . Ele é consumido em XAML, definindo o ListView.IsFastScrollEnabled anexado à propriedade um
boolean valor:

<ContentPage ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core">
<StackLayout Margin="20">
...
<ListView ItemsSource="{Binding GroupedEmployees}"
GroupDisplayBinding="{Binding Key}"
IsGroupingEnabled="true"
android:ListView.IsFastScrollEnabled="true">
...
</ListView>
</StackLayout>
</ContentPage>

Como alternativa, ele pode ser consumido de C# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...

var listView = new Xamarin.Forms.ListView { IsGroupingEnabled = true, ... };


listView.SetBinding(ItemsView<Cell>.ItemsSourceProperty, "GroupedEmployees");
listView.GroupDisplayBinding = new Binding("Key");
listView.On<Android>().SetIsFastScrollEnabled(true);

O ListView.On<Android> método Especifica que este específicos da plataforma serão executado apenas no
Android. O ListView.SetIsFastScrollEnabled método, no Xamarin.Forms.PlatformConfiguration.AndroidSpecific
namespace, é usado para habilitar a rolagem rápida por meio de dados em um ListView . Além disso, o
SetIsFastScrollEnabled método pode ser usado para ativar/desativar a rolagem rápida chamando o
IsFastScrollEnabled método para retornar se a rolagem rápida está habilitada:

listView.On<Android>().SetIsFastScrollEnabled(!listView.On<Android>().IsFastScrollEnabled());

O resultado é que rolagem rápida por meio de dados em um ListView pode ser habilitado, que altera o tamanho
de rolagem:
Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
AndroidSpecific API
AndroidSpecific.AppCompat API
Altura da barra de NavigationPage no Android
12/04/2019 • 2 minutes to read

Baixar o exemplo
Este específicos da plataforma Android define a altura da barra de navegação de um NavigationPage . Ele é
consumido em XAML, definindo o NavigationPage.BarHeight propriedade associável para um valor inteiro:

<NavigationPage ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific.AppCompat;assembly=Xamarin.Forms.Core"
android:NavigationPage.BarHeight="450">
...
</NavigationPage>

Como alternativa, ele pode ser consumido de c# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific.AppCompat;
...

public class AndroidNavigationPageCS : Xamarin.Forms.NavigationPage


{
public AndroidNavigationPageCS()
{
On<Android>().SetBarHeight(450);
}
}

O NavigationPage.On<Android> método Especifica que essa plataforma específica só será executada em


compatibilidade de aplicativos Android. O NavigationPage.SetBarHeight método, no
Xamarin.Forms.PlatformConfiguration.AndroidSpecific.AppCompat namespace, é usado para definir a altura da barra
de navegação em um NavigationPage . Além disso, o NavigationPage.GetBarHeight método pode ser usado para
retornar a altura da barra de navegação a NavigationPage .
O resultado é que a altura da barra de navegação em um NavigationPage podem ser definidos:
Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
AndroidSpecific API
AndroidSpecific.AppCompat API
Eventos de ciclo de vida de página no Android
12/04/2019 • 2 minutes to read

Baixar o exemplo
Este específicos da plataforma Android é usado para desabilitar o Disappearing e Appearing eventos de página
no aplicativo pausar e retomar, respectivamente, para aplicativos que usam AppCompat. Além disso, ele inclui a
capacidade de controlar se o teclado virtual é exibido ao continuar, se ele foi exibido em pausa, desde que o modo
de operação do teclado virtual é definido para WindowSoftInputModeAdjust.Resize .

NOTE
Observe que esses eventos são habilitados por padrão para preservar o comportamento existente para aplicativos que
dependem dos eventos. Desabilitar esses eventos faz com que o ciclo de eventos AppCompat corresponder o ciclo de evento
de pré-AppCompat.

Este específicos da plataforma podem ser consumidos em XAML, definindo o


Application.SendDisappearingEventOnPause , Application.SendAppearingEventOnResume , e
Application.ShouldPreserveKeyboardOnResume propriedades anexadas para boolean valores:

<Application ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
xmlns:androidAppCompat="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific.AppCompat;assembly=Xamarin.Forms.Core"
android:Application.WindowSoftInputModeAdjust="Resize"
androidAppCompat:Application.SendDisappearingEventOnPause="false"
androidAppCompat:Application.SendAppearingEventOnResume="false"
androidAppCompat:Application.ShouldPreserveKeyboardOnResume="true">
...
</Application>

Como alternativa, ele pode ser consumido de C# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific.AppCompat;
...

Xamarin.Forms.Application.Current.On<Android>()
.UseWindowSoftInputModeAdjust(WindowSoftInputModeAdjust.Resize)
.SendDisappearingEventOnPause(false)
.SendAppearingEventOnResume(false)
.ShouldPreserveKeyboardOnResume(true);

O Application.Current.On<Android> método Especifica que este específicos da plataforma serão executado apenas
no Android. O Application.SendDisappearingEventOnPause método, no
Xamarin.Forms.PlatformConfiguration.AndroidSpecific.AppCompat namespace, é usado para habilitar ou desabilitar o
acionamento de Disappearing eventos de página, quando o aplicativo entra em segundo plano. O
Application.SendAppearingEventOnResume método é usado para habilitar ou desabilitar o acionamento de
Appearing evento de página, quando o aplicativo é retomado do plano de fundo. O
Application.ShouldPreserveKeyboardOnResume método é usado o controle se o teclado virtual é exibido ao continuar,
se ele foi exibido em pausa, fornecido que o modo de operação do teclado virtual é definido como
WindowSoftInputModeAdjust.Resize .

O resultado é que o Disappearing e Appearing eventos de página não serão acionados em Pausar o aplicativo e
retomar, respectivamente, e o teclado virtual de que, se foi exibido quando o aplicativo foi colocado em pausa, ele
também será exibido quando o aplicativo é retomado:

Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
AndroidSpecific API
AndroidSpecific.AppCompat API
Modo de entrada de teclado virtual no Android
12/04/2019 • 2 minutes to read

Baixar o exemplo
Este específicos da plataforma Android é usado para definir o modo de operação para uma área de entrada do
teclado virtual e é consumido em XAML, definindo o Application.WindowSoftInputModeAdjust propriedade anexada
a um valor da WindowSoftInputModeAdjust enumeração:

<Application ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
android:Application.WindowSoftInputModeAdjust="Resize">
...
</Application>

Como alternativa, ele pode ser consumido de c# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...

App.Current.On<Android>().UseWindowSoftInputModeAdjust(WindowSoftInputModeAdjust.Resize);

O Application.On<Android> método Especifica que este específicos da plataforma serão executado apenas no
Android. O Application.UseWindowSoftInputModeAdjust método, no
Xamarin.Forms.PlatformConfiguration.AndroidSpecific namespace, é usado para definir o modo de operação de
área de entrada de teclado virtual, com o WindowSoftInputModeAdjust enumeração fornecendo dois valores: Pan e
Resize . O Pan valor usa o AdjustPan opção de ajuste, o que não redimensione a janela quando um controle de
entrada tem o foco. Em vez disso, o conteúdo da janela estendido para que o foco atual não é obscurecido pelo
teclado virtual. O Resize valor usa o AdjustResize opção de ajuste, que redimensiona a janela quando um
controle de entrada tem o foco, para liberar espaço para o teclado virtual.
O resultado é que o teclado virtual área modo operacional pode ser definido quando um controle de entrada tem
o foco de entrada:
Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
AndroidSpecific API
AndroidSpecific.AppCompat API
Página TabbedPage passar o dedo no Android
12/04/2019 • 2 minutes to read

Baixar o exemplo
Este específicos da plataforma Android é usado para habilitar o dedo com um gesto horizontal dedo entre páginas
em um TabbedPage . Ele é consumido em XAML, definindo o TabbedPage.IsSwipePagingEnabled anexado à
propriedade um boolean valor:

<TabbedPage ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
android:TabbedPage.OffscreenPageLimit="2"
android:TabbedPage.IsSwipePagingEnabled="true">
...
</TabbedPage>

Como alternativa, ele pode ser consumido de C# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...

On<Android>().SetOffscreenPageLimit(2)
.SetIsSwipePagingEnabled(true);

O TabbedPage.On<Android> método Especifica que este específicos da plataforma serão executado apenas no
Android. O TabbedPage.SetIsSwipePagingEnabled método, no Xamarin.Forms.PlatformConfiguration.AndroidSpecific
namespace, é usado para habilitar o dedo entre páginas em um TabbedPage . Além disso, o TabbedPage classe na
Xamarin.Forms.PlatformConfiguration.AndroidSpecific namespace também tem um EnableSwipePaging método
que permite que esse específicos da plataforma, e uma DisableSwipePaging método desabilita Essa plataforma
específica. O TabbedPage.OffscreenPageLimit propriedade anexada e SetOffscreenPageLimit método, são usadas
para definir o número de páginas que devem ser mantidos em um estado ocioso em ambos os lados da página
atual.
O resultado é que paginação passe o dedo para as páginas exibidas por um TabbedPage está habilitado:

Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
AndroidSpecific API
AndroidSpecific.AppCompat API
Animações de transição de página TabbedPage no
Android
12/04/2019 • 2 minutes to read

Baixar o exemplo
Este específicos da plataforma Android é usado para desabilitar animações de transição ao navegar pelas páginas,
seja programaticamente ou ao usar a barra de guias, em um TabbedPage . Ele é consumido em XAML, definindo o
TabbedPage.IsSmoothScrollEnabled para a propriedade associável false :

<TabbedPage ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
android:TabbedPage.IsSmoothScrollEnabled="false">
...
</TabbedPage>

Como alternativa, ele pode ser consumido de C# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...

On<Android>().SetIsSmoothScrollEnabled(false);

O TabbedPage.On<Android> método Especifica que este específicos da plataforma serão executado apenas no
Android. O TabbedPage.SetIsSmoothScrollEnabled método, no
Xamarin.Forms.PlatformConfiguration.AndroidSpecific namespace, é usada para controlar se as animações de
transição serão exibidas quando navegar entre páginas em um TabbedPage . Além disso, o TabbedPage classe o
Xamarin.Forms.PlatformConfiguration.AndroidSpecific namespace também tem os seguintes métodos:

IsSmoothScrollEnabled , que é usada para recuperar se animações de transição serão exibidas quando navegar
entre páginas em um TabbedPage .
EnableSmoothScroll , que é usado para habilitar animações de transição ao navegar entre páginas em um
TabbedPage .
DisableSmoothScroll , que é usado para desabilitar animações de transição ao navegar entre páginas em um
TabbedPage .

Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
AndroidSpecific API
AndroidSpecific.AppCompat API
Posicionamento da barra de ferramentas
TabbedPage e cor no Android
12/04/2019 • 2 minutes to read

Baixar o exemplo
Esses itens específicos à plataforma são usadas para definir o posicionamento e a cor da barra de ferramentas em
uma TabbedPage . Eles são consumidos no XAML, definindo o TabbedPage.ToolbarPlacement propriedade anexada
a um valor da ToolbarPlacement enumeração e o TabbedPage.BarItemColor e TabbedPage.BarSelectedItemColor
anexado propriedades para um Color :

<TabbedPage ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
android:TabbedPage.ToolbarPlacement="Bottom"
android:TabbedPage.BarItemColor="Black"
android:TabbedPage.BarSelectedItemColor="Red">
...
</TabbedPage>

Como alternativa, eles podem ser consumidos em C# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...

On<Android>().SetToolbarPlacement(ToolbarPlacement.Bottom)
.SetBarItemColor(Color.Black)
.SetBarSelectedItemColor(Color.Red);

O TabbedPage.On<Android> método Especifica que esses itens específicos à plataforma será executado apenas no
Android. O TabbedPage.SetToolbarPlacement método, no Xamarin.Forms.PlatformConfiguration.AndroidSpecific
namespace, é usado para definir o posicionamento da barra de ferramentas em um TabbedPage , com o
ToolbarPlacement fornecendo os seguintes valores de enumeração:

Default – indica que a barra de ferramentas é colocada no local padrão na página. Esta é a parte superior da
página em telefones e a parte inferior da página em outros idiomas de dispositivo.
Top – indica que a barra de ferramentas é colocada na parte superior da página.
Bottom – indica que a barra de ferramentas é colocada na parte inferior da página.

Além disso, o TabbedPage.SetBarItemColor e TabbedPage.SetBarSelectedItemColor métodos são usados para definir


a cor dos itens da barra de ferramentas e itens de barra de ferramentas selecionado, respectivamente.

NOTE
O GetToolbarPlacement , GetBarItemColor , e GetBarSelectedItemColor métodos podem ser usados para recuperar
o posicionamento e as cores a TabbedPage barra de ferramentas.

O resultado é que o posicionamento da barra de ferramentas, a cor dos itens da barra de ferramentas e a cor do
item da barra de ferramentas selecionado podem ser definidas em um TabbedPage :
Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
AndroidSpecific API
AndroidSpecific.AppCompat API
Elevação VisualElement no Android
12/04/2019 • 2 minutes to read

Baixar o exemplo
Este específicos da plataforma Android é usado para controlar a ordem Z, de elementos visuais em aplicativos ou
a elevação destinados API 21 ou maior. A elevação de um elemento visual determina sua ordem de desenho, com
elementos visuais com valores mais altos de Z occluding elementos visuais com baixos valores de Z. Ele é
consumido em XAML, definindo o VisualElement.Elevation anexado à propriedade um boolean valor:

<ContentPage ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
Title="Elevation">
<StackLayout>
<Grid>
<Button Text="Button Beneath BoxView" />
<BoxView Color="Red" Opacity="0.2" HeightRequest="50" />
</Grid>
<Grid Margin="0,20,0,0">
<Button Text="Button Above BoxView - Click Me" android:VisualElement.Elevation="10"/>
<BoxView Color="Red" Opacity="0.2" HeightRequest="50" />
</Grid>
</StackLayout>
</ContentPage>

Como alternativa, ele pode ser consumido de c# usando a API fluente:


using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...

public class AndroidElevationPageCS : ContentPage


{
public AndroidElevationPageCS()
{
...
var aboveButton = new Button { Text = "Button Above BoxView - Click Me" };
aboveButton.On<Android>().SetElevation(10);

Content = new StackLayout


{
Children =
{
new Grid
{
Children =
{
new Button { Text = "Button Beneath BoxView" },
new BoxView { Color = Color.Red, Opacity = 0.2, HeightRequest = 50 }
}
},
new Grid
{
Margin = new Thickness(0,20,0,0),
Children =
{
aboveButton,
new BoxView { Color = Color.Red, Opacity = 0.2, HeightRequest = 50 }
}
}
}
};
}
}

O Button.On<Android> método Especifica que este específicos da plataforma serão executado apenas no Android.
O VisualElement.SetElevation método, no Xamarin.Forms.PlatformConfiguration.AndroidSpecific namespace, é
usado para definir a elevação do elemento visual como um valor anulável float . Além disso, o
VisualElement.GetElevation método pode ser usado para recuperar o valor de elevação de um elemento visual.

O resultado é que a elevação de elementos visuais pode ser controlada, de modo que os elementos visuais com
valores de Z maior occlude elementos visuais com baixos valores de Z. Portanto, no exemplo a segunda Button é
renderizado acima a BoxView porque ele tem um valor mais alto de elevação:
Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
AndroidSpecific API
AndroidSpecific.AppCompat API
Modo de cor VisualElement herdado no Android
12/04/2019 • 2 minutes to read

Baixar o exemplo
Algumas das exibições de xamarin. Forms apresentam um modo de cor herdado. Nesse modo, quando o
IsEnabled propriedade do modo de exibição é definida como false , o modo de exibição substituirá as cores
definidas pelo usuário com os nativo as cores padrão para o estado desabilitado. Para versões anteriores
compatibilidade, esse modo herdado cor permanece o comportamento padrão para modos de exibição com
suporte.
Este específicos da plataforma Android desabilita nesse modo herdado de cor, para que permaneçam de cores
definido em uma exibição pelo usuário, mesmo quando o modo de exibição está desabilitado. Ele é consumido em
XAML, definindo o VisualElement.IsLegacyColorModeEnabled anexado à propriedade false :

<ContentPage ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core">
<StackLayout>
...
<Button Text="Button"
TextColor="Blue"
BackgroundColor="Bisque"
android:VisualElement.IsLegacyColorModeEnabled="False" />
...
</StackLayout>
</ContentPage>

Como alternativa, ele pode ser consumido de c# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...

_legacyColorModeDisabledButton.On<Android>().SetIsLegacyColorModeEnabled(false);

O VisualElement.On<Android> método Especifica que este específicos da plataforma serão executado apenas no
Android. O VisualElement.SetIsLegacyColorModeEnabled método, no
Xamarin.Forms.PlatformConfiguration.AndroidSpecific namespace, é usada para controlar se o modo de cor
herdados é desabilitado. Além disso, o VisualElement.GetIsLegacyColorModeEnabled método pode ser usado para
retornar se o modo de cor herdado está desabilitado.
O resultado é que o modo herdado de cor pode ser desabilitado, para que as cores definidas em uma exibição pelo
usuário permaneçam até mesmo quando o modo de exibição está desabilitado:
NOTE
Ao definir uma VisualStateGroup em uma exibição, o modo herdado de cor é totalmente ignorado. Para obter mais
informações sobre estados visuais, consulte o Gerenciador de estado Visual xamarin. Forms.

Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
AndroidSpecific API
AndroidSpecific.AppCompat API
WebView conteúdo no Android misturadas
12/04/2019 • 2 minutes to read

Baixar o exemplo
Este específicos da plataforma Android controla se um WebView pode exibir conteúdo misto em aplicativos
destinados a API 21 ou maior. Conteúdo misto é que é inicialmente carregada em uma conexão HTTPS, mas que
carrega os recursos (como imagens, áudio, vídeo, folhas de estilo, scripts) em uma conexão HTTP. Ele é consumido
em XAML, definindo o WebView.MixedContentMode propriedade anexada a um valor da MixedContentHandling
enumeração:

<ContentPage ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core">
<WebView ... android:WebView.MixedContentMode="AlwaysAllow" />
</ContentPage>

Como alternativa, ele pode ser consumido de c# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...

webView.On<Android>().SetMixedContentMode(MixedContentHandling.AlwaysAllow);

O WebView.On<Android> método Especifica que este específicos da plataforma serão executado apenas no Android.
O WebView.SetMixedContentMode método, no Xamarin.Forms.PlatformConfiguration.AndroidSpecific namespace, é
usada para controlar se o conteúdo misto pode ser exibido, com o MixedContentHandling enumeração fornecendo
três valores possíveis:
AlwaysAllow – indica que o WebView permitirá que uma origem HTTPS carregar conteúdo de uma origem
HTTP.
NeverAllow – indica que o WebView não permitirá que uma origem HTTPS carregar conteúdo de uma origem
HTTP.
CompatibilityMode – indica que o WebView tentará ser compatível com a abordagem do navegador da web
mais recente do dispositivo. Parte do conteúdo HTTP poderá ter permissão para ser carregado por uma origem
HTTPS e outros tipos de conteúdo serão bloqueados. Os tipos de conteúdo que são bloqueados ou permitidos
podem ser alterados a cada versão do sistema operacional.
O resultado é que a especificada MixedContentHandling valor é aplicado para o WebView , que controla se o
conteúdo misto pode ser exibido:
Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
AndroidSpecific API
AndroidSpecific.AppCompat API
Classe de dispositivo do xamarin. Forms
12/04/2019 • 9 minutes to read

baixar o exemplo
O Device classe contém um número de propriedades e métodos para ajudar os desenvolvedores personalizar o
layout e a funcionalidade em uma base por plataforma.
Além dos métodos e propriedades para o código de destino em tipos específicos de hardware e tamanhos, o
Device classe inclui o BeginInvokeOnMainThread método que deve ser usado ao interagir com a interface do
usuário controla de threads em segundo plano.

Fornecer valores específicos da plataforma


Antes do xamarin. Forms 2.3.4, a plataforma que o aplicativo estava em execução no poderia ser obtida
examinando os Device.OS propriedade e compará-lo para o TargetPlatform.iOS , TargetPlatform.Android ,
TargetPlatform.WinPhone , e TargetPlatform.Windows valores de enumeração. Da mesma forma, um dos
Device.OnPlatform sobrecargas pode ser usadas para fornecer valores específicos da plataforma para um
controle.
No entanto, desde o xamarin. Forms 2.3.4 essas APIs foram preteridas e substituídas. O Device classe agora
contém constantes de cadeia de caracteres pública que identificam as plataformas – Device.iOS ,
Device.Android , Device.WinPhone ( preterido), Device.WinRT (preterido) Device.UWP , e Device.macOS . Da
mesma forma, o Device.OnPlatform sobrecargas foram substituídas com o OnPlatform e On APIs.
No C#, valores específicos de plataforma podem ser fornecidos com a criação de um switch instrução sobre o
Device.RuntimePlatform propriedade e, em seguida, fornecendo case instruções para as plataformas
necessárias:

double top;
switch (Device.RuntimePlatform)
{
case Device.iOS:
top = 20;
break;
case Device.Android:
case Device.UWP:
default:
top = 0;
break;
}
layout.Margin = new Thickness(5, top, 5, 0);

O OnPlatform e On classes fornecem a mesma funcionalidade em XAML:


<StackLayout>
<StackLayout.Margin>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="0,20,0,0" />
<On Platform="Android, UWP" Value="0,0,0,0" />
</OnPlatform>
</StackLayout.Margin>
...
</StackLayout>

O OnPlatform é uma classe genérica que deve ser instanciada com um x:TypeArguments atributo que
corresponde ao tipo de destino. No On classe, o Platform atributo pode aceitar um único string valor ou
vários delimitada por vírgula string valores.

IMPORTANT
Fornecendo um incorreto Platform valor no atributo de On classe não resultará em erro. Em vez disso, o código será
executado sem o valor específico da plataforma que está sendo aplicado.

Como alternativa, o OnPlatform extensão de marcação pode ser usada em XAML para personalizar a aparência
da interface do usuário em uma base por plataforma. Para obter mais informações, consulte extensão de
marcação OnPlatform.

Device.Idiom
O Device.Idiom propriedade pode ser usada para alterar os layouts ou funcionalidade dependendo do
dispositivo em que o aplicativo está em execução no. O TargetIdiom enumeração contém os seguintes valores:
Telefone – iPhone, iPod touch e dispositivos Android mais estreitos do que 600 quedas ^
Tablet – iPad, dispositivos Windows e dispositivos Android mais de 600 quedas ^
Área de trabalho – somente retornado no aplicativos da UWP em computadores desktop do Windows 10
(retorna Phone em dispositivos móveis do Windows, incluindo em cenários de continuidade)
TV – dispositivos Tizen TV
Assista – Tizen dispositivos de inspeção
Não há suporte para – não utilizados
^ dips não é necessariamente a contagem de pixel físico
O Idiom propriedade é especialmente útil para a criação de layouts que tiram proveito de telas maiores, como
este:

if (Device.Idiom == TargetIdiom.Phone) {
// layout views vertically
} else {
// layout views horizontally for a larger display (tablet or desktop)
}

O OnIdiom classe fornece a mesma funcionalidade em XAML:


<StackLayout>
<StackLayout.Margin>
<OnIdiom x:TypeArguments="Thickness">
<OnIdiom.Phone>0,20,0,0</OnIdiom.Phone>
<OnIdiom.Tablet>0,40,0,0</OnIdiom.Tablet>
<OnIdiom.Desktop>0,60,0,0</OnIdiom.Desktop>
</OnIdiom>
</StackLayout.Margin>
...
</StackLayout>

O OnIdiom é uma classe genérica que deve ser instanciada com um x:TypeArguments atributo que corresponde
ao tipo de destino.
Como alternativa, o OnIdiom extensão de marcação pode ser usada em XAML para personalizar a aparência da
interface do usuário com base no idioma do dispositivo em que o aplicativo está sendo executado. Para obter
mais informações, consulte extensão de marcação OnIdiom.

Device.FlowDirection
O Device.FlowDirection valor recupera uma FlowDirection valor de enumeração que representa a direção do
fluxo atual que está sendo usada pelo dispositivo. A direção do fluxo é a direção na qual os elementos de
interface do usuário na página são detectados pelos olhos. Os valores de enumeração são:
LeftToRight
RightToRight
MatchParent

No XAML, o Device.FlowDirection valor pode ser recuperado usando o x:Static extensão de marcação:

<ContentPage ... FlowDirection="{x:Static Device.FlowDirection}"> />

O código equivalente no C# é:

this.FlowDirection = Device.FlowDirection;

Para obter mais informações sobre a direção do fluxo, consulte localização da direita para esquerda.

Device.Styles
O Styles propriedade contém as definições de estilo interno que podem ser aplicadas a alguns dos controles
(como Label ) Style propriedade. Os estilos disponíveis são:
BodyStyle
CaptionStyle
ListItemDetailTextStyle
ListItemTextStyle
SubtitleStyle
TitleStyle

Device.GetNamedSize
GetNamedSize pode ser usado ao definir FontSize em C# código:
myLabel.FontSize = Device.GetNamedSize (NamedSize.Small, myLabel);
someLabel.FontSize = Device.OnPlatform (
24, // hardcoded size
Device.GetNamedSize (NamedSize.Medium, someLabel),
Device.GetNamedSize (NamedSize.Large, someLabel)
);

Device.OpenUri
O OpenUri método pode ser usado para disparar operações na plataforma subjacente, como abrir uma URL no
navegador da web nativos (Safari no iOS ou Internet no Android).

Device.OpenUri(new Uri("https://evolve.xamarin.com/"));

O amostra WebView inclui um exemplo do uso OpenUri para abrir URLs e também disparar chamadas
telefônicas.
O exemplo de mapas também usa Device.OpenUri para exibir mapas e das direções usando nativo mapeia
aplicativos no iOS e Android.

Device.StartTimer
O Device classe também tem um StartTimer método que fornece uma maneira simple para disparar tarefas
dependentes de tempo que funciona em código comum do xamarin. Forms, incluindo uma biblioteca .NET
Standard. Passar uma TimeSpan para definir o intervalo e retornar true para manter a execução do
temporizador ou false para interrompê-la depois da chamada atual.

Device.StartTimer (new TimeSpan (0, 0, 60), () => {


// do something every 60 seconds
return true; // runs again, or false to stop
});

Se o código dentro do temporizador interage com a interface do usuário (como definir o texto de um Label ou
exibindo um alerta) deve ser feita dentro de um BeginInvokeOnMainThread expressão (veja abaixo).

Device.BeginInvokeOnMainThread
Elementos da interface do usuário nunca devem ser acessados por threads em segundo plano, como o código
em execução em um temporizador ou um manipulador de conclusão para operações assíncronas, como
solicitações da web. Qualquer código em segundo plano que precisa atualizar a interface do usuário deve ser
encapsulado dentro de BeginInvokeOnMainThread . Este é o equivalente de InvokeOnMainThread no iOS,
RunOnUiThread no Android, e Dispatcher.RunAsync na plataforma Universal do Windows.

O código do xamarin. Forms é:

Device.BeginInvokeOnMainThread ( () => {
// interact with UI elements
});

Observe que usando os métodos async/await não é necessário usar BeginInvokeOnMainThread se eles estão em
execução do thread principal da interface do usuário.
Resumo
O xamarin. Forms Device classe permite controle refinado sobre layouts e funcionalidade em uma base por
plataforma – até mesmo o código (projetos da biblioteca .NET Standard ou projetos compartilhados) em
comum.

Links relacionados
Exemplo de dispositivo
Exemplo de estilos
Dispositivo
recursos da plataforma iOS no xamarin. Forms
12/04/2019 • 6 minutes to read

Desenvolvimento de aplicativos xamarin. Forms para iOS requer o Visual Studio. O página de requisitos contém
mais informações sobre os pré-requisitos.

Especificidades da plataforma
Especificidades da plataforma permitem que você consumir funcionalidade só está disponível em uma plataforma
específica, sem implementar renderizadores personalizados ou efeitos.
A seguinte funcionalidade específica da plataforma é fornecida para exibições do xamarin. Forms, páginas e
layouts no iOS:
Suporte para qualquer um de desfoque VisualElement . Para obter mais informações, consulte VisualElement
desfoque no iOS.
Desabilitar o modo de cor herdados em um com suporte VisualElement . Para obter mais informações,
consulte modo de cor VisualElement herdado no iOS.
Habilitando uma sombra em um VisualElement . Para obter mais informações, consulte VisualElement Drop
sombras no iOS.
A seguinte funcionalidade específica da plataforma é fornecida para modos de exibição do xamarin. Forms no iOS:
Definindo o Cell cor do plano de fundo. Para obter mais informações, consulte cor de plano de fundo da
célula no iOS.
Garantir que inseridos texto se adapta a um Entry ajustando o tamanho da fonte. Para obter mais
informações, consulte tamanho da fonte de entrada no iOS.
Configurando a cor do cursor uma Entry . Para obter mais informações, consulte entrada de cor do Cursor no
iOS.
Controlando se ListView células de cabeçalho float durante a rolagem. Para obter mais informações, consulte
ListView estilo do cabeçalho de grupo no iOS.
Controlar se as animações de linha estão desabilitadas quando o ListView coleção de itens está sendo
atualizada. Para obter mais informações, consulte ListView linha animações no iOS.
Definindo o estilo do separador em um ListView . Para obter mais informações, consulte ListView estilo do
separador no iOS.
Controlando quando a seleção de item ocorre em um Picker . Para obter mais informações, consulte seletor
de seleção de Item no iOS.
Habilitando a Slider.Value propriedade a ser definido tocando em uma posição no Slider barra, em vez de
precisar arrastar o Slider thumb. Para obter mais informações, consulte controle deslizante Thumb toque no
iOS.
A seguinte funcionalidade específica da plataforma é fornecida para páginas do xamarin. Forms no iOS:
Ocultando o separador de barra de navegação em um NavigationPage . Para obter mais informações, consulte
NavigationPage separador de barra no iOS.
Controlar se a barra de navegação é translúcida. Para obter mais informações, consulte Translucência da barra
de navegação no iOS.
Controlar se o texto da barra de status de cor em um NavigationPage é ajustado para coincidir com a
luminosidade da barra de navegação. Para obter mais informações, consulte modo de cor de texto
NavigationPage barra no iOS.
Controlar se o título da página é exibido como um título grande na barra de navegação de página. Para obter
mais informações, consulte títulos de página grande no iOS.
Definindo a visibilidade da barra de status em uma Page . Para obter mais informações, consulte página de
visibilidade da barra de Status no iOS.
Garantir que esse conteúdo da página está posicionado em uma área da tela que é segura para todos os
dispositivos iOS. Para obter mais informações, consulte guia do Layout da área de segurança no iOS.
Definindo o estilo de apresentação de páginas modais em um iPad. Para obter mais informações, consulte iPad
estilo de apresentação de página Modal.
A seguinte funcionalidade específica da plataforma é fornecida para layouts do xamarin. Forms no iOS:
Controlar se uma ScrollView manipula um gesto de toque ou passá-lo ao seu conteúdo. Para obter mais
informações, consulte ScrollView toques de conteúdo no iOS.
A seguinte funcionalidade específica da plataforma é fornecida para o xamarin. Forms Application classe no iOS:
Habilitando o controle de layout e renderização atualizações a serem executadas no thread principal. Para obter
mais informações, consulte atualizações de controle do Thread principal no iOS.
Habilitando um PanGestureRecognizer em uma exibição de rolagem para capturar e compartilhar o gesto de
panorâmica com o modo de exibição de rolagem. Para obter mais informações, consulte simultâneas
reconhecimento de gesto de panorâmica no iOS.

formatação específica do iOS


Xamarin. Forms permite que os estilos de interface do usuário de plataforma cruzada e cores a ser definida - mas
há outras opções para definir o tema do iOS usando as APIs da plataforma no projeto do iOS.
Leia mais sobre a formatação de interface do usuário usando as APIs do iOS específicas, como Info. plist
configuração e o UIAppearance API.

Outros recursos do iOS


Usando o renderizadores personalizados, o DependencyServicee o MessagingCenter, é possível incorporar uma
ampla variedade de funcionalidade nativa em Aplicativos xamarin. Forms para iOS.
Cor do plano de fundo de célula no iOS
12/04/2019 • 2 minutes to read

Baixar o exemplo
Este específicos da plataforma iOS define a cor de plano de fundo padrão do Cell instâncias. Ele é consumido em
XAML, definindo o Cell.DefaultBackgroundColor propriedade associável a uma Color :

<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core">
<StackLayout Margin="20">
<ListView ItemsSource="{Binding GroupedEmployees}"
IsGroupingEnabled="true">
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell ios:Cell.DefaultBackgroundColor="Teal">
<Label Margin="10,10"
Text="{Binding Key}"
FontAttributes="Bold" />
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
...
</ListView>
</StackLayout>
</ContentPage>

Como alternativa, ele pode ser consumido de c# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...

var viewCell = new ViewCell { View = ... };


viewCell.On<iOS>().SetDefaultBackgroundColor(Color.Teal);

O ListView.On<iOS> método Especifica que este específicos da plataforma serão executado apenas no iOS. O
Cell.SetDefaultBackgroundColor método, no Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace, define
a cor de plano de fundo da célula para determinado Color . Além disso, o Cell.DefaultBackgroundColor método
pode ser usado para recuperar a cor de plano de fundo da célula atual.
O resultado é que a cor do plano de fundo em um Cell pode ser definido para um determinado Color :
Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
iOSSpecific API
Cor do Cursor de entrada no iOS
12/04/2019 • 2 minutes to read

Baixar o exemplo
Este específicos da plataforma define a cor do cursor de um Entry como uma cor especificada. Ele é consumido
em XAML, definindo o Entry.CursorColor propriedade associável a uma Color :

<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core">
<StackLayout>
<Entry ... ios:Entry.CursorColor="LimeGreen" />
</StackLayout>
</ContentPage>

Como alternativa, ele pode ser consumido de c# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...

var entry = new Xamarin.Forms.Entry();


entry.On<iOS>().SetCursorColor(Color.LimeGreen);

O Entry.On<iOS> método Especifica que este específicos da plataforma serão executado apenas no iOS. O
Entry.SetCursorColor método, no Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace, define a cor do
cursor para um especificados Color . Além disso, o Entry.GetCursorColor método pode ser usado para recuperar
a cor atual do cursor.
O resultado é que a cor do cursor em uma Entry pode ser definido para um determinado Color :

Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
iOSSpecific API
Tamanho da fonte de entrada no iOS
12/04/2019 • 2 minutes to read

Baixar o exemplo
Este específicos da plataforma iOS é usado para dimensionar o tamanho da fonte de um Entry para garantir que
o texto de valores se encaixa no controle. Ele é consumido em XAML, definindo o
Entry.AdjustsFontSizeToFitWidth anexado à propriedade um boolean valor:

<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
<StackLayout Margin="20">
<Entry x:Name="entry"
Placeholder="Enter text here to see the font size change"
FontSize="22"
ios:Entry.AdjustsFontSizeToFitWidth="true" />
...
</StackLayout>
</ContentPage>

Como alternativa, ele pode ser consumido de C# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...

entry.On<iOS>().EnableAdjustsFontSizeToFitWidth();

O Entry.On<iOS> método Especifica que este específicos da plataforma serão executado apenas no iOS. O
Entry.EnableAdjustsFontSizeToFitWidth método, no Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace,
é usado para dimensionar o tamanho da fonte do texto para garantir que ela se encaixa valores de Entry . Além
disso, o Entry classe o Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace também tem um
DisableAdjustsFontSizeToFitWidth método que desabilita essa específicos da plataforma, e um
SetAdjustsFontSizeToFitWidth método que pode ser usado para ativar/desativar o tamanho da fonte
dimensionamento chamando o AdjustsFontSizeToFitWidth método:

entry.On<iOS>().SetAdjustsFontSizeToFitWidth(!entry.On<iOS>().AdjustsFontSizeToFitWidth());

O resultado é que o tamanho da fonte de Entry é dimensionado para garantir que o texto de valores se encaixa
no controle:

Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
iOSSpecific API
Adicionando formatação específica do iOS
12/04/2019 • 4 minutes to read

Uma maneira de definir específico do iOS formatação é criar uma renderizador personalizado para um controle e
definir estilos de específico da plataforma e cores para cada plataforma.
Outras opções para controlar a aparência do aplicativo iOS xamarin. Forms incluem:
Configurando opções de exibição Info. plist
Definindo estilos de controle por meio de UIAppearance API
Essas alternativas são discutidas abaixo.

Personalizando o Info. plist


O Info. plist arquivo lhe permite configurar alguns aspectos do renderering de um aplicativo iOS, como a barra
de status é exibida como (e se).
Por exemplo, o exemplo de tarefas pendentes usa o código a seguir para definir a barra de cor e a cor do texto de
navegação em todas as plataformas:

var nav = new NavigationPage (new TodoListPage ());


nav.BarBackgroundColor = Color.FromHex("91CA47");
nav.BarTextColor = Color.White;

O resultado é mostrado no trecho de tela abaixo. Observe que os itens da barra de status são pretos (isso não
pode ser definido dentro do xamarin. Forms porque ele é um recurso específico da plataforma).

O ideal é que a barra de status também seria branca – algo que podemos pode realizar diretamente no projeto do
iOS. Adicione as seguintes entradas para o Info. plist para forçar a barra de status para ser branco:

ou editar correspondente Info. plist arquivo diretamente para incluir:

<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleLightContent</string>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>

Agora, quando o aplicativo é executado, a barra de navegação é verde e seu texto é branco (devido à formatação
de xamarin. Forms) e o texto da barra de status também é brancas, graças à configuração específica do iOS:
UIAppearance API
O UIAppearance API pode ser usado para definir propriedades visuais em vários controles de iOS sem precisar
criar um renderizador personalizado.
Adição de uma única linha de código para o AppDelegate.cs FinishedLaunching método pode definir o estilo de
todos os controles de um determinado tipo usando seu Appearance propriedade. O código a seguir contém dois
exemplos - globalmente a guia de definição de estilo de barra e alterne o controle:
AppDelegate.cs no projeto iOS

public override bool FinishedLaunching (UIApplication app, NSDictionary options)


{
// tab bar
UITabBar.Appearance.SelectedImageTintColor = UIColor.FromRGB(0x91, 0xCA, 0x47); // green
// switch
UISwitch.Appearance.OnTintColor = UIColor.FromRGB(0x91, 0xCA, 0x47); // green
// required Xamarin.Forms code
Forms.Init ();
LoadApplication (new App ());
return base.FinishedLaunching (app, options);
}

UITabBar
Por padrão, o ícone da barra de guia selecionada em um TabbedPage seria azul:

Para alterar esse comportamento, defina o UITabBar.Appearance propriedade:

UITabBar.Appearance.SelectedImageTintColor = UIColor.FromRGB(0x91, 0xCA, 0x47); // green

Isso faz com que a guia selecionada ser verde:

Usar essa API permite que você personalize a aparência do xamarin. Forms TabbedPage no iOS com muito pouco
código. Consulte a receita Personalizar guias para obter mais detalhes sobre como usar um renderizador
personalizado para definir uma fonte específica para a guia.
UISwitch
O Switch controle é outro exemplo que pode ser estilizado facilmente:

UISwitch.Appearance.OnTintColor = UIColor.FromRGB(0x91, 0xCA, 0x47); // green

Essas capturas de tela de dois mostram o padrão UISwitch controle à esquerda e a versão personalizada
(configuração Appearance ) à direita na exemplo de tarefas pendentes:
Outros controles
Muitos controles de interface do usuário iOS podem ter suas cores padrão e outros atributos definidos usando o
UIAppearance API.

Links relacionados
UIAppearance
Personalizar guias
Estilo de apresentação de página Modal do iPad
12/04/2019 • 2 minutes to read

Baixar o exemplo
Este específicos da plataforma iOS é usado para definir o estilo de apresentação de uma página modal em um
iPad. Ele é consumido em XAML, definindo o Page.ModalPresentationStyle propriedade associável a uma
UIModalPresentationStyle valor de enumeração:

<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
ios:Page.ModalPresentationStyle="FormSheet">
...
</ContentPage>

Como alternativa, ele pode ser consumido de c# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...

public class iOSModalFormSheetPageCS : ContentPage


{
public iOSModalFormSheetPageCS()
{
On<iOS>().SetModalPresentationStyle(UIModalPresentationStyle.FormSheet);
...
}
}

O Page.On<iOS> método Especifica que este específicos da plataforma serão executado apenas no iOS. O
Page.SetModalPresentationStyle método, no Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace, é usado
para definir o estilo de apresentação modal em um Page especificando um dos seguintes
UIModalPresentationStyle enumeração valores:

FullScreen , que define o estilo de apresentação modal para abranger a tela inteira. Por padrão, as páginas
modais são exibidas usando esse estilo de apresentação.
FormSheet , que define o estilo de apresentação modal seja menor do que a tela e centralizada no.

Além disso, o método pode ser usado para recuperar o valor atual do
GetModalPresentationStyle
UIModalPresentationStyle enumeração é aplicada para o Page .
O resultado é que o estilo de apresentação modal em uma Page podem ser definidos:
NOTE
As páginas que usam esse específicos da plataforma para definir o estilo de apresentação modal devem usar a navegação
modal. Para obter mais informações, consulte páginas modais do xamarin. Forms.

Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
iOSSpecific API
Títulos de página grande no iOS
12/04/2019 • 3 minutes to read

Baixar o exemplo
Este específicos da plataforma iOS é usado para exibir o título da página como um título grande na barra de
navegação de um NavigationPage , para dispositivos que usam iOS 11 ou superior. Um título grande é alinhado à
esquerda e usa uma fonte maior e faz a transição para um título padrão conforme o usuário começa a rolagem de
conteúdo, para que o espaço na tela é usado com eficiência. No entanto, em orientação paisagem, o título
retornará para o centro da barra de navegação para otimizar o layout do conteúdo. Ele é consumido em XAML,
definindo o NavigationPage.PrefersLargeTitles anexado à propriedade um boolean valor:

<NavigationPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
...
ios:NavigationPage.PrefersLargeTitles="true">
...
</NavigationPage>

Como alternativa, ele pode ser consumido de C# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...

var navigationPage = new Xamarin.Forms.NavigationPage(new iOSLargeTitlePageCS());


navigationPage.On<iOS>().SetPrefersLargeTitles(true);

O NavigationPage.On<iOS> método Especifica que este específicos da plataforma serão executado apenas no iOS.
O NavigationPage.SetPrefersLargeTitle método, no Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace,
que controla se os títulos grandes estão habilitados.
Desde que os títulos grandes estão habilitados na NavigationPage , todas as páginas na pilha de navegação serão
exibir títulos grandes. Esse comportamento pode ser substituído nas páginas, definindo o Page.LargeTitleDisplay
propriedade anexada a um valor da LargeTitleDisplayMode enumeração:

<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
Title="Large Title"
ios:Page.LargeTitleDisplay="Never">
...
</ContentPage>

Como alternativa, o comportamento de página pode ser substituído no C# usando a API fluente:
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...

public class iOSLargeTitlePageCS : ContentPage


{
public iOSLargeTitlePageCS(ICommand restore)
{
On<iOS>().SetLargeTitleDisplay(LargeTitleDisplayMode.Never);
...
}
...
}

O Page.On<iOS> método Especifica que este específicos da plataforma serão executado apenas no iOS. O
Page.SetLargeTitleDisplay método, no Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace, controla o
comportamento de título grande no Page , com o LargeTitleDisplayMode fornecendo três possíveis de
enumeração valores:
Always – forçar a barra de navegação e a fonte tamanho para usar o formato grande.
Automatic – use o mesmo estilo (pequeno ou grande) como o item anterior na pilha de navegação.
Never – forçar o uso da barra de navegação de formato pequeno regular.

Além disso, o SetLargeTitleDisplay método pode ser usado para alternar os valores de enumeração por meio da
chamada a LargeTitleDisplay método, que retorna atual LargeTitleDisplayMode :

switch (On<iOS>().LargeTitleDisplay())
{
case LargeTitleDisplayMode.Always:
On<iOS>().SetLargeTitleDisplay(LargeTitleDisplayMode.Automatic);
break;
case LargeTitleDisplayMode.Automatic:
On<iOS>().SetLargeTitleDisplay(LargeTitleDisplayMode.Never);
break;
case LargeTitleDisplayMode.Never:
On<iOS>().SetLargeTitleDisplay(LargeTitleDisplayMode.Always);
break;
}

O resultado é que o especificado LargeTitleDisplayMode é aplicada para o Page , que controla o comportamento
de título grande:

Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
iOSSpecific API
Estilo do cabeçalho de grupo de ListView no iOS
12/04/2019 • 2 minutes to read

Baixar o exemplo
Essa controla de específico da plataforma iOS se ListView células de cabeçalho float durante a rolagem. Ele é
consumido em XAML, definindo o ListView.GroupHeaderStyle propriedade associável a um valor da
GroupHeaderStyle enumeração:

<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core">
<StackLayout Margin="20">
<ListView ... ios:ListView.GroupHeaderStyle="Grouped">
...
</ListView>
</StackLayout>
</ContentPage>

Como alternativa, ele pode ser consumido de c# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...

listView.On<iOS>().SetGroupHeaderStyle(GroupHeaderStyle.Grouped);

O ListView.On<iOS> método Especifica que este específicos da plataforma serão executado apenas no iOS. O
ListView.SetGroupHeaderStyle método, no Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace, é usada
para controlar se ListView células de cabeçalho float durante a rolagem. O GroupHeaderStyle enumeração
fornece dois valores possíveis:
Plain – indica que as células de cabeçalho float quando o ListView é rolado (padrão).
Grouped – indica que as células de cabeçalho não flutuante quando o ListView é rolada.

Além disso, o ListView.GetGroupHeaderStyle método pode ser usado para retornar o GroupHeaderStyle que é
aplicado para o ListView .
O resultado é que a especificada GroupHeaderStyle valor é aplicado para o ListView , que controla se as células de
cabeçalho float durante a rolagem:
Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
iOSSpecific API
Animações de linha de ListView no iOS
12/04/2019 • 2 minutes to read

Baixar o exemplo
Essa controla de específico da plataforma iOS de linha se as animações são desabilitados quando o ListView
coleção de itens está sendo atualizada. Ele é consumido em XAML, definindo o ListView.RowAnimationsEnabled
para a propriedade associável false :

<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core">
<StackLayout Margin="20">
<ListView ... ios:ListView.RowAnimationsEnabled="false">
...
</ListView>
</StackLayout>
</ContentPage>

Como alternativa, ele pode ser consumido de c# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...

listView.On<iOS>().SetRowAnimationsEnabled(false);

O ListView.On<iOS> método Especifica que este específicos da plataforma serão executado apenas no iOS. O
ListView.SetRowAnimationsEnabled método, no Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace, é
usada para controlar se as animações de linha são desabilitado quando o ListView coleção de itens está sendo
atualizada. Além disso, o ListView.GetRowAnimationsEnabled método pode ser usado para retornar se animações de
linha estão desabilitadas no ListView .

NOTE
ListView animações de linha são habilitadas por padrão. Portanto, uma animação ocorre quando uma nova linha é
inserida em um ListView .

Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
iOSSpecific API
Estilo do separador de ListView no iOS
12/04/2019 • 2 minutes to read

Baixar o exemplo
Este específicos da plataforma iOS controla se o separador entre células em uma ListView usa a largura total do
ListView . Ele é consumido em XAML, definindo o ListView.SeparatorStyle propriedade anexada a um valor da
SeparatorStyle enumeração:

<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core">
<StackLayout Margin="20">
<ListView ... ios:ListView.SeparatorStyle="FullWidth">
...
</ListView>
</StackLayout>
</ContentPage>

Como alternativa, ele pode ser consumido de C# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...

listView.On<iOS>().SetSeparatorStyle(SeparatorStyle.FullWidth);

O ListView.On<iOS> método Especifica que este específicos da plataforma serão executado apenas no iOS. O
ListView.SetSeparatorStyle método, no Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace, é usada
para controlar se o separador entre células no ListView usa completo largura do ListView , com o
SeparatorStyle enumeração fornecendo dois valores possíveis:

Default – indica o comportamento do separador de iOS padrão. Esse é o comportamento padrão no xamarin.
Forms.
FullWidth – indica que os separadores serão desenhados de uma borda da ListView para outro.
O resultado é que o especificado SeparatorStyle valor é aplicado a ListView , que controla a largura do
separador entre células:
NOTE
Depois que o estilo do separador foi definido como FullWidth , ele não pode ser alterado para Default em tempo de
execução.

Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
iOSSpecific API
Atualizações de controle do Thread principal no iOS
12/04/2019 • 2 minutes to read

Baixar o exemplo
Este específicos da plataforma iOS permite controlar o layout e renderização de atualizações a serem executadas
no thread principal, em vez de que está sendo executada em um thread em segundo plano. Ele deve ser raramente
necessário, mas em alguns casos, pode impedir que falhas. Seu consumido em XAML, definindo o
Application.HandleControlUpdatesOnMainThread para a propriedade associável true :

<Application ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
ios:Application.HandleControlUpdatesOnMainThread="true">
...
</Application>

Como alternativa, ele pode ser consumido de C# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...

Xamarin.Forms.Application.Current.On<iOS>().SetHandleControlUpdatesOnMainThread(true);

O Application.On<iOS> método Especifica que este específicos da plataforma serão executado apenas no iOS. O
Application.SetHandleControlUpdatesOnMainThread método, no Xamarin.Forms.PlatformConfiguration.iOSSpecific
namespace, é usada para controlar se o controle de layout e renderização atualizações são executadas no thread
principal, em vez de que está sendo executada em um thread em segundo plano. Além disso, o
Application.GetHandleControlUpdatesOnMainThread método pode ser usado para retornar se o controle de layout e
renderização atualizações estão sendo executadas no thread principal.

Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
iOSSpecific API
Separador de barra NavigationPage no iOS
12/04/2019 • 2 minutes to read

Baixar o exemplo
Este específicos da plataforma iOS oculta a linha separadora e sombra que está na parte inferior da barra de
navegação em um NavigationPage . Ele é consumido em XAML, definindo o
NavigationPage.HideNavigationBarSeparator para a propriedade associável false :

<NavigationPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
ios:NavigationPage.HideNavigationBarSeparator="true">

</NavigationPage>

Como alternativa, ele pode ser consumido de C# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;

public class iOSTitleViewNavigationPageCS : Xamarin.Forms.NavigationPage


{
public iOSTitleViewNavigationPageCS()
{
On<iOS>().SetHideNavigationBarSeparator(true);
}
}

O NavigationPage.On<iOS> método Especifica que este específicos da plataforma serão executado apenas no iOS.
O NavigationPage.SetHideNavigationBarSeparator método, no Xamarin.Forms.PlatformConfiguration.iOSSpecific
namespace, é usada para controlar se o separador de barra de navegação está oculto. Além disso, o
NavigationPage.HideNavigationBarSeparator método pode ser usado para retornar se o separador de barra de
navegação está oculto.
O resultado é que o separador de barra de navegação em um NavigationPage podem estar ocultos:
Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
iOSSpecific API
Modo de cor de texto NavigationPage barra no iOS
12/04/2019 • 2 minutes to read

Baixar o exemplo
Este controles específicos da plataforma se o texto da barra de status de cor em um NavigationPage é ajustado
para coincidir com a luminosidade da barra de navegação. Ele é consumido em XAML, definindo o
NavigationPage.StatusBarTextColorMode propriedade anexada a um valor da StatusBarTextColorMode enumeração:

<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
x:Class="PlatformSpecifics.iOSStatusBarTextColorModePage">
<MasterDetailPage.Master>
<ContentPage Title="Master Page Title" />
</MasterDetailPage.Master>
<MasterDetailPage.Detail>
<NavigationPage BarBackgroundColor="Blue" BarTextColor="White"
ios:NavigationPage.StatusBarTextColorMode="MatchNavigationBarTextLuminosity">
<x:Arguments>
<ContentPage>
<Label Text="Slide the master page to see the status bar text color mode change." />
</ContentPage>
</x:Arguments>
</NavigationPage>
</MasterDetailPage.Detail>
</MasterDetailPage>

Como alternativa, ele pode ser consumido de c# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...

IsPresentedChanged += (sender, e) =>


{
var mdp = sender as MasterDetailPage;
if (mdp.IsPresented)
((Xamarin.Forms.NavigationPage)mdp.Detail)
.On<iOS>()
.SetStatusBarTextColorMode(StatusBarTextColorMode.DoNotAdjust);
else
((Xamarin.Forms.NavigationPage)mdp.Detail)
.On<iOS>()
.SetStatusBarTextColorMode(StatusBarTextColorMode.MatchNavigationBarTextLuminosity);
};

O NavigationPage.On<iOS> método Especifica que este específicos da plataforma serão executado apenas no iOS.
O NavigationPage.SetStatusBarTextColorMode método, no Xamarin.Forms.PlatformConfiguration.iOSSpecific
namespace, controles se o texto da barra de status de cor no NavigationPage é ajustado para coincidir com o
luminosidade da barra de navegação, com o StatusBarTextColorMode enumeração fornecendo dois valores
possíveis:
DoNotAdjust – indica que a barra de cor do texto de status não devem ser ajustado.
MatchNavigationBarTextLuminosity – indica que a barra de cor do texto de status deve corresponder à
luminosidade da barra de navegação.
Além disso, o método pode ser usado para recuperar o valor atual da
GetStatusBarTextColorMode
StatusBarTextColorMode enumeração é aplicada para o NavigationPage .
O resultado é que o status da barra de cor do texto em uma NavigationPage pode ser ajustado de acordo com a
luminosidade da barra de navegação. Neste exemplo, a barra de alterações de cor do texto de status que o usuário
alterna entre o Master e Detail páginas de um MasterDetailPage :

Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
iOSSpecific API
NavigationPage Translucência de barra no iOS
12/04/2019 • 2 minutes to read

Baixar o exemplo
Este específicos da plataforma iOS é usado para alterar a transparência da barra de navegação em um
NavigationPage e consumido em XAML, definindo o NavigationPage.IsNavigationBarTranslucent propriedade
anexada a um boolean valor:

<NavigationPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
BackgroundColor="Blue"
ios:NavigationPage.IsNavigationBarTranslucent="true">
...
</NavigationPage>

Como alternativa, ele pode ser consumido de C# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...

(App.Current.MainPage as Xamarin.Forms.NavigationPage).BackgroundColor = Color.Blue;


(App.Current.MainPage as Xamarin.Forms.NavigationPage).On<iOS>().EnableTranslucentNavigationBar();

O NavigationPage.On<iOS> método Especifica que este específicos da plataforma serão executado apenas no iOS.
O NavigationPage.EnableTranslucentNavigationBar método, no Xamarin.Forms.PlatformConfiguration.iOSSpecific
namespace, é usado para fazer a barra de navegação translúcido. Além disso, o NavigationPage classe o
Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace também tem um DisableTranslucentNavigationBar
método que restaura a barra de navegação para seu estado padrão, e um SetIsNavigationBarTranslucent método
que pode ser usado para alternar a transparência da barra de navegação, chamando o IsNavigationBarTranslucent
método:

(App.Current.MainPage as Xamarin.Forms.NavigationPage)
.On<iOS>()
.SetIsNavigationBarTranslucent(!(App.Current.MainPage as Xamarin.Forms.NavigationPage).On<iOS>
().IsNavigationBarTranslucent());

O resultado é que a transparência da barra de navegação pode ser alterada:

Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
iOSSpecific API
Página de visibilidade da barra de Status no iOS
12/04/2019 • 2 minutes to read

Baixar o exemplo
Este específicos da plataforma iOS é usado para definir a visibilidade da barra de status em uma Page , e inclui a
capacidade de controlar como a barra de status entra ou sai de Page . Ele é consumido em XAML, definindo o
Page.PrefersStatusBarHidden propriedade anexada a um valor da StatusBarHiddenMode enumeração e,
opcionalmente, o Page.PreferredStatusBarUpdateAnimation propriedade anexada a um valor da
UIStatusBarAnimation enumeração:

<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
ios:Page.PrefersStatusBarHidden="True"
ios:Page.PreferredStatusBarUpdateAnimation="Fade">
...
</ContentPage>

Como alternativa, ele pode ser consumido de c# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...

On<iOS>().SetPrefersStatusBarHidden(StatusBarHiddenMode.True)
.SetPreferredStatusBarUpdateAnimation(UIStatusBarAnimation.Fade);

O Page.On<iOS> método Especifica que este específicos da plataforma serão executado apenas no iOS. O
Page.SetPrefersStatusBarHidden método, no Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace, é usado
para definir a visibilidade da barra de status em um Page especificando um dos StatusBarHiddenMode valores de
enumeração: Default , True , ou False . O StatusBarHiddenMode.True e StatusBarHiddenMode.False valores
definidos a visibilidade da barra de status, independentemente da orientação do dispositivo e o
StatusBarHiddenMode.Default valor oculta a barra de status em um ambiente compact verticalmente.

O resultado é que a visibilidade da barra de status em uma Page podem ser definidos:
NOTE
Em um TabbedPage , especificado StatusBarHiddenMode valor de enumeração também atualizará a barra de status em
todas as páginas filho. Em todos os outros Page -tipos derivados, especificados StatusBarHiddenMode valor de
enumeração só atualizará a barra de status na página atual.

O método é usado para definir como a barra de status entra ou sai do


Page.SetPreferredStatusBarUpdateAnimation
Page especificando um da UIStatusBarAnimation valores de enumeração: None , Fade , ou Slide . Se o Fade ou
Slide o valor de enumeração for especificado, uma segunda 0,25 animação é executada como a barra de status
entra ou sai do Page .

Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
iOSSpecific API
Seleção de Item de seletor no iOS
12/04/2019 • 2 minutes to read

Baixar o exemplo
Este específicos da plataforma iOS controla quando a seleção de item ocorre em um Picker , permitindo que o
usuário especifique que a seleção de item ocorre ao navegar por itens no controle, ou apenas uma vez a feito
botão é pressionado. Ele é consumido em XAML, definindo o Picker.UpdateMode propriedade anexada a um valor
da UpdateMode enumeração:

<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core">
<StackLayout Margin="20">
<Picker ... Title="Select a monkey" ios:Picker.UpdateMode="WhenFinished">
...
</Picker>
...
</StackLayout>
</ContentPage>

Como alternativa, ele pode ser consumido de c# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...

picker.On<iOS>().SetUpdateMode(UpdateMode.WhenFinished);

O Picker.On<iOS> método Especifica que este específicos da plataforma serão executado apenas no iOS. O
Picker.SetUpdateMode método, no Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace, é usado para
controlar quando a seleção de item ocorre, com o UpdateMode enumeração fornecendo dois valores possíveis:
Immediately – seleção de item ocorre conforme o usuário navega por itens na Picker . Esse é o
comportamento padrão no xamarin. Forms.
WhenFinished – seleção de item ocorrerá somente depois que o usuário pressiona o feito botão na Picker .
Além disso, o SetUpdateMode método pode ser usado para alternar os valores de enumeração por meio da
chamada a UpdateMode método, que retorna atual UpdateMode :

switch (picker.On<iOS>().UpdateMode())
{
case UpdateMode.Immediately:
picker.On<iOS>().SetUpdateMode(UpdateMode.WhenFinished);
break;
case UpdateMode.WhenFinished:
picker.On<iOS>().SetUpdateMode(UpdateMode.Immediately);
break;
}

O resultado é que a especificada UpdateMode é aplicada para o Picker , que controla quando ocorre a seleção de
item:
Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
iOSSpecific API
Guia do Layout da área de segurança no iOS
12/04/2019 • 2 minutes to read

Baixar o exemplo
Este específicos da plataforma iOS é usado para garantir que o conteúdo da página é posicionado em uma área da
tela que é segura para todos os dispositivos que usam iOS 11 e superior. Especificamente, ele ajudará a garantir
que o conteúdo não é recortado pelo cantos arredondados de dispositivo, o indicador de base ou a estrutura do
sensor em um iPhone X. Ele é consumido em XAML, definindo o Page.UseSafeArea anexado à propriedade um
boolean valor:

<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
Title="Safe Area"
ios:Page.UseSafeArea="true">
<StackLayout>
...
</StackLayout>
</ContentPage>

Como alternativa, ele pode ser consumido de c# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...

On<iOS>().SetUseSafeArea(true);

O Page.On<iOS> método Especifica que este específicos da plataforma serão executado apenas no iOS. O
Page.SetUseSafeArea método, no Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace, que controla se o
guia do layout da área de segurança está habilitado.
O resultado é que o conteúdo da página pode ser posicionado em uma área da tela que é segura para todos os
iPhones:
NOTE
Área de segurança definida pela Apple é usada no xamarin. Forms para definir a Page.Padding propriedade e substituirá
qualquer anteriores valores dessa propriedade que foram definidos.

Área de segurança pode ser personalizada, recuperando seu Thickness de valor com o Page.SafeAreaInsets
método da Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace. Em seguida, pode ser modificado como
necessário e reatribuído à Padding propriedade no construtor da página ou OnAppearing substituir:

protected override void OnAppearing()


{
base.OnAppearing();

var safeInsets = On<iOS>().SafeAreaInsets();


safeInsets.Left = 20;
Padding = safeInsets;
}

Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
iOSSpecific API
ScrollView toques de conteúdo no iOS
12/04/2019 • 2 minutes to read

Baixar o exemplo
Um temporizador implícito é disparado quando um gesto de toque começa em um ScrollView no iOS e o
ScrollView decide, com base na ação de usuário na extensão de timer, se ele deve tratar o gesto ou passá-lo ao
seu conteúdo. Por padrão, o iOS ScrollView toques de conteúdo de atrasos, mas isso pode causar problemas em
algumas circunstâncias com o ScrollView conteúdo não ganhando o gesto quando deveria. Portanto, esse
controles específicos da plataforma se um ScrollView manipula um gesto de toque ou passá-lo ao seu conteúdo.
Ele é consumido em XAML, definindo o ScrollView.ShouldDelayContentTouches anexado à propriedade um
boolean valor:

<MasterDetailPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core">
<MasterDetailPage.Master>
<ContentPage Title="Menu" BackgroundColor="Blue" />
</MasterDetailPage.Master>
<MasterDetailPage.Detail>
<ContentPage>
<ScrollView x:Name="scrollView" ios:ScrollView.ShouldDelayContentTouches="false">
<StackLayout Margin="0,20">
<Slider />
<Button Text="Toggle ScrollView DelayContentTouches" Clicked="OnButtonClicked" />
</StackLayout>
</ScrollView>
</ContentPage>
</MasterDetailPage.Detail>
</MasterDetailPage>

Como alternativa, ele pode ser consumido de C# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...

scrollView.On<iOS>().SetShouldDelayContentTouches(false);

O ScrollView.On<iOS> método Especifica que este específicos da plataforma serão executado apenas no iOS. O
ScrollView.SetShouldDelayContentTouches método, no Xamarin.Forms.PlatformConfiguration.iOSSpecific
namespace, é usada para controlar se uma ScrollView manipula um gesto de toque ou passá-lo ao seu conteúdo.
Além disso, o SetShouldDelayContentTouches método pode ser usado para ativar/desativar atrasando o conteúdo
de toques, chamando o ShouldDelayContentTouches método para retornar se o conteúdo de toques estão atrasadas:

scrollView.On<iOS>().SetShouldDelayContentTouches(!scrollView.On<iOS>().ShouldDelayContentTouches());

O resultado é que um ScrollView pode desabilitar atrasando o recebimento de toques de conteúdo, portanto, que
neste cenário o Slider recebe o gesto em vez de Detail página do MasterDetailPage :
Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
iOSSpecific API
Reconhecimento de gesto de panorâmica
simultâneas no iOS
12/04/2019 • 2 minutes to read

Baixar o exemplo
Quando um PanGestureRecognizer é anexado a um modo de exibição dentro de uma exibição de rolagem, todos a
panorâmica de gestos são capturados pelo PanGestureRecognizer e não serão passados para o modo de exibição
de rolagem. Portanto, o modo de exibição de rolagem não mais será rolada.
Este específicos da plataforma iOS permite que um PanGestureRecognizer em uma exibição de rolagem para
capturar e compartilhar o gesto de panorâmica com o modo de exibição de rolagem. Ele é consumido em XAML,
definindo o Application.PanGestureRecognizerShouldRecognizeSimultaneously anexado à propriedade true :

<Application ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
ios:Application.PanGestureRecognizerShouldRecognizeSimultaneously="true">
...
</Application>

Como alternativa, ele pode ser consumido de C# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...

Xamarin.Forms.Application.Current.On<iOS>().SetPanGestureRecognizerShouldRecognizeSimultaneously(true);

O Application.On<iOS> método Especifica que este específicos da plataforma serão executado apenas no iOS. O
Application.SetPanGestureRecognizerShouldRecognizeSimultaneously método, no
Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace, é usada para controlar se um reconhecedor de
gestos em uma exibição da rolagem panorâmica capturar o gesto de panorâmica, ou capturar e compartilhar a
panorâmica com o modo de exibição de rolagem do gesto. Além disso, o
Application.GetPanGestureRecognizerShouldRecognizeSimultaneously método pode ser usado para retornar se o
gesto de Panorâmica é compartilhado com o modo de exibição de rolagem que contém o PanGestureRecognizer .
Portanto, com essa específicos da plataforma habilitado, quando um ListView contém um PanGestureRecognizer ,
ambos o ListView e o PanGestureRecognizer receberá o gesto de Panorâmica e processá-lo. No entanto, com essa
específicos da plataforma desabilitado, quando um ListView contém uma PanGestureRecognizer , o
PanGestureRecognizer capturará o gesto de Panorâmica e processá-lo e o ListView não receberá o gesto de
panorâmica.

Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
iOSSpecific API
Controle deslizante Thumb toque no iOS
12/04/2019 • 2 minutes to read

Baixar o exemplo
Este específicos da plataforma iOS permite que o Slider.Value propriedade a ser definido tocando em uma
posição no Slider barra, em vez de precisar arrastar o Slider thumb. Ele é consumido em XAML, definindo o
Slider.UpdateOnTap para a propriedade associável true :

<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core">
<StackLayout ...>
<Slider ... ios:Slider.UpdateOnTap="true" />
...
</StackLayout>
</ContentPage>

Como alternativa, ele pode ser consumido de C# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...

var slider = new Xamarin.Forms.Slider();


slider.On<iOS>().SetUpdateOnTap(true);

O Slider.On<iOS> método Especifica que este específicos da plataforma serão executado apenas no iOS. O
Slider.SetUpdateOnTap método, no Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace, é usada para
controlar se um toque do Slider barra definirá o Slider.Value propriedade. Além disso, o
Slider.GetUpdateOnTap método pode ser usado para retornar se um toque dos Slider barra definirá o
Slider.Value propriedade.

O resultado é que um toque do Slider barra pode mover o Slider thumb e defina o Slider.Value propriedade:

Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
iOSSpecific API
VisualElement desfoque no iOS
12/04/2019 • 2 minutes to read

Baixar o exemplo
Este específicos da plataforma iOS é usado para desfocar o conteúdo em camadas abaixo dela e pode ser aplicado
a qualquer VisualElement . Ele é consumido em XAML, definindo o VisualElement.BlurEffect propriedade
anexada a um valor da BlurEffectStyle enumeração:

<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core">
...
<AbsoluteLayout HorizontalOptions="Center">
<Image Source="monkeyface.png" />
<BoxView x:Name="boxView" ios:VisualElement.BlurEffect="ExtraLight" HeightRequest="300"
WidthRequest="300" />
</AbsoluteLayout>
...
</ContentPage>

Como alternativa, ele pode ser consumido de c# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...

boxView.On<iOS>().UseBlurEffect(BlurEffectStyle.ExtraLight);

O BoxView.On<iOS> método Especifica que este específicos da plataforma serão executado apenas no iOS. O
VisualElement.UseBlurEffect método, no Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace, é usado
para aplicar o efeito de desfoque, com o BlurEffectStyle enumeração fornecendo quatro valores: None ,
ExtraLight , Light , e Dark .

O resultado é que o especificado BlurEffectStyle é aplicado ao BoxView da instância, que Desfoca a Image em
camadas abaixo dela:
NOTE
Ao adicionar um efeito de desfoque a uma VisualElement , eventos de toque ainda serão recebidos pelo VisualElement .

Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
iOSSpecific API
VisualElement Drop sombras no iOS
12/04/2019 • 3 minutes to read

Baixar o exemplo
Este específicos da plataforma iOS é usado para habilitar uma sombra em um VisualElement . Ele é consumido
em XAML, definindo o VisualElement.IsShadowEnabled anexado à propriedade true , juntamente com um número
de adicionais opcional propriedades que controlam a sombra anexadas:

<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core">
<StackLayout Margin="20">
<BoxView ...
ios:VisualElement.IsShadowEnabled="true"
ios:VisualElement.ShadowColor="Purple"
ios:VisualElement.ShadowOpacity="0.7"
ios:VisualElement.ShadowRadius="12">
<ios:VisualElement.ShadowOffset>
<Size>
<x:Arguments>
<x:Double>10</x:Double>
<x:Double>10</x:Double>
</x:Arguments>
</Size>
</ios:VisualElement.ShadowOffset>
</BoxView>
...
</StackLayout>
</ContentPage>

Como alternativa, ele pode ser consumido de c# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...

var boxView = new BoxView { Color = Color.Aqua, WidthRequest = 100, HeightRequest = 100 };
boxView.On<iOS>()
.SetIsShadowEnabled(true)
.SetShadowColor(Color.Purple)
.SetShadowOffset(new Size(10,10))
.SetShadowOpacity(0.7)
.SetShadowRadius(12);

O VisualElement.On<iOS> método Especifica que este específicos da plataforma serão executado apenas no iOS. O
VisualElement.SetIsShadowEnabled método, no Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace, é
usada para controlar se uma sombra está habilitada no VisualElement . Além disso, os métodos a seguir podem
ser invocados para controlar a sombra:
SetShadowColor – Define a cor da sombra. A cor padrão é Color.Default .
SetShadowOffset – Define o deslocamento da sombra. O deslocamento altera a direção da sombra é convertida
e é especificada como uma Size valor. O Size valores de estrutura são expressos em unidades
independentes de dispositivo, com o primeiro valor que está sendo a distância para a esquerda (valor negativo)
ou a direita (valor positivo) e o segundo valor sendo a distância acima (valor negativo) ou abaixo (valor
positivo) . O valor padrão dessa propriedade é (0,0, 0,0), que resulta na sombra que está sendo convertido em
torno de cada lado do VisualElement .
SetShadowOpacity – Define a opacidade da sombra, com o valor sendo no intervalo de 0,0 (transparente) para
1,0 (opaco). O valor de opacidade padrão é 0,5.
SetShadowRadius – Define o raio de desfoque usado para renderizar a sombra projetada. O valor de raio padrão
é 10.0.

NOTE
O estado de uma sombra pode ser consultado por meio da chamada a GetIsShadowEnabled , GetShadowColor ,
GetShadowOffset , GetShadowOpacity , e GetShadowRadius métodos.

O resultado é que uma sombra pode ser habilitada em um VisualElement :

Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
iOSSpecific API
Modo de cor VisualElement herdado no iOS
12/04/2019 • 2 minutes to read

Baixar o exemplo
Algumas das exibições de xamarin. Forms apresentam um modo de cor herdado. Nesse modo, quando o
IsEnabled propriedade do modo de exibição é definida como false , o modo de exibição substituirá as cores
definidas pelo usuário com os nativo as cores padrão para o estado desabilitado. Para versões anteriores
compatibilidade, esse modo herdado cor permanece o comportamento padrão para modos de exibição com
suporte.
Este específicos da plataforma iOS desabilita esse modo herdado de cor em um VisualElement , de modo que as
cores definidas em uma exibição pelo usuário permanecem até mesmo quando o modo de exibição está
desabilitado. Ele é consumido em XAML, definindo o VisualElement.IsLegacyColorModeEnabled anexado à
propriedade false :

<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core">
<StackLayout>
...
<Button Text="Button"
TextColor="Blue"
BackgroundColor="Bisque"
ios:VisualElement.IsLegacyColorModeEnabled="False" />
...
</StackLayout>
</ContentPage>

Como alternativa, ele pode ser consumido de c# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...

_legacyColorModeDisabledButton.On<iOS>().SetIsLegacyColorModeEnabled(false);

O VisualElement.On<iOS> método Especifica que este específicos da plataforma serão executado apenas no iOS. O
VisualElement.SetIsLegacyColorModeEnabled método, no Xamarin.Forms.PlatformConfiguration.iOSSpecific
namespace, é usada para controlar se o modo de cor herdados é desabilitado. Além disso, o
VisualElement.GetIsLegacyColorModeEnabled método pode ser usado para retornar se o modo de cor herdado está
desabilitado.
O resultado é que o modo herdado de cor pode ser desabilitado, para que as cores definidas em uma exibição pelo
usuário permaneçam até mesmo quando o modo de exibição está desabilitado:
NOTE
Ao definir uma VisualStateGroup em uma exibição, o modo herdado de cor é totalmente ignorado. Para obter mais
informações sobre estados visuais, consulte o Gerenciador de estado Visual xamarin. Forms.

Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
iOSSpecific API
Xamarin. Forms em projetos do Xamarin nativo
12/04/2019 • 23 minutes to read

baixar o exemplo
Formulários nativos permitem que páginas ContentPage do xamarin. Forms derivado a ser consumido por
projetos nativos do xamarin. IOS, xamarin. Android e plataforma Universal do Windows (UWP ). Projetos nativos
podem consumir páginas com ContentPage derivada que são adicionadas diretamente ao projeto ou de uma
biblioteca .NET Standard, um projeto compartilhado ou uma biblioteca .NET Standard. Este artigo explica como
consumir páginas ContentPage derivadas que são adicionadas diretamente ao projetos nativos e como navegar
entre eles.
Normalmente, um aplicativo xamarin. Forms inclui uma ou mais páginas que derivam de ContentPage , e essas
páginas são compartilhadas por todas as plataformas em um projeto compartilhado ou o projeto de biblioteca
.NET Standard. No entanto, formas nativas permite ContentPage -derivado de páginas a serem adicionados
diretamente a aplicativos nativos do xamarin. IOS, xamarin. Android e UWP. Em comparação com a ter o projeto
nativo consumir ContentPage -páginas derivadas de um projeto de biblioteca .NET Standard ou o projeto
compartilhado, a vantagem de adicionar páginas diretamente em projetos nativos é que as páginas podem ser
estendidas com exibições nativas. Exibições nativas, em seguida, podem ser nomeadas no XAML com x:Name e
referenciada de code-behind. Para obter mais informações sobre exibições nativas, consulte exibições nativas.
O processo para o consumo de um xamarin. Forms ContentPage -página derivada em um projeto nativo é o
seguinte:
1. Adicione o pacote do NuGet xamarin. Forms para o projeto nativo.
2. Adicione a ContentPage -derivado de página e quaisquer dependências, para o projeto nativo.
3. Chame o método Forms.Init .
4. Construir uma instância de ContentPage -página derivada e convertê-lo para o tipo apropriado de nativo
usando um dos seguintes métodos de extensão: CreateViewController para iOS, CreateSupportFragment para o
Android, ou CreateFrameworkElement para UWP.
5. Navegue até a representação de tipo nativo do ContentPage -usando a API nativa de navegação de página
derivada.
Xamarin. Forms deve ser inicializado chamando o Forms.Init método antes de um projeto nativo pode construir
uma ContentPage -página derivada. Escolher quando fazer isso principalmente depende de quando é mais
conveniente em seu fluxo de aplicativo – pode ser executada na inicialização do aplicativo, ou imediatamente antes
do ContentPage -página derivada é construído. Neste artigo, e os aplicativos de exemplo que acompanha este
artigo, o Forms.Init método é chamado na inicialização do aplicativo.

NOTE
O NativeForms solução de aplicativo de exemplo não contém todos os projetos xamarin. Forms. Em vez disso, ele consiste
em um projeto xamarin. IOS, um projeto xamarin. Android e um projeto UWP. Cada projeto é um projeto nativo que usa
formulários nativos para consumir ContentPage -derivado de páginas. No entanto, não há nenhum motivo por que os
projetos nativos não podiam consumir ContentPage -derivado de páginas de um projeto de biblioteca .NET Standard ou o
projeto compartilhado.

Ao usar formulários Native, xamarin. Forms recursos como DependencyService , MessagingCenter e o mecanismo
de associação de dados, todo o trabalho ainda. No entanto, a navegação de página deve ser executada usando a
API nativa de navegação.

iOS
No iOS, o FinishedLaunching substituir no AppDelegate classe geralmente é o lugar para executar o aplicativo de
tarefas relacionadas à inicialização. Ele é chamado depois que o aplicativo foi iniciado e geralmente é substituído
para configurar a janela principal e exibir o controlador. O seguinte exemplo de código mostra o AppDelegate
classe no aplicativo de exemplo:

[Register("AppDelegate")]
public class AppDelegate : UIApplicationDelegate
{
public static AppDelegate Instance;

UIWindow _window;
UINavigationController _navigation;

public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)


{
Forms.Init();

Instance = this;
_window = new UIWindow(UIScreen.MainScreen.Bounds);

UINavigationBar.Appearance.SetTitleTextAttributes(new UITextAttributes
{
TextColor = UIColor.Black
});

var mainPage = new PhonewordPage().CreateViewController();


mainPage.Title = "Phoneword";

_navigation = new UINavigationController(mainPage);


_window.RootViewController = _navigation;
_window.MakeKeyAndVisible();

return true;
}
...
}

O FinishedLaunching método realiza as seguintes tarefas:


Xamarin. Forms é inicializado chamando o Forms.Init método.
Uma referência para o AppDelegate classe é armazenada na static Instance campo. Isso é fornecer um
mecanismo para chamar métodos definidos em outras classes de AppDelegate classe.
O UIWindow , que é o principal contêiner para modos de exibição em aplicativos nativos iOS, é criada.
O PhonewordPage classe, que é um xamarin. Forms ContentPage -derivado da página definida em XAML, que é
construído e convertido em um UIViewController usando o CreateViewController método de extensão.
O Title propriedade do UIViewController for definido, que será exibido o UINavigationBar .
Um UINavigationController é criada para gerenciar a navegação hierárquica. O UINavigationController classe
gerencia uma pilha de controladores de exibição e o UIViewController passado para o construtor será exibido
inicialmente quando o UINavigationController é carregado.
O UINavigationController instância é definida como o nível superior UIViewController para o UIWindow e o
UIWindow é definida como a janela de chave para o aplicativo e se torna visível.

Uma vez a FinishedLaunching método foi executado, a interface do usuário definido no xamarin. Forms
PhonewordPage classe será exibida, conforme mostrado na seguinte captura de tela:
Interagindo com a interface do usuário, por exemplo, tocando em uma Button , resultará em manipuladores de
eventos no PhonewordPage de lógica de execução. Por exemplo, quando um usuário toca a histórico de
chamadas botão, o manipulador de eventos a seguir é executado:

void OnCallHistory(object sender, EventArgs e)


{
AppDelegate.Instance.NavigateToCallHistoryPage();
}

O static AppDelegate.Instance campo permite que o AppDelegate.NavigateToCallHistoryPage método a ser


invocado, que é mostrado no exemplo de código a seguir:

public void NavigateToCallHistoryPage()


{
var callHistoryPage = new CallHistoryPage().CreateViewController();
callHistoryPage.Title = "Call History";
_navigation.PushViewController(callHistoryPage, true);
}

O NavigateToCallHistoryPage método converte o xamarin. Forms ContentPage -derivado da página para um


UIViewController com o CreateViewController o método de extensão e conjuntos do Title propriedade do
UIViewController . O UIViewController , em seguida, é enviado por push UINavigationController pelo
PushViewController método. Portanto, a interface do usuário definido no xamarin. Forms CallHistoryPage classe
será exibida, conforme mostrado na seguinte captura de tela:
Quando o CallHistoryPage for exibida, tocando o back seta será exibida a UIViewController para o
CallHistoryPage de classe da UINavigationController , retornando o usuário para o UIViewController para o
PhonewordPage classe.

Android
No Android, o OnCreate substituir no MainActivity classe geralmente é o lugar para executar o aplicativo de
tarefas relacionadas à inicialização. O seguinte exemplo de código mostra o MainActivity classe no aplicativo de
exemplo:
public class MainActivity : AppCompatActivity
{
public static MainActivity Instance;

protected override void OnCreate(Bundle bundle)


{
base.OnCreate(bundle);

Forms.Init(this, bundle);
Instance = this;

SetContentView(Resource.Layout.Main);
var toolbar = FindViewById<Toolbar>(Resource.Id.toolbar);
SetSupportActionBar(toolbar);
SupportActionBar.Title = "Phoneword";

var mainPage = new PhonewordPage().CreateSupportFragment(this);


SupportFragmentManager
.BeginTransaction()
.Replace(Resource.Id.fragment_frame_layout, mainPage)
.Commit();
...
}
...
}

O OnCreate método realiza as seguintes tarefas:


Xamarin. Forms é inicializado chamando o Forms.Init método.
Uma referência para o MainActivity classe é armazenada na static Instance campo. Isso é fornecer um
mecanismo para chamar métodos definidos em outras classes de MainActivity classe.
O Activity o conteúdo está definido de um recurso de layout. No aplicativo de exemplo, o layout consiste em
uma LinearLayout que contém uma Toolbar e um FrameLayout para atuar como um contêiner de fragmento.
O Toolbar é recuperado e definido como a barra de ação para o Activity , e o título da barra de ação está
definido.
O PhonewordPage classe, que é um xamarin. Forms ContentPage -derivado da página definida em XAML, que é
construído e convertido em um Fragment usando o CreateSupportFragment método de extensão.
O SupportFragmentManager classe cria e confirma uma transação que substitui o FrameLayout da instância com
o Fragment para o PhonewordPage classe.

Para obter mais informações sobre fragmentos, consulte fragmentos.


Uma vez a OnCreate método foi executado, a interface do usuário definido no xamarin. Forms PhonewordPage
classe será exibida, conforme mostrado na seguinte captura de tela:
Interagindo com a interface do usuário, por exemplo, tocando em uma Button , resultará em manipuladores de
eventos no PhonewordPage de lógica de execução. Por exemplo, quando um usuário toca a histórico de
chamadas botão, o manipulador de eventos a seguir é executado:

void OnCallHistory(object sender, EventArgs e)


{
MainActivity.Instance.NavigateToCallHistoryPage();
}

O static MainActivity.Instance campo permite que o MainActivity.NavigateToCallHistoryPage método a ser


invocado, que é mostrado no exemplo de código a seguir:

public void NavigateToCallHistoryPage()


{
var callHistoryPage = new CallHistoryPage().CreateSupportFragment(this);
SupportFragmentManager
.BeginTransaction()
.AddToBackStack(null)
.Replace(Resource.Id.fragment_frame_layout, callHistoryPage)
.Commit();
}

O NavigateToCallHistoryPage método converte o xamarin. Forms ContentPage -derivado da página para um


Fragment com o CreateSupportFragment o método de extensão e adiciona o Fragment pilha de volta para o
fragmento. Portanto, a interface do usuário definido no xamarin. Forms CallHistoryPage será exibida, conforme
mostrado na seguinte captura de tela:
Quando o CallHistoryPage for exibida, tocando o back seta será exibida a Fragment para o CallHistoryPage da
pilha voltar de fragmento, retornando o usuário para o Fragment para o PhonewordPage classe.
Habilitando o suporte de navegação regressiva
O SupportFragmentManager classe tem um BackStackChanged evento é acionado sempre que o conteúdo da pilha
voltar de fragmento é alterado. O OnCreate método no MainActivity classe contém um manipulador de eventos
anônimos para este evento:

SupportFragmentManager.BackStackChanged += (sender, e) =>


{
bool hasBack = SupportFragmentManager.BackStackEntryCount > 0;
SupportActionBar.SetHomeButtonEnabled(hasBack);
SupportActionBar.SetDisplayHomeAsUpEnabled(hasBack);
SupportActionBar.Title = hasBack ? "Call History" : "Phoneword";
};

Esse manipulador de eventos exibe um botão Voltar na barra de ação, desde que haja um ou mais Fragment
instâncias no fragmento de pilha de volta. A resposta ao tocar no botão Voltar é tratada pelo
OnOptionsItemSelected substituir:

public override bool OnOptionsItemSelected(Android.Views.IMenuItem item)


{
if (item.ItemId == global::Android.Resource.Id.Home && SupportFragmentManager.BackStackEntryCount > 0)
{
SupportFragmentManager.PopBackStack();
return true;
}
return base.OnOptionsItemSelected(item);
}
O OnOptionsItemSelected substituição é chamada sempre que um item no menu de opções está selecionado. Essa
implementação retira o fragmento atual da pilha voltar de fragmento, desde que foi selecionado o botão Voltar e
há um ou mais Fragment instâncias no fragmento de pilha de volta.
Várias atividades
Quando um aplicativo é composto por várias atividades, ContentPage -páginas derivadas podem ser inseridas em
cada uma das atividades. Nesse cenário, o Forms.Init método precisa ser chamado somente em de OnCreate
substituir da primeira Activity que incorpora um xamarin. Forms ContentPage . No entanto, isso tem o seguinte
impacto:
O valor de Xamarin.Forms.Color.Accent será extraído o Activity que chamou o Forms.Init método.
O valor de Xamarin.Forms.Application.Current será associado a Activity que chamou o Forms.Init método.

Escolher um arquivo
Ao inserir uma ContentPage -derivado de página que usa um WebView que precisa para dar suporte um HTML
"Escolher arquivo" botão, o Activity precisará substituir o OnActivityResult método:

protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)


{
base.OnActivityResult(requestCode, resultCode, data);
ActivityResultCallbackRegistry.InvokeCallback(requestCode, resultCode, data);
}

UWP
Na UWP, nativo App classe geralmente é o lugar para executar o aplicativo de tarefas relacionadas à inicialização.
Xamarin. Forms é geralmente inicializado, em aplicativos da UWP do xamarin. Forms, na OnLaunched substituir
em nativo App classe, para passar o LaunchActivatedEventArgs argumento para o Forms.Init método. Por esse
motivo, os aplicativos nativos de UWP que consomem um xamarin. Forms ContentPage -página derivada pode
chamar mais facilmente os Forms.Init método a partir de App.OnLaunched método.
Por padrão, nativo App classe inicia o MainPage classe como a primeira página do aplicativo. O seguinte exemplo
de código mostra o MainPage classe no aplicativo de exemplo:

public sealed partial class MainPage : Page


{
public static MainPage Instance;

public MainPage()
{
this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Enabled;
Instance = this;
this.Content = new Phoneword.UWP.Views.PhonewordPage().CreateFrameworkElement();
}
...
}

O MainPage construtor executa as seguintes tarefas:


O cache é habilitado para a página, para que um novo MainPage não é construída quando um usuário navega
para a página.
Uma referência para o MainPage classe é armazenada na static Instance campo. Isso é fornecer um
mecanismo para chamar métodos definidos em outras classes de MainPage classe.
O PhonewordPage classe, que é um xamarin. Forms ContentPage -derivado da página definida em XAML, que é
construído e convertido em um FrameworkElement usando o CreateFrameworkElement método de extensão e, em
seguida, defina como o conteúdo da MainPage classe.

Uma vez a MainPage construtor foi executado, a interface do usuário definido no xamarin. Forms PhonewordPage
classe será exibida, conforme mostrado na seguinte captura de tela:

Interagindo com a interface do usuário, por exemplo, tocando em uma Button , resultará em manipuladores de
eventos no PhonewordPage de lógica de execução. Por exemplo, quando um usuário toca a histórico de
chamadas botão, o manipulador de eventos a seguir é executado:

void OnCallHistory(object sender, EventArgs e)


{
Phoneword.UWP.MainPage.Instance.NavigateToCallHistoryPage();
}

O static MainPage.Instance campo permite que o MainPage.NavigateToCallHistoryPage método a ser invocado,


que é mostrado no exemplo de código a seguir:

public void NavigateToCallHistoryPage()


{
this.Frame.Navigate(new CallHistoryPage());
}

Navegação no UWP normalmente é executada com o Frame.Navigate método, que usa um Page argumento.
Xamarin. Forms define uma Frame.Navigate método de extensão que usa um ContentPage -instância de página
derivada. Portanto, quando o NavigateToCallHistoryPage método é executado, a interface do usuário definido no
xamarin. Forms CallHistoryPage será exibida, conforme mostrado na seguinte captura de tela:
Quando o CallHistoryPage for exibida, tocando o back seta será exibida a FrameworkElement para o
CallHistoryPage da pilha Voltar no aplicativo, retornando o usuário para o FrameworkElement para o
PhonewordPage classe.
Habilitando o suporte de navegação regressiva
Na UWP, aplicativos devem habilitar a navegação para todos os software e hardware back botões, em fatores
forma de dispositivo diferentes. Isso pode ser feito ao registrar um manipulador de eventos para o BackRequested
evento, que pode ser executado em de OnLaunched método nativo App classe:

protected override void OnLaunched(LaunchActivatedEventArgs e)


{
Frame rootFrame = Window.Current.Content as Frame;

if (rootFrame == null)
{
...
// Place the frame in the current Window
Window.Current.Content = rootFrame;

SystemNavigationManager.GetForCurrentView().BackRequested += OnBackRequested;
}
...
}

Quando o aplicativo é iniciado, o GetForCurrentView método recupera o SystemNavigationManager objeto


associado com o modo de exibição atual, em seguida, registra um manipulador de eventos para o BackRequested
eventos. O aplicativo recebe esse evento somente se ele é o aplicativo de primeiro plano e, em resposta, chama o
OnBackRequested manipulador de eventos:
void OnBackRequested(object sender, BackRequestedEventArgs e)
{
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame.CanGoBack)
{
e.Handled = true;
rootFrame.GoBack();
}
}

O OnBackRequested chamadas do manipulador de eventos a GoBack método no quadro da raiz do aplicativo e


conjuntos da BackRequestedEventArgs.Handled propriedade true para marcar o evento como manipulado. Não
marcar o evento como manipulado pode resultar no sistema de navegar para fora do aplicativo (na família de
dispositivo móvel) ou ignorando o evento (na família de dispositivo de desktop).
O aplicativo se baseia em um botão Voltar do sistema fornecidos em um telefone, mas escolhe se deseja mostrar
um botão Voltar na barra de título em dispositivos da área de trabalho. Isso é feito definindo a
AppViewBackButtonVisibility propriedade para um do AppViewBackButtonVisibility valores de enumeração:

void OnNavigated(object sender, NavigationEventArgs e)


{
SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility =
((Frame)sender).CanGoBack ? AppViewBackButtonVisibility.Visible :
AppViewBackButtonVisibility.Collapsed;
}

O OnNavigated manipulador de eventos, que é executado em resposta ao Navigated evento disparando, atualiza a
visibilidade do botão Voltar da barra de título quando ocorrer a navegação de página. Isso garante que o botão
Voltar de barra de título é visível se a pilha Voltar no aplicativo não está vazia ou removido da barra de título se a
pilha Voltar no aplicativo está vazia.
Para obter mais informações sobre o suporte de navegação regressiva na UWP, consulte histórico de navegação e
para trás a navegação para aplicativos UWP.

Resumo
Formulários nativos permitem que o xamarin. Forms ContentPage -derivado de páginas a ser consumido por
projetos nativos do xamarin. IOS, xamarin. Android e plataforma Universal do Windows (UWP ). Projetos nativos
podem consumir ContentPage -derivado de páginas que são adicionadas diretamente ao projeto, ou de um projeto
de biblioteca .NET Standard ou o projeto compartilhado. Este artigo explicou como consumir ContentPage -
derivado de páginas que são adicionadas diretamente para projetos nativos e como navegar entre eles.

Links relacionados
NativeForms (amostra)
Exibições nativas
Modos de exibição nativo no xamarin. Forms
12/04/2019 • 2 minutes to read

Exibições nativo do iOS, Android e o Windows UWP (plataforma Universal) podem ser referenciadas
diretamente do xamarin. Forms. Propriedades e manipuladores de eventos podem ser definidos em exibições
nativo, e eles podem interagir com exibições xamarin. Forms.

Exibições nativos em XAML


Exibições nativo do iOS, Android e UWP podem ser referenciadas diretamente das páginas do xamarin. Forms
criadas usando XAML.

Exibições nativas em C#
Exibições nativo do iOS, Android e UWP podem ser referenciadas diretamente do xamarin. Forms páginas
criadas usando o c#.

Links relacionados
Formulários nativos
Exibições nativas em XAML
12/04/2019 • 23 minutes to read

baixar o exemplo
Exibições nativas do iOS, Android e plataforma Universal do Windows podem ser referenciadas diretamente de
arquivos XAML de xamarin. Forms. Propriedades e os manipuladores de eventos podem ser definidos em exibições
nativas e eles podem interagir com exibições do xamarin. Forms. Este artigo demonstra como consumir exibições
nativas de arquivos XAML de xamarin. Forms.
Este artigo discute os seguintes tópicos:
Consumindo exibições nativas – o processo para o consumo de um modo de exibição nativo de XAML.
Usando associações nativas – e para as propriedades de exibições nativas de vinculação de dados.
Passando argumentos para exibições nativas – passando argumentos para construtores de modo nativo e
chamar métodos de fábrica de modo nativo.
Referindo-se a exibições nativas do código – recuperar instâncias de modo nativo declarado em um arquivo
XAML, de seu arquivo code-behind.
Exibições nativas da subclasse – subclasses exibições nativas para definir uma API amigável a XAML.

Visão geral
Para inserir uma exibição nativa em um arquivo XAML de xamarin. Forms:
1. Adicionar um xmlns declaração de namespace no arquivo XAML para o namespace que contém o modo
nativo.
2. Crie uma instância do modo nativo no arquivo XAML.

NOTE
XAMLC deve ser desativado para todas as páginas XAML que usam exibições nativas.

Para fazer referência a um modo de exibição nativo de um arquivo code-behind, você deve usar um projeto de
ativo compartilhado (SAP ) e encapsule o código específico da plataforma com diretivas de compilação condicional.
Para obter mais informações, consulte referindo-se a exibições nativas do código.

Consumindo exibições nativas


O exemplo de código a seguir demonstra o consumo de exibições nativas para cada plataforma para um xamarin.
Forms ContentPage :
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:ios="clr-namespace:UIKit;assembly=Xamarin.iOS;targetPlatform=iOS"
xmlns:androidWidget="clr-namespace:Android.Widget;assembly=Mono.Android;targetPlatform=Android"
xmlns:androidLocal="clr-
namespace:SimpleColorPicker.Droid;assembly=SimpleColorPicker.Droid;targetPlatform=Android"
xmlns:win="clr-namespace:Windows.UI.Xaml.Controls;assembly=Windows, Version=255.255.255.255,
Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime;targetPlatform=Windows"
x:Class="NativeViews.NativeViewDemo">
<StackLayout Margin="20">
<ios:UILabel Text="Hello World" TextColor="{x:Static ios:UIColor.Red}" View.HorizontalOptions="Start"
/>
<androidWidget:TextView Text="Hello World" x:Arguments="{x:Static androidLocal:MainActivity.Instance}"
/>
<win:TextBlock Text="Hello World" />
</StackLayout>
</ContentPage>

Bem como especificar o clr-namespace e assembly para um namespace de modo nativo, um targetPlatform
também deve ser especificado. Isso deve ser definido como um dos valores da TargetPlatform enumeração e
normalmente será definido como iOS , Android , ou Windows . Em tempo de execução, o analisador XAML
ignorará quaisquer prefixos de namespace XML que têm um targetPlatform que não coincida com a plataforma
na qual o aplicativo está em execução.
Cada declaração de namespace pode ser usada para fazer referência a qualquer classe ou estrutura de namespace
especificado. Por exemplo, o ios declaração de namespace pode ser usada para fazer referência a qualquer classe
ou estrutura do iOS UIKit namespace. Propriedades do modo nativo podem ser definidas por meio de XAML,
mas os tipos de objeto e propriedade devem coincidir. Por exemplo, o UILabel.TextColor estiver definida como
UIColor.Red usando o x:Static extensão de marcação e o ios namespace.

Propriedades vinculáveis e propriedades vinculáveis anexadas podem também ser definidas em exibições nativas
usando o Class.BindableProperty="value" sintaxe. Cada exibição nativa é encapsulada em uma plataforma
específica NativeViewWrapper instância, que deriva de Xamarin.Forms.View classe. Definir uma propriedade
associável ou a propriedade associável anexada em um modo de exibição nativo transfere o valor da propriedade
para o wrapper. Por exemplo, um layout horizontal centralizado pode ser especificado definindo
View.HorizontalOptions="Center" na exibição nativa.

NOTE
Observe que os estilos não podem ser usados com exibições nativas, porque os estilos somente podem direcionar as
propriedades que têm o respaldo BindableProperty objetos.

Construtores de widget Android geralmente requerem o Android Context objeto como um argumento e isso
podem ser disponibilizado por meio de uma propriedade estática no MainActivity classe. Portanto, ao criar um
widget de Android em XAML, o Context objeto geralmente deve ser passado ao construtor do widget usando o
x:Arguments atributo com um x:Static extensão de marcação. Para obter mais informações, consulte passando
argumentos para exibições nativas.

NOTE
Observe que uma exibição nativa com a nomenclatura x:Name não é possível em um projeto de biblioteca .NET Standard ou
um projeto de ativo compartilhado (SAP). Isso vai gerar uma variável do tipo nativo, o que causará um erro de compilação.
No entanto, podem ser ajustadas exibições nativas em ContentView instâncias e recuperados no arquivo code-behind,
desde que um SAP está sendo usado. Para obter mais informações, consulte referindo-se a uma exibição nativo do código.
Associações nativas
Vinculação de dados é usada para sincronizar uma interface do usuário com sua fonte de dados e simplifica como
um aplicativo xamarin. Forms exibe e interage com seus dados. Desde que o objeto de origem implementa o
INotifyPropertyChanged interface, as alterações na código -fonte objeto são enviadas automaticamente para o
destino objeto pela estrutura de associação e as alterações no alvo objeto opcionalmente pode ser enviado para o
origem objeto.
Propriedades de exibições nativas também podem usar a vinculação de dados. O exemplo de código a seguir
demonstra a associação de dados usando propriedades de exibições nativas:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:ios="clr-namespace:UIKit;assembly=Xamarin.iOS;targetPlatform=iOS"
xmlns:androidWidget="clr-namespace:Android.Widget;assembly=Mono.Android;targetPlatform=Android"
xmlns:androidLocal="clr-
namespace:SimpleColorPicker.Droid;assembly=SimpleColorPicker.Droid;targetPlatform=Android"
xmlns:win="clr-namespace:Windows.UI.Xaml.Controls;assembly=Windows, Version=255.255.255.255,
Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime;targetPlatform=Windows"
xmlns:local="clr-namespace:NativeSwitch"
x:Class="NativeSwitch.NativeSwitchPage">
<StackLayout Margin="20">
<Label Text="Native Views Demo" FontAttributes="Bold" HorizontalOptions="Center" />
<Entry Placeholder="This Entry is bound to the native switch" IsEnabled="{Binding IsSwitchOn}" />
<ios:UISwitch On="{Binding Path=IsSwitchOn, Mode=TwoWay, UpdateSourceEventName=ValueChanged}"
OnTintColor="{x:Static ios:UIColor.Red}"
ThumbTintColor="{x:Static ios:UIColor.Blue}" />
<androidWidget:Switch x:Arguments="{x:Static androidLocal:MainActivity.Instance}"
Checked="{Binding Path=IsSwitchOn, Mode=TwoWay, UpdateSourceEventName=CheckedChange}"
Text="Enable Entry?" />
<win:ToggleSwitch Header="Enable Entry?"
OffContent="No"
OnContent="Yes"
IsOn="{Binding IsSwitchOn, Mode=TwoWay, UpdateSourceEventName=Toggled}" />
</StackLayout>
</ContentPage>

A página contém um Entry cujo IsEnabled propriedade associa ao NativeSwitchPageViewModel.IsSwitchOn


propriedade. O BindingContext da página é definido como uma nova instância dos NativeSwitchPageViewModel
classe no arquivo code-behind, com a classe ViewModel Implementando o INotifyPropertyChanged interface.
A página também contém um comutador nativo para cada plataforma. Cada comutador nativo usa um TwoWay
associação para atualizar o valor da NativeSwitchPageViewModel.IsSwitchOn propriedade. Portanto, quando estiver
desativada, o Entry estiver desabilitada, e quando a opção estiver ativada, o Entry está habilitado. As capturas de
tela a seguir mostram a essa funcionalidade em cada plataforma:
Vinculações bidirecionais automaticamente têm suporte contanto que implementa a propriedade nativa
INotifyPropertyChanged , ou oferece suporte a observar de chave-valor ( KVO ) no iOS, ou é um DependencyProperty
na UWP. No entanto, muitas exibições nativas não oferecem suporte a notificação de alteração de propriedade.
Para esses modos de exibição, você pode especificar uma UpdateSourceEventName valor da propriedade como parte
da expressão de associação. Essa propriedade deve ser definida para o nome de um evento no modo de exibição
nativo que sinaliza quando a propriedade de destino foi alterado. Em seguida, quando o valor da opção nativo
muda, o Binding classe é notificado de que o usuário alterou o valor da opção e o
NativeSwitchPageViewModel.IsSwitchOn valor da propriedade é atualizado.

Passando argumentos para exibições nativas


Argumentos de construtor podem ser passados para exibições nativas usando o x:Arguments do atributo com um
x:Static extensão de marcação. Além disso, os métodos de fábrica de modo nativo ( public static métodos que
retornam objetos ou valores do mesmo tipo que a classe ou estrutura que define os métodos) pode ser chamado,
especificando o método nome usando o x:FactoryMethod atributo e seus argumentos usando o x:Arguments
atributo.
O exemplo de código a seguir demonstra as duas técnicas:
<ContentPage ...
xmlns:ios="clr-namespace:UIKit;assembly=Xamarin.iOS;targetPlatform=iOS"
xmlns:androidWidget="clr-namespace:Android.Widget;assembly=Mono.Android;targetPlatform=Android"
xmlns:androidGraphics="clr-namespace:Android.Graphics;assembly=Mono.Android;targetPlatform=Android"
xmlns:androidLocal="clr-
namespace:SimpleColorPicker.Droid;assembly=SimpleColorPicker.Droid;targetPlatform=Android"
xmlns:winControls="clr-namespace:Windows.UI.Xaml.Controls;assembly=Windows, Version=255.255.255.255,
Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime;targetPlatform=Windows"
xmlns:winMedia="clr-namespace:Windows.UI.Xaml.Media;assembly=Windows, Version=255.255.255.255,
Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime;targetPlatform=Windows"
xmlns:winText="clr-namespace:Windows.UI.Text;assembly=Windows, Version=255.255.255.255,
Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime;targetPlatform=Windows"
xmlns:winui="clr-namespace:Windows.UI;assembly=Windows, Version=255.255.255.255, Culture=neutral,
PublicKeyToken=null, ContentType=WindowsRuntime;targetPlatform=Windows">
...
<ios:UILabel Text="Simple Native Color Picker" View.HorizontalOptions="Center">
<ios:UILabel.Font>
<ios:UIFont x:FactoryMethod="FromName">
<x:Arguments>
<x:String>Papyrus</x:String>
<x:Single>24</x:Single>
</x:Arguments>
</ios:UIFont>
</ios:UILabel.Font>
</ios:UILabel>
<androidWidget:TextView x:Arguments="{x:Static androidLocal:MainActivity.Instance}"
Text="Simple Native Color Picker"
TextSize="24"
View.HorizontalOptions="Center">
<androidWidget:TextView.Typeface>
<androidGraphics:Typeface x:FactoryMethod="Create">
<x:Arguments>
<x:String>cursive</x:String>
<androidGraphics:TypefaceStyle>Normal</androidGraphics:TypefaceStyle>
</x:Arguments>
</androidGraphics:Typeface>
</androidWidget:TextView.Typeface>
</androidWidget:TextView>
<winControls:TextBlock Text="Simple Native Color Picker"
FontSize="20"
FontStyle="{x:Static winText:FontStyle.Italic}"
View.HorizontalOptions="Center">
<winControls:TextBlock.FontFamily>
<winMedia:FontFamily>
<x:Arguments>
<x:String>Georgia</x:String>
</x:Arguments>
</winMedia:FontFamily>
</winControls:TextBlock.FontFamily>
</winControls:TextBlock>
...
</ContentPage>

O UIFont.FromName método de fábrica é usado para definir a UILabel.Font propriedade para um novo UIFont no
iOS. O UIFont nome e tamanho são especificados pelos argumentos de método que são filhos do x:Arguments
atributo.
O Typeface.Create método de fábrica é usado para definir a TextView.Typeface propriedade para um novo
Typeface no Android. O Typeface nome da família e estilo são especificados pelos argumentos de método que
são filhos do x:Arguments atributo.
O FontFamily construtor é usado para definir a TextBlock.FontFamily propriedade para um novo FontFamily no
Universal Windows Platform (UWP ). O FontFamily nome é especificado pelo argumento do método que é um
filho do x:Arguments atributo.
NOTE
Argumentos devem corresponder aos tipos exigidos pelo método de construtor ou de fábrica.

As capturas de tela a seguir mostram o resultado da especificação de argumentos de método e construtor de


fábrica para definir a fonte em diferentes exibições nativas:

Para obter mais informações sobre como passar argumentos em XAML, consulte passando argumentos em
XAML.

Referindo-se a exibições nativas do código


Embora não seja possível nomear uma exibição nativa com o x:Name atributo, é possível recuperar uma instância
de modo nativo, declarada em um arquivo XAML de seu arquivo code-behind em um projeto de acesso
compartilhado, desde que o modo nativo é um filho de um ContentView que especifica um x:Name valor do
atributo. Em seguida, dentro de diretivas de compilação condicional no arquivo code-behind você deve:
1. Recuperar o ContentView.Content propriedade de valor e convertê-lo para um específico da plataforma
NativeViewWrapper tipo.
2. Recuperar o NativeViewWrapper.NativeElement propriedade e convertê-lo para o tipo de modo nativo.

A API nativa, em seguida, pode ser invocada no modo de nativo para executar as operações desejadas. Essa
abordagem também oferece o benefício que várias exibições nativas do XAML para diferentes plataformas podem
ser filhos dos mesmos ContentView . O exemplo de código a seguir demonstra essa técnica:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:ios="clr-namespace:UIKit;assembly=Xamarin.iOS;targetPlatform=iOS"
xmlns:androidWidget="clr-namespace:Android.Widget;assembly=Mono.Android;targetPlatform=Android"
xmlns:androidLocal="clr-
namespace:SimpleColorPicker.Droid;assembly=SimpleColorPicker.Droid;targetPlatform=Android"
xmlns:winControls="clr-namespace:Windows.UI.Xaml.Controls;assembly=Windows, Version=255.255.255.255,
Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime;targetPlatform=Windows"
xmlns:local="clr-namespace:NativeViewInsideContentView"
x:Class="NativeViewInsideContentView.NativeViewInsideContentViewPage">
<StackLayout Margin="20">
<ContentView x:Name="contentViewTextParent" HorizontalOptions="Center"
VerticalOptions="CenterAndExpand">
<ios:UILabel Text="Text in a UILabel" TextColor="{x:Static ios:UIColor.Red}" />
<androidWidget:TextView x:Arguments="{x:Static androidLocal:MainActivity.Instance}"
Text="Text in a TextView" />
<winControls:TextBlock Text="Text in a TextBlock" />
</ContentView>
<ContentView x:Name="contentViewButtonParent" HorizontalOptions="Center"
VerticalOptions="EndAndExpand">
<ios:UIButton TouchUpInside="OnButtonTap" View.HorizontalOptions="Center"
View.VerticalOptions="Center" />
<androidWidget:Button x:Arguments="{x:Static androidLocal:MainActivity.Instance}"
Text="Scale and Rotate Text"
Click="OnButtonTap" />
<winControls:Button Content="Scale and Rotate Text" />
</ContentView>
</StackLayout>
</ContentPage>

No exemplo acima, as exibições de nativas para cada plataforma são filhos de ContentView controles, com o
x:Name valor de atributo que está sendo usado para recuperar o ContentView no code-behind:
public partial class NativeViewInsideContentViewPage : ContentPage
{
public NativeViewInsideContentViewPage()
{
InitializeComponent();

#if __IOS__
var wrapper = (Xamarin.Forms.Platform.iOS.NativeViewWrapper)contentViewButtonParent.Content;
var button = (UIKit.UIButton)wrapper.NativeView;
button.SetTitle("Scale and Rotate Text", UIKit.UIControlState.Normal);
button.SetTitleColor(UIKit.UIColor.Black, UIKit.UIControlState.Normal);
#endif
#if __ANDROID__
var wrapper = (Xamarin.Forms.Platform.Android.NativeViewWrapper)contentViewTextParent.Content;
var textView = (Android.Widget.TextView)wrapper.NativeView;
textView.SetTextColor(Android.Graphics.Color.Red);
#endif
#if WINDOWS_UWP
var textWrapper = (Xamarin.Forms.Platform.UWP.NativeViewWrapper)contentViewTextParent.Content;
var textBlock = (Windows.UI.Xaml.Controls.TextBlock)textWrapper.NativeElement;
textBlock.Foreground = new Windows.UI.Xaml.Media.SolidColorBrush(Windows.UI.Colors.Red);
var buttonWrapper = (Xamarin.Forms.Platform.UWP.NativeViewWrapper)contentViewButtonParent.Content;
var button = (Windows.UI.Xaml.Controls.Button)buttonWrapper.NativeElement;
button.Click += (sender, args) => OnButtonTap(sender, EventArgs.Empty);
#endif
}

async void OnButtonTap(object sender, EventArgs e)


{
contentViewButtonParent.Content.IsEnabled = false;
contentViewTextParent.Content.ScaleTo(2, 2000);
await contentViewTextParent.Content.RotateTo(360, 2000);
contentViewTextParent.Content.ScaleTo(1, 2000);
await contentViewTextParent.Content.RelRotateTo(360, 2000);
contentViewButtonParent.Content.IsEnabled = true;
}
}

O ContentView.Content propriedade é acessada para recuperar o modo de exibição nativo encapsulado como um
específico da plataforma NativeViewWrapper instância. O NativeViewWrapper.NativeElement propriedade é acessada,
em seguida, para recuperar o modo nativo como seu tipo nativo. API nativa do modo de exibição, em seguida, é
chamado para realizar as operações desejadas.
O iOS e Android botões nativo compartilham a mesma OnButtonTap manipulador de eventos, porque cada botão
nativo consome um EventHandler delegar em resposta a um evento de toque. No entanto, a Universal Windows
Platform (UWP ) usa um separado RoutedEventHandler , que por sua vez consome o OnButtonTap manipulador de
eventos neste exemplo. Portanto, quando um botão nativo é clicado, o OnButtonTap manipulador de eventos é
executado, que se dimensiona e gira o controle nativo contido a ContentView chamado contentViewTextParent . As
capturas de tela a seguir demonstram essa que ocorrem em cada plataforma:
Criando subclasses exibições nativas
Muitos iOS e Android exibições nativas não são adequadas para criar uma instância em XAML, porque eles usam
métodos, em vez de propriedades, para configurar o controle. Exibições nativas de subclasse nos wrappers que
definem uma API de XAML compatível com mais do que usa as propriedades para o controle de instalação, e que
usa eventos independente de plataforma é a solução para esse problema. Os modos de exibição encapsulados
nativos podem ser colocados em um projeto de ativo compartilhado (SAP ) e cercados com diretivas de
compilação condicional, ou colocados em projetos específicos da plataforma e referenciados de XAML em um
projeto de biblioteca .NET Standard.
O exemplo de código a seguir demonstra uma página de xamarin. Forms que consome uma subclasse exibições
nativas:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:ios="clr-namespace:UIKit;assembly=Xamarin.iOS;targetPlatform=iOS"
xmlns:iosLocal="clr-
namespace:SubclassedNativeControls.iOS;assembly=SubclassedNativeControls.iOS;targetPlatform=iOS"
xmlns:android="clr-namespace:Android.Widget;assembly=Mono.Android;targetPlatform=Android"
xmlns:androidLocal="clr-
namespace:SimpleColorPicker.Droid;assembly=SimpleColorPicker.Droid;targetPlatform=Android"
xmlns:androidLocal="clr-
namespace:SubclassedNativeControls.Droid;assembly=SubclassedNativeControls.Droid;targetPlatform=Android"
xmlns:winControls="clr-namespace:Windows.UI.Xaml.Controls;assembly=Windows, Version=255.255.255.255,
Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime;targetPlatform=Windows"
xmlns:local="clr-namespace:SubclassedNativeControls"
x:Class="SubclassedNativeControls.SubclassedNativeControlsPage">
<StackLayout Margin="20">
<Label Text="Subclassed Native Views Demo" FontAttributes="Bold" HorizontalOptions="Center" />
<StackLayout Orientation="Horizontal">
<Label Text="You have chosen:" />
<Label Text="{Binding SelectedFruit}" />
</StackLayout>
<iosLocal:MyUIPickerView ItemsSource="{Binding Fruits}"
SelectedItem="{Binding SelectedFruit, Mode=TwoWay, UpdateSourceEventName=SelectedItemChanged}" />
<androidLocal:MySpinner x:Arguments="{x:Static androidLocal:MainActivity.Instance}"
ItemsSource="{Binding Fruits}"
SelectedObject="{Binding SelectedFruit, Mode=TwoWay, UpdateSourceEventName=ItemSelected}" />
<winControls:ComboBox ItemsSource="{Binding Fruits}"
SelectedItem="{Binding SelectedFruit, Mode=TwoWay, UpdateSourceEventName=SelectionChanged}" />
</StackLayout>
</ContentPage>

A página contém um Label que exibe as frutas escolhidas pelo usuário de um controle nativo. O Label está
associado a SubclassedNativeControlsPageViewModel.SelectedFruit propriedade. O BindingContext da página é
definido como uma nova instância dos SubclassedNativeControlsPageViewModel classe no arquivo code-behind, com
a classe ViewModel Implementando o INotifyPropertyChanged interface.
A página também contém um modo de exibição de seletor de nativo para cada plataforma. Cada exibição nativa
exibe a coleção de frutas, associando sua ItemSource propriedade para o
SubclassedNativeControlsPageViewModel.Fruits coleção. Isso permite que o usuário escolha uma frutas, conforme
mostrado nas capturas de tela seguir:
No iOS e Android os seletores nativos usam métodos para configurar os controles. Portanto, esses seletores
devem ser uma subclasse para expor as propriedades para torná-las amigável a XAML. Na Universal Windows
Platform (UWP ), o ComboBox já é compatível com XAML e, portanto, não exige a criação de subclasses.
iOS
As subclasses de implementação do iOS a UIPickerView exibição e expõe propriedades e um evento que pode ser
facilmente consumido de XAML:
public class MyUIPickerView : UIPickerView
{
public event EventHandler<EventArgs> SelectedItemChanged;

public MyUIPickerView()
{
var model = new PickerModel();
model.ItemChanged += (sender, e) =>
{
if (SelectedItemChanged != null)
{
SelectedItemChanged.Invoke(this, e);
}
};
Model = model;
}

public IList<string> ItemsSource


{
get
{
var pickerModel = Model as PickerModel;
return (pickerModel != null) ? pickerModel.Items : null;
}
set
{
var model = Model as PickerModel;
if (model != null)
{
model.Items = value;
}
}
}

public string SelectedItem


{
get { return (Model as PickerModel).SelectedItem; }
set { }
}
}

O MyUIPickerView classe expõe ItemsSource e SelectedItem propriedades e um SelectedItemChanged eventos.


Um UIPickerView requer uma subjacente UIPickerViewModel modelo de dados, que pode é acessado pelo
MyUIPickerView propriedades e eventos. O UIPickerViewModel modelo de dados é fornecido pelo PickerModel
classe:
class PickerModel : UIPickerViewModel
{
int selectedIndex = 0;
public event EventHandler<EventArgs> ItemChanged;
public IList<string> Items { get; set; }

public string SelectedItem


{
get
{
return Items != null && selectedIndex >= 0 && selectedIndex < Items.Count ? Items[selectedIndex] :
null;
}
}

public override nint GetRowsInComponent(UIPickerView pickerView, nint component)


{
return Items != null ? Items.Count : 0;
}

public override string GetTitle(UIPickerView pickerView, nint row, nint component)


{
return Items != null && Items.Count > row ? Items[(int)row] : null;
}

public override nint GetComponentCount(UIPickerView pickerView)


{
return 1;
}

public override void Selected(UIPickerView pickerView, nint row, nint component)


{
selectedIndex = (int)row;
if (ItemChanged != null)
{
ItemChanged.Invoke(this, new EventArgs());
}
}
}

O PickerModel classe fornece o armazenamento subjacente para o MyUIPickerView classe, por meio de Items
propriedade. Sempre que o item selecionado na MyUIPickerView alterações, o Selected método é executado, que
atualiza o índice selecionado e aciona o ItemChanged eventos. Isso garante que o SelectedItem propriedade
sempre retornará o último item escolhido pelo usuário. Além disso, o PickerModel classe substitui os métodos que
são usados para configurar o MyUIPickerView instância.
Android
As subclasses de implementação do Android a Spinner exibição e expõe propriedades e um evento que pode ser
facilmente consumido de XAML:
class MySpinner : Spinner
{
ArrayAdapter adapter;
IList<string> items;

public IList<string> ItemsSource


{
get { return items; }
set
{
if (items != value)
{
items = value;
adapter.Clear();

foreach (string str in items)


{
adapter.Add(str);
}
}
}
}

public string SelectedObject


{
get { return (string)GetItemAtPosition(SelectedItemPosition); }
set
{
if (items != null)
{
int index = items.IndexOf(value);
if (index != -1)
{
SetSelection(index);
}
}
}
}

public MySpinner(Context context) : base(context)


{
ItemSelected += OnBindableSpinnerItemSelected;

adapter = new ArrayAdapter(context, Android.Resource.Layout.SimpleSpinnerItem);


adapter.SetDropDownViewResource(Android.Resource.Layout.SimpleSpinnerDropDownItem);
Adapter = adapter;
}

void OnBindableSpinnerItemSelected(object sender, ItemSelectedEventArgs args)


{
SelectedObject = (string)GetItemAtPosition(args.Position);
}
}

O MySpinner classe expõe ItemsSource e SelectedObject propriedades e um ItemSelected eventos. Os itens


exibidos pelo MySpinner classe são fornecidas pelo Adapter associado com o modo de exibição e itens serão
populadas na Adapter quando o ItemsSource propriedade é definida pela primeira vez. Sempre que o item
selecionado na MySpinner classe alterações, o OnBindableSpinnerItemSelected atualizações do manipulador de
eventos a SelectedObject propriedade.

Resumo
Este artigo demonstrou como consumir exibições nativas de arquivos XAML de xamarin. Forms. Propriedades e os
manipuladores de eventos podem ser definidos em exibições nativas e eles podem interagir com exibições do
xamarin. Forms.

Links relacionados
NativeSwitch (amostra)
Forms2Native (amostra)
NativeViewInsideContentView (amostra)
SubclassedNativeControls (amostra)
Formulários nativos
Passando argumentos em XAML
Exibições nativas em c#
12/04/2019 • 12 minutes to read

baixar o exemplo
Exibições nativas do iOS, Android e UWP podem ser referenciadas diretamente das páginas do xamarin. Forms
criadas usando a linguagem c#. Este artigo demonstra como adicionar exibições nativas para um layout de
xamarin. Forms criado usando a linguagem c# e como substituir o layout dos modos de exibição personalizados
para corrigir seu uso da API de medição.

Visão geral
Qualquer controle do xamarin. Forms que permite Content deve ser definido, ou que tenha um Children , pode
adicionar modos de exibição específicos da plataforma. Por exemplo, um iOS UILabel podem ser adicionados
diretamente para o ContentView.Content propriedade, ou para o StackLayout.Children coleção. No entanto,
observe que essa funcionalidade requer o uso de #if define em soluções de projeto do xamarin. Forms
compartilhado e não está disponível em soluções do xamarin. Forms .NET Standard library.
As capturas de tela a seguir demonstram específicos da plataforma exibições ter sido adicionado a um xamarin.
Forms StackLayout :

A capacidade de adicionar modos de exibição específicos da plataforma para um layout de xamarin. Forms é
habilitada por dois métodos de extensão em cada plataforma:
Add – Adiciona uma exibição específica da plataforma para o Children coleção de um layout.
ToView – usa uma exibição específica de plataforma e o encapsula como um xamarin. Forms View que pode
ser definido como o Content propriedade de um controle.
Usando esses métodos em um projeto compartilhado do xamarin. Forms requer importando o namespace
apropriado do xamarin. Forms específicos da plataforma:
iOS – Xamarin.Forms.Platform.iOS
Android – Xamarin.Forms.Platform.Android
Plataforma universal do Windows (UWP ) – Xamarin.Forms.Platform.UWP

Adicionando modos de exibição específicos da plataforma em cada


plataforma
As seções a seguir demonstram como adicionar modos de exibição específicos da plataforma para um layout de
xamarin. Forms em cada plataforma.
iOS
O exemplo de código a seguir demonstra como adicionar um UILabel para um StackLayout e um ContentView :

var uiLabel = new UILabel {


MinimumFontSize = 14f,
Lines = 0,
LineBreakMode = UILineBreakMode.WordWrap,
Text = originalText,
};
stackLayout.Children.Add (uiLabel);
contentView.Content = uiLabel.ToView();

O exemplo supõe que o stackLayout e contentView instâncias criadas anteriormente no XAML ou c#.
Android
O exemplo de código a seguir demonstra como adicionar um TextView para um StackLayout e um ContentView :

var textView = new TextView (MainActivity.Instance) { Text = originalText, TextSize = 14 };


stackLayout.Children.Add (textView);
contentView.Content = textView.ToView();

O exemplo supõe que o stackLayout e contentView instâncias criadas anteriormente no XAML ou c#.
Plataforma Universal do Windows
O exemplo de código a seguir demonstra como adicionar um TextBlock para um StackLayout e um ContentView
:

var textBlock = new TextBlock


{
Text = originalText,
FontSize = 14,
FontFamily = new FontFamily("HelveticaNeue"),
TextWrapping = TextWrapping.Wrap
};
stackLayout.Children.Add(textBlock);
contentView.Content = textBlock.ToView();

O exemplo supõe que o stackLayout e contentView instâncias criadas anteriormente no XAML ou c#.
Substituindo as medidas da plataforma para modos de exibição
personalizados
Exibições personalizadas em cada plataforma geralmente só corretamente implementam medida para o cenário de
layout para o qual eles foram criados. Por exemplo, uma exibição personalizada pode ter sido projetada para
ocupar apenas metade da largura disponível do dispositivo. No entanto, após o que está sendo compartilhado com
outros usuários, o modo de exibição personalizado pode ser necessário para ocupar a largura total disponível do
dispositivo. Portanto, pode ser necessário substituir uma implementação de medição de modos de exibição
personalizados quando sendo reutilizadas em um layout de xamarin. Forms. Por esse motivo, o Add e ToView
métodos de extensão fornecem substituições que permitem que os representantes de medida seja especificado,
que podem substituir o layout do modo de exibição personalizado quando ele é adicionado a um layout de
xamarin. Forms.
As seções a seguir demonstram como substituir o layout dos modos de exibição personalizados, para corrigir seu
uso da API de medição.
iOS
O seguinte exemplo de código mostra a CustomControl classe, que herda de UILabel :

public class CustomControl : UILabel


{
public override string Text {
get { return base.Text; }
set { base.Text = value.ToUpper (); }
}

public override CGSize SizeThatFits (CGSize size)


{
return new CGSize (size.Width, 150);
}
}

Uma instância dessa exibição é adicionada a um StackLayout , conforme demonstrado no exemplo de código a
seguir:

var customControl = new CustomControl {


MinimumFontSize = 14,
Lines = 0,
LineBreakMode = UILineBreakMode.WordWrap,
Text = "This control has incorrect sizing - there's empty space above and below it."
};
stackLayout.Children.Add (customControl);

No entanto, porque o CustomControl.SizeThatFits substituição sempre retorna uma altura de 150, o modo de
exibição será exibido com um espaço vazio acima e abaixo dele, conforme mostrado na seguinte captura de tela:
Uma solução para esse problema é fornecer um GetDesiredSizeDelegate implementação, conforme demonstrado
no exemplo de código a seguir:

SizeRequest? FixSize (NativeViewWrapperRenderer renderer, double width, double height)


{
var uiView = renderer.Control;

if (uiView == null) {
return null;
}

var constraint = new CGSize (width, height);

// Let the CustomControl determine its size (which will be wrong)


var badRect = uiView.SizeThatFits (constraint);

// Use the width and substitute the height


return new SizeRequest (new Size (badRect.Width, 70));
}

Esse método usa a largura fornecida pelo CustomControl.SizeThatFits método, mas substitui a altura de 150 de
altura de 70. Quando o CustomControl instância é adicionada ao StackLayout , o FixSize método pode ser
especificado como o GetDesiredSizeDelegate para corrigir a medida incorreta fornecida pelo CustomControl classe:

stackLayout.Children.Add (customControl, FixSize);

Isso resulta na exibição personalizada que está sendo exibida corretamente, sem espaço vazio acima e abaixo dele,
conforme mostrado na seguinte captura de tela:

Android
O seguinte exemplo de código mostra a CustomControl classe, que herda de TextView :
public class CustomControl : TextView
{
public CustomControl (Context context) : base (context)
{
}

protected override void OnMeasure (int widthMeasureSpec, int heightMeasureSpec)


{
int width = MeasureSpec.GetSize (widthMeasureSpec);

// Force the width to half of what's been requested.


// This is deliberately wrong to demonstrate providing an override to fix it with.
int widthSpec = MeasureSpec.MakeMeasureSpec (width / 2, MeasureSpec.GetMode (widthMeasureSpec));

base.OnMeasure (widthSpec, heightMeasureSpec);


}
}

Uma instância dessa exibição é adicionada a um StackLayout , conforme demonstrado no exemplo de código a
seguir:

var customControl = new CustomControl (MainActivity.Instance) {


Text = "This control has incorrect sizing - it doesn't occupy the available width of the device.",
TextSize = 14
};
stackLayout.Children.Add (customControl);

No entanto, porque o CustomControl.OnMeasure substituição sempre retorna a metade da largura solicitada, o


modo de exibição será exibido que ocupam somente metade da largura disponível do dispositivo, conforme
mostrado na seguinte captura de tela:

Uma solução para esse problema é fornecer um GetDesiredSizeDelegate implementação, conforme demonstrado
no exemplo de código a seguir:

SizeRequest? FixSize (NativeViewWrapperRenderer renderer, int widthConstraint, int heightConstraint)


{
var nativeView = renderer.Control;

if ((widthConstraint == 0 && heightConstraint == 0) || nativeView == null) {


return null;
}

int width = Android.Views.View.MeasureSpec.GetSize (widthConstraint);


int widthSpec = Android.Views.View.MeasureSpec.MakeMeasureSpec (
width * 2, Android.Views.View.MeasureSpec.GetMode (widthConstraint));
nativeView.Measure (widthSpec, heightConstraint);
return new SizeRequest (new Size (nativeView.MeasuredWidth, nativeView.MeasuredHeight));
}

Esse método usa a largura fornecida pelo CustomControl.OnMeasure método, mas o multiplica por dois. Quando o
CustomControl instância é adicionada ao StackLayout , o FixSize método pode ser especificado como o
GetDesiredSizeDelegate para corrigir a medida incorreta fornecida pelo CustomControl classe:

stackLayout.Children.Add (customControl, FixSize);

Isso resulta no modo de exibição personalizado que está sendo exibida corretamente, que ocupa a largura do
dispositivo, conforme mostrado na seguinte captura de tela:

Plataforma Universal do Windows


O seguinte exemplo de código mostra a CustomControl classe, que herda de Panel :
public class CustomControl : Panel
{
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register(
"Text", typeof(string), typeof(CustomControl), new PropertyMetadata(default(string),
OnTextPropertyChanged));

public string Text


{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value.ToUpper()); }
}

readonly TextBlock textBlock;

public CustomControl()
{
textBlock = new TextBlock
{
MinHeight = 0,
MaxHeight = double.PositiveInfinity,
MinWidth = 0,
MaxWidth = double.PositiveInfinity,
FontSize = 14,
TextWrapping = TextWrapping.Wrap,
VerticalAlignment = VerticalAlignment.Center
};

Children.Add(textBlock);
}

static void OnTextPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs


args)
{
((CustomControl)dependencyObject).textBlock.Text = (string)args.NewValue;
}

protected override Size ArrangeOverride(Size finalSize)


{
// This is deliberately wrong to demonstrate providing an override to fix it with.
textBlock.Arrange(new Rect(0, 0, finalSize.Width/2, finalSize.Height));
return finalSize;
}

protected override Size MeasureOverride(Size availableSize)


{
textBlock.Measure(availableSize);
return new Size(textBlock.DesiredSize.Width, textBlock.DesiredSize.Height);
}
}

Uma instância dessa exibição é adicionada a um StackLayout , conforme demonstrado no exemplo de código a
seguir:

var brokenControl = new CustomControl {


Text = "This control has incorrect sizing - it doesn't occupy the available width of the device."
};
stackLayout.Children.Add(brokenControl);

No entanto, porque o CustomControl.ArrangeOverride substituição sempre retorna a metade da largura solicitada, o


modo de exibição será recortado para metade da largura disponível do dispositivo, conforme mostrado na
seguinte captura de tela:
Uma solução para esse problema é fornecer um ArrangeOverrideDelegate implementação, ao adicionar o modo de
exibição para o StackLayout , conforme demonstrado no exemplo de código a seguir:

stackLayout.Children.Add(fixedControl, arrangeOverrideDelegate: (renderer, finalSize) =>


{
if (finalSize.Width <= 0 || double.IsInfinity(finalSize.Width))
{
return null;
}
var frameworkElement = renderer.Control;
frameworkElement.Arrange(new Rect(0, 0, finalSize.Width * 2, finalSize.Height));
return finalSize;
});

Esse método usa a largura fornecida pelo CustomControl.ArrangeOverride método, mas o multiplica por dois. Isso
resulta no modo de exibição personalizado que está sendo exibida corretamente, que ocupa a largura do
dispositivo, conforme mostrado na seguinte captura de tela:

Resumo
Este artigo explicou como adicionar exibições nativas para um layout de xamarin. Forms criado usando a
linguagem c# e como substituir o layout dos modos de exibição personalizados para corrigir seu uso da API de
medição.

Links relacionados
NativeEmbedding (amostra)
Formulários nativos
Outras plataformas xamarin. Forms
12/04/2019 • 2 minutes to read

Xamarin. Forms dá suporte a plataformas adicionais além do iOS, Android e Windows.

GTK
Xamarin. Forms agora tem suporte para aplicativos do GTK # visualização.

Mac
Xamarin. Forms agora tem suporte para aplicativos macOS visualização.

Tizen
Tizen .NET permite que você crie aplicativos .NET com xamarin. Forms e Tizen .NET Framework.

WPF
Xamarin. Forms agora tem suporte de visualização para aplicativos do Windows Presentation Foundation (WPF ).
Instalação de plataforma do GTK #
12/04/2019 • 10 minutes to read

Xamarin. Forms agora tem suporte para aplicativos do GTK # visualização. O GTK # é um kit de ferramentas de
interface gráfica do usuário que vincula o Kit de ferramentas GTK + e uma variedade de bibliotecas GNOME,
permitindo o desenvolvimento de GNOME totalmente nativo aplicativos de gráficos usando o Mono e .NET. Este
artigo demonstra como adicionar um projeto GTK # a uma solução do xamarin. Forms.
Antes de começar, crie uma nova solução xamarin. Forms ou usar uma solução existente do xamarin. Forms, por
exemplo, GameOfLife.

NOTE
Embora este artigo se concentra na adição de um aplicativo do GTK # a uma solução do xamarin. Forms no VS2017 e o
Visual Studio para Mac, ele também pode ser executado no MonoDevelop para Linux.

Adicionar um aplicativo do GTK #


O GTK # para macOS e Linux é instalado como parte do Mono. O GTK # para .NET pode ser instalado no
Windows com o instalador do GTK #.
Visual Studio
Visual Studio para Mac
Siga estas instruções para adicionar um aplicativo do GTK # que será executado na área de trabalho do Windows:
1. No Visual Studio de 2019, clique com botão direito no nome da solução no Gerenciador de soluções e
escolha Adicionar > Novo projeto... .
2. No novo projeto janela, à esquerda, selecione Visual C# e área de trabalho clássica do Windows. Na
lista de tipos de projeto, escolha biblioteca de classes (.NET Framework) e certifique-se de que o
Framework suspensa é definida como um mínimo de .NET Framework 4.7.
3. Digite um nome para o projeto com um GTK extensão, por exemplo GameOfLife.GTK. Clique no navegue
botão, selecione a pasta que contém a plataforma de outra projetos e pressione Selecionar pasta. Isso
colocará o projeto GTK no mesmo diretório que os outros projetos na solução.
Pressione a Okey botão para criar o projeto.
4. No Gerenciador de soluções, com o botão direito do mouse no projeto GTK novo e selecione Manage
NuGet Packages. Selecione o navegue guia e pesquise xamarin. Forms 3.0 ou superior.

Selecione o pacote e clique no instalar botão.


5. Agora pesquise a Xamarin.Forms.Platform.GTK pacote 3.0 ou superior.

Selecione o pacote e clique no instalar botão.


6. No Gerenciador de soluções, clique com botão direito no nome da solução e selecione gerenciar
pacotes NuGet para solução. Selecione o atualização guia e o xamarin. Forms pacote. Selecione todos
os projetos e atualizá-los para a mesma versão do xamarin. Forms usado pelo projeto GTK.
7. No Gerenciador de soluções, clique duas vezes em referências no projeto GTK. No Gerenciador de
referências caixa de diálogo, selecione projetos na esquerda e verifique a caixa de seleção adjacente ao
projeto .NET Standard ou compartilhada:
8. No Gerenciador de referências caixa de diálogo, pressione a procurar botão e navegue até o
C:\Program Files (x86)\GtkSharp\2.12\lib pasta e selecione o ATK sharp.dll, gdk sharp.dll, glade
sharp.dll, glib sharp.dll, gtk-dotnet.dll, sharp.dll gtk arquivos.

Pressione a Okey botão para adicionar as referências.


9. No projeto GTK, renomeie Class1.cs à Program.cs.
10. No projeto GTK, edite o Program.cs arquivo para que ele fique parecido com o código a seguir:
using System;
using Xamarin.Forms;
using Xamarin.Forms.Platform.GTK;

namespace GameOfLife.GTK
{
class MainClass
{
[STAThread]
public static void Main(string[] args)
{
Gtk.Application.Init();
Forms.Init();

var app = new App();


var window = new FormsWindow();
window.LoadApplication(app);
window.SetApplicationTitle("Game of Life");
window.Show();

Gtk.Application.Run();
}
}
}

Esse código inicializa o GTK # e xamarin. Forms, cria uma janela do aplicativo e executa o aplicativo.
11. No Gerenciador de soluções, com o botão direito do mouse no projeto GTK e selecione propriedades.
12. No propriedades janela, selecione a aplicativo guia e altere a tipo de saída lista suspensa para
aplicativo Windows.

13. No Gerenciador de soluções, clique com botão direito no projeto GTK e selecione definir como projeto
de inicialização. Pressione F5 para executar o programa com o depurador do Visual Studio, na área de
trabalho do Windows:
Próximas etapas
Especificidades da plataforma
Você pode determinar em qual plataforma está em execução no seu aplicativo xamarin. Forms de XAML ou
código. Isso permite que você altere as características do programa quando ele é executado em GTK #. No código,
comparar o valor de Device.RuntimePlatform com o Device.GTK constante (que é igual a cadeia de caracteres
"GTK"). Se houver uma correspondência, o aplicativo está em execução em GTK #.
No XAML, você pode usar o OnPlatform marca para selecionar um valor de propriedade específico da plataforma:

<Button.TextColor>
<OnPlatform x:TypeArguments="Color">
<On Platform="iOS" Value="White" />
<On Platform="macOS" Value="White" />
<On Platform="Android" Value="Black" />
<On Platform="GTK" Value="Blue" />
</OnPlatform>
</Button.TextColor>

Ícone do Aplicativo
Você pode definir o ícone do aplicativo na inicialização:

window.SetApplicationIcon("icon.png");

Temas
Há uma grande variedade de temas disponíveis para GTK #, e eles podem ser usados em um aplicativo xamarin.
Forms:
GtkThemes.Init ();
GtkThemes.LoadCustomTheme ("Themes/gtkrc");

Formulários nativos
Formulários nativos permite que o xamarin. Forms ContentPage -derivado de páginas a ser consumido por
projetos nativos, incluindo projetos GTK #. Isso pode ser feito criando uma instância das ContentPage -derivado de
página e convertê-lo para o nativo GTK # tipo usando o CreateContainer método de extensão:

var settingsView = new SettingsView().CreateContainer();


vbox.PackEnd(settingsView, true, true, 0);

Para obter mais informações sobre formulários nativos, consulte formulários nativos.

Problemas
Esta é uma visualização, portanto, você deve esperar que nem tudo está pronto para produção. O status atual de
implementação, consulte Statuse para os problemas conhecidos atuais, consulte problemas conhecidos e
pendentes.
Configuração de plataforma do Mac
12/04/2019 • 5 minutes to read

Antes de começar, crie (ou usar uma existente) projeto xamarin. Forms. Você só pode adicionar aplicativos do Mac
usando o Visual Studio para Mac.

A adição de um projeto do macOS para xamarin. Forms, por Xamarin University

Adicionar um aplicativo do Mac


Siga estas instruções para adicionar um aplicativo do Mac que será executado no macOS Sierra e macOS El
Capitan:
1. No Visual Studio para Mac, clique com botão direito na solução do xamarin. Forms existente e escolha
Adicionar > Adicionar novo projeto...
2. No novo projeto janela escolher Mac > aplicativo > aplicativo Cocoa e pressione próxima.
3. Tipo de um nome do aplicativo (e, opcionalmente, escolha um nome diferente para o Item do Dock), em
seguida, pressione próxima.
4. Examine a configuração e pressione criar. Essas etapas são mostradas no abaixo:

5. No projeto do Mac, clique duas vezes em pacotes > Adicionar pacotes... para adicionar o xamarin. Forms
NuGet. Você também deve atualizar os outros projetos para usar a mesma versão do pacote NuGet do
xamarin. Forms.
6. No projeto do Mac, clique duas vezes em referências e adicione uma referência ao projeto xamarin. Forms
(projeto de biblioteca de projeto compartilhado ou .NET Standard).

7. Atualização Main.cs para inicializar o AppDelegate :

static class MainClass


{
static void Main(string[] args)
{
NSApplication.Init();
NSApplication.SharedApplication.Delegate = new AppDelegate(); // add this line
NSApplication.Main(args);
}
}

8. Atualização AppDelegate para inicializar o xamarin. Forms, criar uma janela e carregar o aplicativo xamarin.
Forms (Lembre-se de definir um apropriado Title ). Se você tiver outras dependências que precisam ser
inicializados, fazer isso aqui também.

using Xamarin.Forms;
using Xamarin.Forms.Platform.MacOS;
// also add a using for the Xamarin.Forms project, if the namespace is different to this file
...
[Register("AppDelegate")]
public class AppDelegate : FormsApplicationDelegate
{
NSWindow window;
public AppDelegate()
{
var style = NSWindowStyle.Closable | NSWindowStyle.Resizable | NSWindowStyle.Titled;

var rect = new CoreGraphics.CGRect(200, 1000, 1024, 768);


window = new NSWindow(rect, style, NSBackingStore.Buffered, false);
window.Title = "Xamarin.Forms on Mac!"; // choose your own Title here
window.TitleVisibility = NSWindowTitleVisibility.Hidden;
}

public override NSWindow MainWindow


{
get { return window; }
}

public override void DidFinishLaunching(NSNotification notification)


{
Forms.Init();
LoadApplication(new App());
base.DidFinishLaunching(notification);
}
}
9. Clique duas vezes em Main. Storyboard para editar no Xcode. Selecione o janela e desmarque o
controlador inicial é caixa de seleção (Isso ocorre porque o código anterior cria uma janela):

Você pode editar o sistema de menus no storyboard para remover os itens indesejados.
10. Por fim, adicione qualquer recurso local (por exemplo. arquivos de imagem) de projetos de plataforma
existentes que são necessários.
11. Projeto do Mac agora deve executar seu código do xamarin. Forms em macOS!

Próximas etapas
Estilo
Com as alterações recentes feitas OnPlatform agora você pode direcionar qualquer número de plataformas. Isso
inclui o macOS.

<Button.TextColor>
<OnPlatform x:TypeArguments="Color">
<On Platform="iOS" Value="White"/>
<On Platform="macOS" Value="White"/>
<On Platform="Android" Value="Black"/>
</OnPlatform>
</Button.TextColor>

Observe que você também pode dobrar em plataformas como este: <On Platform="iOS, macOS" ...> .
Posição e tamanho da janela
Você pode ajustar o tamanho inicial e o local da janela no AppDelegate :

var rect = new CoreGraphics.CGRect(200, 1000, 1024, 768); // x, y, width, height

Problemas Conhecidos
Esta é uma visualização, portanto, você deve esperar que nem tudo está pronto para produção. Abaixo estão
algumas coisas que você pode encontrar conforme você adiciona o macOS para seus projetos:
Nem todos os NuGets estão prontos para o macOS
Você pode achar que algumas das bibliotecas que você usa não ainda dão suporte a macOS. Nesse caso, você
precisará enviar uma solicitação para o mantenedor do projeto para adicioná-lo. Até que tenham suporte, você
precisa procurar alternativas.
Recursos ausentes do xamarin. Forms
Nem todos os recursos do xamarin. Forms forem concluídos nesta visualização. Para obter mais informações,
consulte suporte de plataforma macOS Status na xamarin. Forms repositório do GitHub.

Links relacionados
Xamarin.Mac
Tizen .NET
12/04/2019 • 2 minutes to read

Tizen .NET permite que você desenvolva aplicativos de Tizen sejam executados em dispositivos Samsung,
incluindo TVs, dispositivos portáteis, dispositivos móveis e outros dispositivos de IoT.
Tizen .NET permite que você crie aplicativos .NET com xamarin. Forms e Tizen .NET framework. Xamarin. Forms
permite que você crie com facilidade interfaces do usuário, enquanto a API TizenFX fornece interfaces para o
hardware que se encontra no modo de TV moderno, móvel, dispositivo portátil e dispositivos IoT. Para obter mais
informações sobre o .NET Tizen, consulte Introdução ao aplicativo do .NET Tizen.

Introdução
Antes de poder começar a desenvolver aplicativos .NET Tizen, primeiro você deve configurar seu ambiente de
desenvolvimento. Para obter mais informações, consulte instalar o Visual Studio Tools for Tizen.
Para obter informações sobre como adicionar um projeto .NET Tizen a uma solução existente do xamarin. Forms,
consulte criando seu primeiro aplicativo .NET Tizen.

Documentação
Documentação do xamarin. Forms – como compilar aplicativos de plataforma cruzada com C# e xamarin.
Forms.
Developer.tizen.org – documentação e vídeos para ajudá-lo a criar e implantar aplicativos Tizen.

Exemplos
Samsung mantém uma bifurcação do exemplos de xamarin. Forms com projetos Tizen adicionados, e há um
repositório separado Tizen-Csharp-Samples que contém projetos adicionais, incluindo o dispositivo portátil e
Demonstrações de TV específicos.
Instalação de plataforma do WPF
12/04/2019 • 6 minutes to read

Xamarin. Forms agora tem suporte de visualização para o Windows Presentation Foundation (WPF ). Este artigo
demonstra como adicionar um projeto do WPF para uma solução xamarin. Forms.
Antes de começar, criar uma nova solução xamarin. Forms no Visual Studio de 2019 ou usar uma solução existente
do xamarin. Forms, por exemplo, BoxViewClock. Você só pode adicionar aplicativos do WPF a uma solução do
xamarin. Forms no Windows.

Adicione um projeto WPF a um aplicativo xamarin. Forms com


Xamarin.University
Xamarin. Forms 3.0 WPF dão suporte, por Xamarin University

Adicionar um aplicativo do WPF


Siga estas instruções para adicionar um aplicativo do WPF que serão executados nas áreas de trabalho do
Windows 7, 8 e 10:
1. No Visual Studio de 2019, clique com botão direito no nome da solução nos Gerenciador de soluções e
escolha Adicionar > Novo projeto... .
2. No novo projeto janela, à esquerda, selecione Visual C# e área de trabalho clássica do Windows. Na
lista de tipos de projeto, escolha aplicativo WPF (.NET Framework).
3. Digite um nome para o projeto com um WPF extensão, por exemplo, BoxViewClock.WPF. Clique o
navegue botão, selecione o BoxViewClock pasta e pressione Selecionar pasta. Isso colocará o projeto
WPF no mesmo diretório que os outros projetos na solução.
Pressione Okey para criar o projeto.
4. No Gerenciador de soluções, à direita, clique no botão new BoxViewClock.WPF do projeto e selecione
Manage NuGet Packages. Selecione o navegue , clique no incluir pré-lançamento caixa de seleção e
pesquise xamarin. Forms.

Selecione em que o pacote e clique no instalar botão.


5. Agora pesquise Xamarin.Forms.Platform.WPF empacotar e instalar aqui também. Verifique se que o
pacote é da Microsoft!
6. Clique com botão direito no nome da solução nos Gerenciador de soluções e selecione gerenciar
pacotes NuGet para solução. Selecione o atualização guia e o xamarin. Forms pacote. Selecione todos
os projetos e atualizá-los para a mesma versão do xamarin. Forms:

7. No projeto do WPF, clique duas vezes em referências. No Gerenciador de referências caixa de diálogo,
selecione projetos na esquerda e verifique a caixa de seleção adjacente para o BoxViewClock projeto:

8. Editar o MainWindow. XAML arquivo do projeto WPF. No Window marca, adicione uma declaração de
namespace XML para o Xamarin.Forms.Platform.WPF assembly e namespace:
xmlns:wpf="clr-namespace:Xamarin.Forms.Platform.WPF;assembly=Xamarin.Forms.Platform.WPF"

Agora, altere a Window marca a wpf:FormsApplicationPage . Alterar o Title definindo como o nome do seu
aplicativo, por exemplo, BoxViewClock. O arquivo XAML concluído deve ter esta aparência:

<wpf:FormsApplicationPage x:Class="BoxViewClock.WPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:wpf="clr-namespace:Xamarin.Forms.Platform.WPF;assembly=Xamarin.Forms.Platform.WPF"
xmlns:local="clr-namespace:BoxViewClock.WPF"
mc:Ignorable="d"
Title="BoxViewClock" Height="450" Width="800">
<Grid>

</Grid>
</wpf:FormsApplicationPage>

9. Editar o MainWindow.xaml.cs arquivo do projeto WPF. Adicione dois novos using diretivas:

using Xamarin.Forms;
using Xamarin.Forms.Platform.WPF;

Altere a classe base da MainWindow partir Window para FormsApplicationPage . Seguindo o


InitializeComponent chamar, adicione as duas instruções a seguir:

Forms.Init();
LoadApplication(new BoxViewClock.App());

Exceto para comentários e não utilizadas using diretivas, completo MainWindows.xaml.cs arquivo deve
ter esta aparência:

using Xamarin.Forms;
using Xamarin.Forms.Platform.WPF;

namespace BoxViewClock.WPF
{
public partial class MainWindow : FormsApplicationPage
{
public MainWindow()
{
InitializeComponent();

Forms.Init();
LoadApplication(new BoxViewClock.App());
}
}
}

10. Clique com botão direito no projeto do WPF na Gerenciador de soluções e selecione definir como
projeto de inicialização. Pressione F5 para executar o programa com o depurador do Visual Studio, na
área de trabalho do Windows:
Próximas etapas
Especificidades da plataforma
Você pode determinar em qual plataforma está em execução no seu aplicativo xamarin. Forms de código ou
XAML. Isso permite que você altere as características do programa quando ele está em execução no WPF. No
código, comparar o valor de Device.RuntimePlatform com o Device.WPF constante (que é igual a cadeia de
caracteres "WPF"). Se houver uma correspondência, o aplicativo está em execução no WPF.
No XAML, você pode usar o OnPlatform marca para selecionar um valor de propriedade específico da plataforma:

<Button.TextColor>
<OnPlatform x:TypeArguments="Color">
<On Platform="iOS" Value="White" />
<On Platform="macOS" Value="White" />
<On Platform="Android" Value="Black" />
<On Platform="WPF" Value="Blue" />
</OnPlatform>
</Button.TextColor>

Tamanho da janela
Você pode ajustar o tamanho inicial da janela no WPF MainWindow. XAML arquivo:

Title="BoxViewClock" Height="450" Width="800"

Problemas
Esta é uma visualização, portanto, você deve esperar que nem tudo está pronto para produção. Nem todos os
pacotes do NuGet para xamarin. Forms estão prontos para WPF, e alguns recursos talvez não esteja funcionando
totalmente.
Especificidades da plataforma
12/04/2019 • 11 minutes to read

baixar o exemplo
Especificidades da plataforma permitem que você consumir funcionalidade só está disponível em uma plataforma
específica, sem implementar renderizadores personalizados ou efeitos.
O processo para o consumo de um específico da plataforma por meio de XAML, ou por meio do código API
fluente é da seguinte maneira:
1. Adicionar um xmlns declaração ou using diretiva para o Xamarin.Forms.PlatformConfiguration namespace.
2. Adicionar um xmlns declaração ou using diretiva para o namespace que contém a funcionalidade específica
da plataforma:
a. No iOS, essa é a Xamarin.Forms.PlatformConfiguration.iOSSpecific namespace.
b. No Android, essa é a Xamarin.Forms.PlatformConfiguration.AndroidSpecific namespace. Para Android
AppCompat, esse é o Xamarin.Forms.PlatformConfiguration.AndroidSpecific.AppCompat namespace.
c. Na plataforma Universal do Windows, isso é o Xamarin.Forms.PlatformConfiguration.WindowsSpecific
namespace.
3. Aplicar o específicos da plataforma de XAML ou de código com o On<T> API fluente. O valor de T pode ser o
iOS , Android , ou Windows tipos do Xamarin.Forms.PlatformConfiguration namespace.

NOTE
Observe que a tentativa de consumir um específico da plataforma em uma plataforma em que ele não está disponível não
resultará em erro. Em vez disso, o código será executado sem o específicos da plataforma que está sendo aplicado.

Especificidades da plataforma consumidos por meio de On<T> retorno da API de código fluente
IPlatformElementConfiguration objetos. Isso permite que várias especificações de plataforma a ser invocado no
mesmo objeto com método em cascata.
Para obter mais informações sobre as especificidades de plataforma fornecido pelo xamarin. Forms, consulte
especificidades da plataforma do iOS, especificidades da plataforma Android, e Windows-especificidades da
plataforma.

Criando as especificidades da plataforma


Fornecedores podem criar seus próprios itens específicos à plataforma com efeitos. Um efeito fornece a
funcionalidade específica, que, em seguida, é exposta por meio de uma plataforma específica. O resultado é um
efeito que pode ser mais facilmente consumido por meio de XAML e um API fluente de código.
O processo para a criação de uma plataforma específica é da seguinte maneira:
1. Implemente a funcionalidade específica como um efeito. Para obter mais informações, consulte criando um
efeito.
2. Crie uma classe específica da plataforma que irá expor o efeito. Para obter mais informações, consulte criando
uma classe específica da plataforma.
3. Na classe específica da plataforma, implemente uma propriedade anexada para permitir que o específicos da
plataforma ser consumida por meio de XAML. Para obter mais informações, consulte adicionando uma
propriedade anexada.
4. Na classe específica da plataforma, implemente métodos de extensão para permitir que o específicos da
plataforma ser consumida por meio de um API fluente de código. Para obter mais informações, consulte
adicionando métodos de extensão.
5. Modifique a implementação em vigor para que o efeito é aplicado somente se a plataforma específica foi
invocada na mesma plataforma como o efeito. Para obter mais informações, consulte criando o efeito de.
O resultado de expor um efeito como uma plataforma específica é que o efeito pode ser consumido com mais
facilidade por meio de XAML e um API fluente de código.

NOTE
É previu que fornecedores usará essa técnica para criar seus próprios-especificidades da plataforma, para facilitar o consumo
por usuários. Embora os usuários podem optar por criar seus próprios especificidades da plataforma, deve-se observar que
ela requer mais código que criar e consumir um efeito.

O aplicativo de exemplo demonstra uma Shadow específicos da plataforma que adiciona uma sombra para o texto
exibido por um Label controle:

O aplicativo de exemplo implementa o Shadow específico da plataforma em cada plataforma, para facilitar a
compreensão. No entanto, além de cada implementação do efeito específico da plataforma, a implementação da
classe sombra é praticamente idêntica para cada plataforma. Portanto, este guia concentra-se na implementação
da classe de sombra e efeito associado em uma única plataforma.
Para obter mais informações sobre os efeitos, consulte personalizar controles com efeitos.
Criando uma classe específica da plataforma
Uma plataforma específica é criada como um public static classe:

namespace MyCompany.Forms.PlatformConfiguration.iOS
{
public static Shadow
{
...
}
}

As seções a seguir discutem a implementação do Shadow efeito específico da plataforma e associado.


Adicionando uma propriedade anexada
Uma propriedade anexada deve ser adicionada para o Shadow específicos da plataforma para permitir o consumo
por meio de XAML:

namespace MyCompany.Forms.PlatformConfiguration.iOS
{
using System.Linq;
using Xamarin.Forms;
using Xamarin.Forms.PlatformConfiguration;
using FormsElement = Xamarin.Forms.Label;

public static class Shadow


{
const string EffectName = "MyCompany.LabelShadowEffect";

public static readonly BindableProperty IsShadowedProperty =


BindableProperty.CreateAttached("IsShadowed",
typeof(bool),
typeof(Shadow),
false,
propertyChanged: OnIsShadowedPropertyChanged);

public static bool GetIsShadowed(BindableObject element)


{
return (bool)element.GetValue(IsShadowedProperty);
}

public static void SetIsShadowed(BindableObject element, bool value)


{
element.SetValue(IsShadowedProperty, value);
}

...

static void OnIsShadowedPropertyChanged(BindableObject element, object oldValue, object newValue)


{
if ((bool)newValue)
{
AttachEffect(element as FormsElement);
}
else
{
DetachEffect(element as FormsElement);
}
}

static void AttachEffect(FormsElement element)


{
IElementController controller = element;
if (controller == null || controller.EffectIsAttached(EffectName))
{
return;
}
element.Effects.Add(Effect.Resolve(EffectName));
}

static void DetachEffect(FormsElement element)


{
IElementController controller = element;
if (controller == null || !controller.EffectIsAttached(EffectName))
{
return;
}

var toRemove = element.Effects.FirstOrDefault(e => e.ResolveId ==


Effect.Resolve(EffectName).ResolveId);
if (toRemove != null)
{
element.Effects.Remove(toRemove);
}
}
}
}

O IsShadowed propriedade anexada é usada para adicionar o MyCompany.LabelShadowEffect efeito e removê-lo do


controle que o Shadow classe está anexado ao. Isso anexado propriedade registra o OnIsShadowedPropertyChanged
método que será executado quando o valor da propriedade é alterado. Por sua vez, esse método chama o
AttachEffect ou DetachEffect método para adicionar ou remover o efeito com base no valor da IsShadowed
propriedade anexada. O efeito é adicionado ou removido do controle, modificando o controle Effects coleção.

NOTE
Observe que o efeito é resolvido, especificando um valor que é uma concatenação do nome do grupo de resolução e
identificador exclusivo que é especificado na implementação do efeito. Para obter mais informações, consulte criando um
efeito.

Para obter mais informações sobre propriedades anexadas, consulte propriedades anexadas.
Adicionando métodos de extensão
Métodos de extensão devem ser adicionados para o Shadow específicos da plataforma para permitir o consumo
por meio de um API fluente de código:

namespace MyCompany.Forms.PlatformConfiguration.iOS
{
using System.Linq;
using Xamarin.Forms;
using Xamarin.Forms.PlatformConfiguration;
using FormsElement = Xamarin.Forms.Label;

public static class Shadow


{
...
public static bool IsShadowed(this IPlatformElementConfiguration<iOS, FormsElement> config)
{
return GetIsShadowed(config.Element);
}

public static IPlatformElementConfiguration<iOS, FormsElement> SetIsShadowed(this


IPlatformElementConfiguration<iOS, FormsElement> config, bool value)
{
SetIsShadowed(config.Element, value);
return config;
}
...
}
}

O IsShadowed e SetIsShadowed chamar get de métodos de extensão e definir acessadores para o IsShadowed
anexado a propriedade, respectivamente. Cada método de extensão funciona com o
IPlatformElementConfiguration<iOS, FormsElement> tipo, que especifica que a plataforma específica pode ser
invocada sob Label instâncias do iOS.
Criando o efeito
O Shadow específico da plataforma adiciona a MyCompany.LabelShadowEffect para um Label e a remove. O
seguinte exemplo de código mostra o LabelShadowEffect implementação para o projeto do iOS:
[assembly: ResolutionGroupName("MyCompany")]
[assembly: ExportEffect(typeof(LabelShadowEffect), "LabelShadowEffect")]
namespace ShadowPlatformSpecific.iOS
{
public class LabelShadowEffect : PlatformEffect
{
protected override void OnAttached()
{
UpdateShadow();
}

protected override void OnDetached()


{
}

protected override void OnElementPropertyChanged(PropertyChangedEventArgs args)


{
base.OnElementPropertyChanged(args);

if (args.PropertyName == Shadow.IsShadowedProperty.PropertyName)
{
UpdateShadow();
}
}

void UpdateShadow()
{
try
{
if (((Label)Element).OnThisPlatform().IsShadowed())
{
Control.Layer.CornerRadius = 5;
Control.Layer.ShadowColor = UIColor.Black.CGColor;
Control.Layer.ShadowOffset = new CGSize(5, 5);
Control.Layer.ShadowOpacity = 1.0f;
}
else if (!((Label)Element).OnThisPlatform().IsShadowed())
{
Control.Layer.ShadowOpacity = 0;
}
}
catch (Exception ex)
{
Console.WriteLine("Cannot set property on attached control. Error: ", ex.Message);
}
}
}
}

O UpdateShadow método define Control.Layer as propriedades para criar a sombra, desde que o IsShadowed
propriedade anexada é definida como true e desde que o Shadow específicos da plataforma foi invocado na
mesma plataforma que o Efeito é implementado para. Essa verificação é realizada com o OnThisPlatform método.
Se o Shadow.IsShadowed anexado alterações de valor de propriedade em tempo de execução, o efeito precisa
responder, removendo a sombra. Portanto, uma versão de substituição de OnElementPropertyChanged método é
usado para responder à alteração de propriedade associável chamando o UpdateShadow método.
Para obter mais informações sobre como criar um efeito, consulte criando um efeito e passando os parâmetros de
efeito como propriedades anexadas.
Consumindo o específicos da plataforma
O Shadow específico da plataforma é consumido em XAML, definindo o Shadow.IsShadowed anexado à
propriedade um boolean valor:
<ContentPage xmlns:ios="clr-namespace:MyCompany.Forms.PlatformConfiguration.iOS" ...>
...
<Label Text="Label Shadow Effect" ios:Shadow.IsShadowed="true" ... />
...
</ContentPage>

Como alternativa, ele pode ser consumido de C# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using MyCompany.Forms.PlatformConfiguration.iOS;

...

shadowLabel.On<iOS>().SetIsShadowed(true);

Links relacionados
PlatformSpecifics (amostra)
ShadowPlatformSpecific (amostra)
Especificidades da plataforma do iOS
Especificidades da plataforma Android
Especificidades da plataforma Windows
Personalizar controles com efeitos
Propriedades anexadas
PlatformConfiguration API
Recursos da plataforma Windows
12/04/2019 • 4 minutes to read

Desenvolvimento de aplicativos xamarin. Forms para plataformas do Windows requer o Visual Studio. O página
de requisitos contém mais informações sobre os pré-requisitos.

Especificidades da plataforma
Especificidades da plataforma permitem que você consumir funcionalidade só está disponível em uma plataforma
específica, sem implementar renderizadores personalizados ou efeitos.
A seguinte funcionalidade específica da plataforma é fornecida para exibições do xamarin. Forms, páginas e
layouts no Universal Windows Platform (UWP ):
Definindo uma tecla de acesso para um VisualElement . Para obter mais informações, consulte VisualElement
chaves de acesso no Windows.
Desabilitar o modo de cor herdados em um com suporte VisualElement . Para obter mais informações,
consulte modo de cor VisualElement herdado no Windows.
A seguinte funcionalidade específica da plataforma é fornecida para modos de exibição do xamarin. Forms na
UWP:
Detectando a ordem de leitura do conteúdo de texto Entry , Editor , e Label instâncias. Para obter mais
informações, consulte InputView a ordem de leitura no Windows.
Habilitando o suporte de gestos de toque em um ListView . Para obter mais informações, consulte ListView
SelectionMode no Windows.
Habilitando um SearchBar para interagir com o mecanismo de verificação ortográfica. Para obter mais
informações, consulte SearchBar de verificação ortográfica no Windows.
Habilitando um WebView para exibir alertas de JavaScript em uma caixa de diálogo de mensagem UWP. Para
obter mais informações, consulte alertas de JavaScript do WebView no Windows.
A seguinte funcionalidade específica da plataforma é fornecida para páginas do xamarin. Forms na UWP:
Recolher o MasterDetailPage barra de navegação. Para obter mais informações, consulte MasterDetailPage
barra de navegação no Windows.
Definindo opções de posicionamento da barra de ferramentas. Para obter mais informações, consulte
posicionamento da barra de ferramentas de página no Windows.
Habilitar ícones de página a ser exibido em uma TabbedPage barra de ferramentas. Para obter mais
informações, consulte TabbedPage ícones no Windows.
Suporte de plataforma
Os modelos do xamarin. Forms disponíveis no Visual Studio contêm um projeto de plataforma Universal do
Windows (UWP ).

NOTE
Suporte de xamarin. Forms 1.x e 2.x Windows Phone 8 Silverlight, Windows Phone 8.1, e Windows 8.1 desenvolvimento de
aplicativos. No entanto, esses tipos de projeto foram preteridos.

Introdução
Vá para arquivo > Novo > projeto no Visual Studio e escolha uma da plataforma cruzada > aplicativo em
branco (xamarin. Forms) modelos para começar.
Soluções antigas do xamarin. Forms, ou aqueles criados no macOS, não terá todos os projetos do Windows
listados acima (mas eles precisam ser adicionados manualmente). Se a plataforma do Windows que você deseja
direcionar ainda não estiver em sua solução, visite o instruções de instalação para adicionar os Windows
desejados tipo/s do projeto.

Exemplos
Todos os exemplos para livro Charles Petzold criação de aplicativos móveis com xamarin. Forms incluir projetos
de plataforma Universal do Windows (para Windows 10).
O aplicativo de demonstração de "Scott Hanselman" está disponível separadamente e também inclui projetos de
Apple Watch e o Android Wear (usando xamarin. IOS e xamarin. Android, respectivamente, xamarin. Forms não é
executado nessas plataformas).

Links relacionados
Projetos de instalação do Windows
Ordem de leitura de InputView no Windows
12/04/2019 • 2 minutes to read

Baixar o exemplo
Essa plataforma específicas de plataforma Universal do Windows permite que a ordem de leitura (esquerda para a
direita ou à direita para esquerda) do texto bidirecional no Entry , Editor e Label instâncias para ser detectada
dinamicamente. Ele é consumido em XAML, definindo o InputView.DetectReadingOrderFromContent (para Entry e
Editor instâncias) ou Label.DetectReadingOrderFromContent anexado à propriedade um boolean valor:

<ContentPage ...
xmlns:windows="clr-
namespace:Xamarin.Forms.PlatformConfiguration.WindowsSpecific;assembly=Xamarin.Forms.Core">
<StackLayout>
<Editor ... windows:InputView.DetectReadingOrderFromContent="true" />
...
</StackLayout>
</ContentPage>

Como alternativa, ele pode ser consumido de C# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;
...

editor.On<Windows>().SetDetectReadingOrderFromContent(true);

O Editor.On<Windows> método Especifica que este específicos da plataforma só serão executado na plataforma
Universal do Windows. O InputView.SetDetectReadingOrderFromContent método, no
Xamarin.Forms.PlatformConfiguration.WindowsSpecific namespace, é usada para controlar se a ordem de leitura é
detectada de conteúdo a InputView . Além disso, o InputView.SetDetectReadingOrderFromContent método pode ser
usado para ativar ou desativar a ordem de leitura é detectada do conteúdo por meio da chamada a
InputView.GetDetectReadingOrderFromContent método para retornar o valor atual:

editor.On<Windows>().SetDetectReadingOrderFromContent(!editor.On<Windows>
().GetDetectReadingOrderFromContent());

O resultado é que Entry , Editor , e Label instâncias podem ter a ordem de leitura de seus conteúdos
detectadas dinamicamente:
NOTE
Ao contrário da configuração de FlowDirection propriedade, a lógica para modos de exibição que detectar que a ordem
de leitura do seu conteúdo de texto não afetará o alinhamento do texto dentro da exibição. Em vez disso, ele ajusta a ordem
na qual os blocos de texto bidirecional são apresentados.

Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
WindowsSpecific API
ListView SelectionMode no Windows
12/04/2019 • 3 minutes to read

Baixar o exemplo
Na plataforma Universal do Windows, por padrão, o xamarin. Forms ListView usa nativo ItemClick eventos
para responder à interação, em vez de nativo Tapped eventos. Isso fornece funcionalidades de acessibilidade para
que o Narrador do Windows e o teclado podem interagir com o ListView . No entanto, ele também processa
qualquer gestos de toque dentro a ListView inoperável.
Este controles específicos da plataforma de plataforma Universal do Windows se itens em uma ListView pode
responder para gestos de toque e, portanto, se nativo ListView é acionado o ItemClick ou Tapped eventos. Ele é
consumido em XAML, definindo o ListView.SelectionMode propriedade anexada a um valor da
ListViewSelectionMode enumeração:

<ContentPage ...
xmlns:windows="clr-
namespace:Xamarin.Forms.PlatformConfiguration.WindowsSpecific;assembly=Xamarin.Forms.Core">
<StackLayout>
<ListView ... windows:ListView.SelectionMode="Inaccessible">
...
</ListView>
</StackLayout>
</ContentPage>

Como alternativa, ele pode ser consumido de C# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;
...

listView.On<Windows>().SetSelectionMode(ListViewSelectionMode.Inaccessible);

O ListView.On<Windows> método Especifica que este específicos da plataforma só serão executado na plataforma
Universal do Windows. O ListView.SetSelectionMode método, no
Xamarin.Forms.PlatformConfiguration.WindowsSpecific namespace, é usada para controlar se itens em um
ListView pode responder para toque gestos, com o ListViewSelectionMode enumeração fornecendo dois valores
possíveis:
Accessible – indica que o ListView acionarão nativo ItemClick eventos para manipular a interação e,
portanto, fornecer funcionalidades de acessibilidade. Portanto, o Narrador do Windows e o teclado podem
interagir com o ListView . No entanto, os itens no ListView não pode responder para gestos de toque. Esse é
o comportamento padrão para ListView instâncias na plataforma Universal do Windows.
Inaccessible – indica que o ListView acionarão nativo Tapped eventos para manipular a interação. Portanto,
os itens no ListView pode responder para gestos de toque. No entanto, não há nenhuma funcionalidade de
acessibilidade e, portanto, o Narrador do Windows e o teclado não é possível interagir com o ListView .
NOTE
O Accessible e Inaccessible modos de seleção são mutuamente exclusivos, e você precisará escolher entre uma
acessível ListView ou um ListView que pode responder a gestos de toque.

Além disso, o GetSelectionMode método pode ser usado para retornar atual ListViewSelectionMode .
O resultado é que o especificado ListViewSelectionMode é aplicado ao ListView , que controla se itens do
ListView pode responder para gestos de toque e, portanto, se nativo ListView é acionado o ItemClick ou
Tapped eventos.

Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
WindowsSpecific API
Barra de navegação MasterDetailPage no Windows
12/04/2019 • 2 minutes to read

Baixar o exemplo
Essa plataforma específicas de plataforma Universal do Windows é usada para recolher a barra de navegação em
um MasterDetailPage e é consumido em XAML, definindo o MasterDetailPage.CollapseStyle e
MasterDetailPage.CollapsedPaneWidth propriedades anexadas:

<MasterDetailPage ...
xmlns:windows="clr-
namespace:Xamarin.Forms.PlatformConfiguration.WindowsSpecific;assembly=Xamarin.Forms.Core"
windows:MasterDetailPage.CollapseStyle="Partial"
windows:MasterDetailPage.CollapsedPaneWidth="48">
...
</MasterDetailPage>

Como alternativa, ele pode ser consumido de c# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;
...

page.On<Windows>().SetCollapseStyle(CollapseStyle.Partial).CollapsedPaneWidth(148);

O MasterDetailPage.On<Windows> método Especifica que este específicos da plataforma serão executado apenas no
Windows. O Page.SetCollapseStyle método, no Xamarin.Forms.PlatformConfiguration.WindowsSpecific namespace,
é usado para especificar o estilo de recolher, com o CollapseStyle enumeração fornecendo dois valores: Full e
Partial . O MasterDetailPage.CollapsedPaneWidth método é usado para especificar a largura de uma barra de
navegação colapsada parcialmente.
O resultado é que o especificado CollapseStyle é aplicado para o MasterDetailPage instância, com a largura
também está sendo especificada:
Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
WindowsSpecific API
Posicionamento da barra de ferramentas da página
no Windows
12/04/2019 • 2 minutes to read

Baixar o exemplo
Específico da plataforma essa plataforma Universal do Windows é usado para alterar o posicionamento de uma
barra de ferramentas em uma Page e consumido em XAML, definindo o Page.ToolbarPlacement anexado à
propriedade um valor de ToolbarPlacement enumeração:

<TabbedPage ...
xmlns:windows="clr-
namespace:Xamarin.Forms.PlatformConfiguration.WindowsSpecific;assembly=Xamarin.Forms.Core"
windows:Page.ToolbarPlacement="Bottom">
...
</TabbedPage>

Como alternativa, ele pode ser consumido de c# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;
...

page.On<Windows>().SetToolbarPlacement(ToolbarPlacement.Bottom);

O Page.On<Windows> método Especifica que este específicos da plataforma serão executado apenas no Windows.
O Page.SetToolbarPlacement método, no Xamarin.Forms.PlatformConfiguration.WindowsSpecific namespace, é
usado para definir o posicionamento da barra de ferramentas, com o ToolbarPlacement fornecendo de
enumeração três valores: Default , Top , e Bottom .
O resultado é que o posicionamento da barra de ferramentas especificada é aplicado para o Page instância:
Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
WindowsSpecific API
Projetos de instalação do Windows
12/04/2019 • 6 minutes to read

Adição de novos projetos do Windows a uma solução existente do xamarin. Forms


Soluções antigas do xamarin. Forms (ou aquelas criadas no macOS ) não terá a projetos de aplicativo da
plataforma Universal do Windows (UWP ). Portanto, você precisará adicionar manualmente um projeto UWP
para criar um aplicativo do Windows 10 (UWP ).

Adicionar um Universal Windows Platform app


Visual Studio de 2019 na Windows 10 é recomendado para criar aplicativos da UWP. Para obter mais
informações sobre a plataforma Universal do Windows, consulte Introdução à plataforma Windows Universal.
UWP está disponível no xamarin. Forms 2.1 e posterior e Xamarin.Forms.Maps tem suporte no xamarin. Forms
2.2 e posterior.
Verifique as solução de problemas seção para obter dicas úteis.
Siga estas instruções para adicionar um aplicativo UWP que será executado em telefones, tablets e desktops
Windows 10:
1 . Clique com botão direito na solução e selecione Adicionar > Novo projeto... e adicione uma aplicativo em
branco (Universal Windows) projeto:

2 . No novo projeto da plataforma Windows Universal caixa de diálogo, selecione as versões mínima e de
destino do Windows 10 que o aplicativo será executado em:

3 . Clique com botão direito no projeto UWP e selecione gerenciar pacotes NuGet... e adicione o xamarin.
Forms pacote. Certifique-se de que os outros projetos na solução também são atualizados para a mesma versão
do pacote do xamarin. Forms.
4 . Verifique se o novo projeto UWP será compilado na compilar > Configuration Manager janela (isso
provavelmente não ter ocorrido por padrão). Escala de construir e implantar caixas para o projeto Universal:
5 . Clique com botão direito no projeto e selecione Add > referência e criar uma referência ao projeto de
aplicativo xamarin. Forms (.NET Standard ou projeto compartilhado).

6 . No projeto UWP, edite App.xaml.cs para incluir o Init chamada do método dentro de OnLaunched método
perto da linha 52:

// under this line


rootFrame.NavigationFailed += OnNavigationFailed;
// add this line
Xamarin.Forms.Forms.Init (e); // requires the `e` parameter

7 . No projeto UWP, edite MainPage. XAML removendo a Grid contidos o Page elemento.
8 . Na MainPage. XAML, adicione uma nova xmlns entrada de Xamarin.Forms.Platform.UWP :

xmlns:forms="using:Xamarin.Forms.Platform.UWP"

9 . Na MainPage. XAML, alterar a raiz <Page elemento <forms:WindowsPage :

<forms:WindowsPage
...
xmlns:forms="using:Xamarin.Forms.Platform.UWP"
...
</forms:WindowsPage>

10 . No projeto UWP, edite MainPage.xaml.cs para remover o : Page especificador de herança para o nome
da classe (uma vez que ele agora herda WindowsPage devido à alteração feita na etapa anterior):

public sealed partial class MainPage // REMOVE ": Page"

11 . No MainPage.xaml.cs, adicione o LoadApplication chamar o MainPage construtor para iniciar o aplicativo


xamarin. Forms:
// below this existing line
this.InitializeComponent();
// add this line
LoadApplication(new YOUR_NAMESPACE.App());

12 . Adicione qualquer recurso local (por exemplo. arquivos de imagem) de projetos de plataforma existentes
que são necessários.

Solução de problemas
"Exceção de invocação de destino" ao usar "Compilar com cadeia de ferramentas nativas do .NET"
Se seu aplicativo da UWP está fazendo referência a vários assemblies (por exemplo bibliotecas de controle de
terceiros, ou seu próprio aplicativo é dividido em várias bibliotecas), xamarin. Forms talvez não consiga carregar
objetos desses assemblies (como renderizadores personalizados).
Isso pode ocorrer ao usar o compilar com cadeia de ferramentas .NET Native que é uma opção para
aplicativos UWP na Propriedades > Build > geral janela para o projeto.
Você pode corrigir isso usando uma sobrecarga específica de UWP do Forms.Init chamar App.xaml.cs
conforme mostrado no código a seguir (você deve substituir ClassInOtherAssembly com uma classe real do seu
código faz referência):

// You'll need to add `using System.Reflection;`


List<Assembly> assembliesToInclude = new List<Assembly>();

// Now, add in all the assemblies your app uses


assembliesToInclude.Add(typeof (ClassInOtherAssembly).GetTypeInfo().Assembly);

// Also do this for all your other 3rd party libraries


Xamarin.Forms.Forms.Init(e, assembliesToInclude);
// replaces Xamarin.Forms.Forms.Init(e);

Adicione uma entrada para cada assembly que você adicionou como uma referência no Gerenciador de
soluções, por meio de uma referência direta ou um NuGet.
Compilação nativa de serviços de dependência e .NET
Builds de versão usando a compilação do .NET nativo podem fazer para resolver os serviços de dependência
que são definidos fora o executável de aplicativo principal (como em um projeto separado ou biblioteca).
Use o DependencyService.Register<T>() método para registrar manualmente as classes de serviço de
dependência. Com base no exemplo acima, adicione o método register como este:

Xamarin.Forms.Forms.Init(e, assembliesToInclude);
Xamarin.Forms.DependencyService.Register<ClassInOtherAssembly>(); // add this
Verificação ortográfica SearchBar no Windows
12/04/2019 • 2 minutes to read

Baixar o exemplo
Essa plataforma específicas de plataforma Universal do Windows permite que um SearchBar para interagir com o
mecanismo de verificação ortográfica. Ele é consumido em XAML, definindo o SearchBar.IsSpellCheckEnabled
anexado à propriedade um boolean valor:

<ContentPage ...
xmlns:windows="clr-
namespace:Xamarin.Forms.PlatformConfiguration.WindowsSpecific;assembly=Xamarin.Forms.Core">
<StackLayout>
<SearchBar ... windows:SearchBar.IsSpellCheckEnabled="true" />
...
</StackLayout>
</ContentPage>

Como alternativa, ele pode ser consumido de c# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;
...

searchBar.On<Windows>().SetIsSpellCheckEnabled(true);

O SearchBar.On<Windows> método Especifica que este específicos da plataforma só serão executado na plataforma
Universal do Windows. O SearchBar.SetIsSpellCheckEnabled método, no
Xamarin.Forms.PlatformConfiguration.WindowsSpecific e no namespace, desativa o verificador ortográfico. Além
disso, o SearchBar.SetIsSpellCheckEnabled método pode ser usado para ativar/desativar a verificação ortográfica,
chamando o SearchBar.GetIsSpellCheckEnabled método para retornar se o verificador ortográfico está habilitado:

searchBar.On<Windows>().SetIsSpellCheckEnabled(!searchBar.On<Windows>().GetIsSpellCheckEnabled());

O resultado é inserido no texto a SearchBar pode ser ortografia verificada, com erros de ortografia incorretos
sendo indicados para o usuário:
NOTE
O SearchBar classe de Xamarin.Forms.PlatformConfiguration.WindowsSpecific também tem um namespace
EnableSpellCheck e DisableSpellCheck métodos que podem ser usados para habilitar e desabilitar o verificador
ortográfico no SearchBar , respectivamente.

Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
WindowsSpecific API
Ícones de TabbedPage no Windows
12/04/2019 • 2 minutes to read

Baixar o exemplo
Essa plataforma específicas de plataforma Universal do Windows permite que os ícones de página a ser exibido
em uma TabbedPage barra de ferramentas e fornece a capacidade de, opcionalmente, especificar o tamanho do
ícone. Ele é consumido em XAML, definindo o TabbedPage.HeaderIconsEnabled anexado à propriedade true e,
opcionalmente, definindo o TabbedPage.HeaderIconsSize anexado à propriedade um Size valor:

<TabbedPage ...
xmlns:windows="clr-
namespace:Xamarin.Forms.PlatformConfiguration.WindowsSpecific;assembly=Xamarin.Forms.Core"
windows:TabbedPage.HeaderIconsEnabled="true">
<windows:TabbedPage.HeaderIconsSize>
<Size>
<x:Arguments>
<x:Double>24</x:Double>
<x:Double>24</x:Double>
</x:Arguments>
</Size>
</windows:TabbedPage.HeaderIconsSize>
<ContentPage Title="Todo" Icon="todo.png">
...
</ContentPage>
<ContentPage Title="Reminders" Icon="reminders.png">
...
</ContentPage>
<ContentPage Title="Contacts" Icon="contacts.png">
...
</ContentPage>
</TabbedPage>

Como alternativa, ele pode ser consumido de C# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;
...

public class WindowsTabbedPageIconsCS : Xamarin.Forms.TabbedPage


{
public WindowsTabbedPageIconsCS()
{
On<Windows>().SetHeaderIconsEnabled(true);
On<Windows>().SetHeaderIconsSize(new Size(24, 24));

Children.Add(new ContentPage { Title = "Todo", Icon = "todo.png" });


Children.Add(new ContentPage { Title = "Reminders", Icon = "reminders.png" });
Children.Add(new ContentPage { Title = "Contacts", Icon = "contacts.png" });
}
}

O TabbedPage.On<Windows> método Especifica que este específicos da plataforma só serão executado na plataforma
Universal do Windows. O TabbedPage.SetHeaderIconsEnabled método, no
Xamarin.Forms.PlatformConfiguration.WindowsSpecific namespace, é usado para ativar ou desativar os ícones de
cabeçalho. O TabbedPage.SetHeaderIconsSize método, opcionalmente, especifica o tamanho do ícone de cabeçalho
com um Size valor.
Além disso, o TabbedPage classe o Xamarin.Forms.PlatformConfiguration.WindowsSpecific namespace também tem
um EnableHeaderIcons método que permite que os ícones de cabeçalho, uma DisableHeaderIcons método que
desabilita os ícones de cabeçalho, e uma IsHeaderIconsEnabled método que retorna um boolean valor que indica
se os ícones de cabeçalho estão habilitados.
O resultado é que essa página ícones podem ser exibidos em uma TabbedPage barra de ferramentas, com o
tamanho do ícone, opcionalmente, que está sendo definido como um tamanho desejado:

Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
WindowsSpecific API
Chaves de acesso de VisualElement no Windows
12/04/2019 • 6 minutes to read

Baixar o exemplo
Chaves de acesso são atalhos de teclado que melhoram a usabilidade e a acessibilidade de aplicativos na
plataforma Universal de Windows (UWP ), fornecendo uma maneira intuitiva para os usuários a navegar
rapidamente e interagir com a interface do usuário visível do aplicativo por meio de um teclado em vez de por
meio de toque ou um mouse. Eles são combinações da tecla Alt e uma ou mais chaves alfanuméricas,
normalmente pressionadas em sequência. Atalhos de teclado automaticamente têm suporte para chaves de
acesso que usam um único caractere alfanumérico.
Dicas de tecla de acesso são flutuantes selos exibidos ao lado de controles que incluem as chaves de acesso. Cada
dica de tecla de acesso contém as chaves alfanuméricas que ativam o controle associado. Quando um usuário
pressiona a tecla Alt, as dicas de tecla de acesso são exibidas.
Essa plataforma específica de UWP é usada para especificar uma chave de acesso para um VisualElement . Ele é
consumido em XAML, definindo o VisualElement.AccessKey propriedade anexada para um valor alfanumérico e,
opcionalmente, definindo o VisualElement.AccessKeyPlacement propriedade anexada com o valor de
AccessKeyPlacement enumeração, o VisualElement.AccessKeyHorizontalOffset anexado à propriedade um double e
a VisualElement.AccessKeyVerticalOffset propriedade anexada a um double :

<TabbedPage ...
xmlns:windows="clr-
namespace:Xamarin.Forms.PlatformConfiguration.WindowsSpecific;assembly=Xamarin.Forms.Core">
<ContentPage Title="Page 1"
windows:VisualElement.AccessKey="1">
<StackLayout Margin="20">
...
<Switch windows:VisualElement.AccessKey="A" />
<Entry Placeholder="Enter text here"
windows:VisualElement.AccessKey="B" />
...
<Button Text="Access key F, placement top with offsets"
Margin="20"
Clicked="OnButtonClicked"
windows:VisualElement.AccessKey="F"
windows:VisualElement.AccessKeyPlacement="Top"
windows:VisualElement.AccessKeyHorizontalOffset="20"
windows:VisualElement.AccessKeyVerticalOffset="20" />
...
</StackLayout>
</ContentPage>
...
</TabbedPage>

Como alternativa, ele pode ser consumido de C# usando a API fluente:


using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;
...

var page = new ContentPage { Title = "Page 1" };


page.On<Windows>().SetAccessKey("1");

var switchView = new Switch();


switchView.On<Windows>().SetAccessKey("A");
var entry = new Entry { Placeholder = "Enter text here" };
entry.On<Windows>().SetAccessKey("B");
...

var button4 = new Button { Text = "Access key F, placement top with offsets", Margin = new Thickness(20) };
button4.Clicked += OnButtonClicked;
button4.On<Windows>()
.SetAccessKey("F")
.SetAccessKeyPlacement(AccessKeyPlacement.Top)
.SetAccessKeyHorizontalOffset(20)
.SetAccessKeyVerticalOffset(20);
...

O VisualElement.On<Windows> método Especifica que este específicos da plataforma só serão executado na


plataforma Universal do Windows. O VisualElement.SetAccessKey método, no
Xamarin.Forms.PlatformConfiguration.WindowsSpecific namespace, é usado para definir o valor de chave de acesso
para o VisualElement . O VisualElement.SetAccessKeyPlacement método, opcionalmente, especifica a posição a ser
usado para exibir a dica de tecla de acesso, com o AccessKeyPlacement enumeração fornecendo os seguintes
valores possíveis:
Auto – indica que o posicionamento da dica de tecla de acesso será determinado pelo sistema operacional.
Top – indica que a dica de tecla de acesso será exibido acima da borda superior do VisualElement .
Bottom – indica que a dica de tecla de acesso será exibido abaixo da borda inferior do VisualElement .
Right – indica que a dica de tecla de acesso será exibido à direita da borda direita do VisualElement .
Left – indica que a dica de tecla de acesso será exibido à esquerda da borda esquerda do VisualElement .
Center – indica que a dica de tecla de acesso aparecem sobreposta no centro do VisualElement .

NOTE
Normalmente, o Auto posicionamento da dica de tecla é suficiente, que inclui suporte para interfaces do usuário adaptável.

O VisualElement.SetAccessKeyHorizontalOffset e VisualElement.SetAccessKeyVerticalOffset métodos podem ser


usados para um controle mais granular do local de dica de tecla de acesso. O argumento para o
SetAccessKeyHorizontalOffset método indica como o momento para mover a dica de tecla de acesso para a
esquerda ou direita e o argumento para o SetAccessKeyVerticalOffset método indica o quanto mover a dica de
tecla de acesso para cima ou para baixo.

NOTE
Deslocamentos de dica de tecla de acesso não podem ser definidos quando o posicionamento de chave de acesso é definido
Auto .

Além disso, o GetAccessKey , GetAccessKeyPlacement , GetAccessKeyHorizontalOffset , e


GetAccessKeyVerticalOffset métodos podem ser usados para recuperar um acesso de valor e do local da chave.
O resultado é que as dicas de tecla de acesso podem ser exibidas ao lado de qualquer VisualElement instâncias
que definem a acessar as chaves, pressionando a tecla Alt:

Quando um usuário ativa uma chave de acesso, pressionando a tecla Alt, seguida pelo acesso de chave, a ação
padrão para o VisualElement será executado. Por exemplo, quando um usuário ativa a chave de acesso em uma
Switch , o Switch é alternada. Quando um usuário ativa a chave de acesso em uma Entry , o Entry ganha o
foco. Quando um usuário ativa a chave de acesso em uma Button , o manipulador de eventos para o Clicked
eventos é executado.
Para obter mais informações sobre chaves de acesso, consulte chaves de acesso.

Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
WindowsSpecific API
Modo de cor VisualElement herdado no Windows
12/04/2019 • 2 minutes to read

Baixar o exemplo
Algumas das exibições de xamarin. Forms apresentam um modo de cor herdado. Nesse modo, quando o
IsEnabled propriedade do modo de exibição é definida como false , o modo de exibição substituirá as cores
definidas pelo usuário com os nativo as cores padrão para o estado desabilitado. Para versões anteriores
compatibilidade, esse modo herdado cor permanece o comportamento padrão para modos de exibição com
suporte.
Essa plataforma específicas de plataforma Universal do Windows desabilita a esse modo herdado de cor, para que
as cores definidas em uma exibição pelo usuário permanecem mesmo quando o modo de exibição está
desabilitado. Ele é consumido em XAML, definindo o VisualElement.IsLegacyColorModeEnabled anexado à
propriedade false :

<ContentPage ...
xmlns:windows="clr-
namespace:Xamarin.Forms.PlatformConfiguration.WindowsSpecific;assembly=Xamarin.Forms.Core">
<StackLayout>
...
<Editor Text="Enter text here"
TextColor="Blue"
BackgroundColor="Bisque"
windows:VisualElement.IsLegacyColorModeEnabled="False" />
...
</StackLayout>
</ContentPage>

Como alternativa, ele pode ser consumido de C# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;
...

_legacyColorModeDisabledEditor.On<Windows>().SetIsLegacyColorModeEnabled(false);

O VisualElement.On<Windows> método Especifica que este específicos da plataforma serão executado apenas no
Windows. O VisualElement.SetIsLegacyColorModeEnabled método, no
Xamarin.Forms.PlatformConfiguration.WindowsSpecific namespace, é usada para controlar se o modo de cor
herdados é desabilitado. Além disso, o VisualElement.GetIsLegacyColorModeEnabled método pode ser usado para
retornar se o modo de cor herdado está desabilitado.
O resultado é que o modo herdado de cor pode ser desabilitado, para que as cores definidas em uma exibição pelo
usuário permaneçam até mesmo quando o modo de exibição está desabilitado:
NOTE
Ao definir uma VisualStateGroup em uma exibição, o modo herdado de cor é totalmente ignorado. Para obter mais
informações sobre estados visuais, consulte o Gerenciador de estado Visual xamarin. Forms.

Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
WindowsSpecific API
Alertas do WebView do JavaScript no Windows
12/04/2019 • 2 minutes to read

Baixar o exemplo
Este específicos da plataforma permite que um WebView para exibir alertas de JavaScript em uma caixa de diálogo
de mensagem UWP. Ele é consumido em XAML, definindo o WebView.IsJavaScriptAlertEnabled anexado à
propriedade um boolean valor:

<ContentPage ...
xmlns:windows="clr-
namespace:Xamarin.Forms.PlatformConfiguration.WindowsSpecific;assembly=Xamarin.Forms.Core">
<StackLayout>
<WebView ... windows:WebView.IsJavaScriptAlertEnabled="true" />
...
</StackLayout>
</ContentPage>

Como alternativa, ele pode ser consumido de c# usando a API fluente:

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;
...

var webView = new Xamarin.Forms.WebView


{
Source = new HtmlWebViewSource
{
Html = @"<html><body><button onclick=""window.alert('Hello World from JavaScript');"">Click Me</button>
</body></html>"
}
};
webView.On<Windows>().SetIsJavaScriptAlertEnabled(true);

O WebView.On<Windows> método Especifica que este específicos da plataforma só serão executado na plataforma
Universal do Windows. O WebView.SetIsJavaScriptAlertEnabled método, no
Xamarin.Forms.PlatformConfiguration.WindowsSpecific namespace, é usada para controlar se os alertas de
JavaScript estão habilitados. Além disso, o WebView.SetIsJavaScriptAlertEnabled método pode ser usado para
ativar/desativar alertas de JavaScript por meio da chamada a IsJavaScriptAlertEnabled método para retornar se
eles estão habilitados:

_webView.On<Windows>().SetIsJavaScriptAlertEnabled(!_webView.On<Windows>().IsJavaScriptAlertEnabled());

O resultado é que os alertas de JavaScript podem ser exibidas em uma caixa de diálogo de mensagem UWP:
Links relacionados
PlatformSpecifics (amostra)
Criação de itens específicos à plataforma
WindowsSpecific API
Xamarin.Essentials
12/04/2019 • 4 minutes to read • Edit Online

O Xamarin.Essentials fornece desenvolvedores com APIs de plataforma cruzada para seus aplicativos móveis.
O Android, iOS e UWP oferecem APIs de plataforma e sistema operacional exclusivos nos quais os
desenvolvedores podem acessar tudo que estiver no C# aproveitando o Xamarin. O Xamarin.Essentials oferece
uma API única entre plataformas que funciona com qualquer aplicativo Xamarin.Forms, Android, iOS ou UWP e
que pode ser acessado no código compartilhado, independentemente da forma como a interface do usuário é
criada.

Introdução ao Xamarin.Essentials
Siga o guia de introdução para instalar o pacote NuGet do Xamarin.Essentials em seus projetos existentes ou
novos do Xamarin.Forms, Android, iOS ou UWP.

Guias de recursos
Siga os guias para integrar esses recursos Xamarin.Essentials em seus aplicativos:
Acelerômetro – recuperar dados de aceleração do dispositivo no espaço tridimensional.
Informações do aplicativo – localize informações sobre o aplicativo.
Barômetro – monitorar o barômetro em relação a alterações de pressão.
Bateria – facilmente detectar o nível de bateria, o código-fonte e o estado.
Área de transferência – definir ou ler rapidamente e facilmente texto na área de transferência.
Conversores de cor – métodos auxiliares para System.Drawing.Color.
Bússola – monitorar a bússola em relação a alterações.
Conectividade – verificar o estado da conectividade e detectar alterações.
Detectar movimento – detectar um movimento do dispositivo.
Informações sobre a exibição de dispositivos – obter a orientação e as métricas de tela do dispositivo.
Informações do dispositivo – saiba mais sobre o dispositivo com facilidade.
Email – enviar mensagens de email com facilidade.
Auxiliares do sistema de arquivos – salve arquivos em dados de aplicativo com facilidade.
Lanterna – uma maneira simples de ativar a lanterna/desativar.
Geocodificação – geocodificação e geocodificação reversa dos endereços e coordenadas.
Localização geográfica – recuperar a localização do GPS do dispositivo.
Giroscópio – acompanhar a rotação em torno dos três principais eixos do dispositivo.
Inicializador – permite que um aplicativo abra um URI pelo sistema.
Magnetômetro – detectar a orientação do dispositivo em relação ao campo magnético da Terra.
Thread principal – executar código no thread principal do aplicativo.
Mapas – abrir o aplicativo de mapas em um local específico.
Abrir o navegador – abrir um navegador em um site específico com rapidez e facilidade.
Sensor de orientação – recuperar a orientação do dispositivo no espaço tridimensional.
Discagem telefônica – abrir a discagem telefônica.
Extensões da plataforma – métodos auxiliares para converter retângulo, tamanho e ponto.
Preferências – adicionar preferências persistentes com rapidez e facilidade.
Armazenamento seguro – armazenar dados com segurança.
Compartilhar – enviar texto e URIs de site a outros aplicativos.
SMS – criar uma mensagem de texto para enviar.
Conversão de Texto em Fala – vocalizar texto no dispositivo.
Conversores de unidade – métodos auxiliares para converter unidades.
Controle de versão – controlar a versão de aplicativos e os números de build.
Vibrar – fazer o dispositivo vibrar.

Solução de problemas
Encontre ajuda se você estiver tendo problemas.

Documentação da API
Navegue pela documentação da API de todos os recursos Xamarin.Essentials.
Introdução ao Xamarin.Essentials
12/04/2019 • 5 minutes to read • Edit Online

O Xamarin.Essentials oferece uma API única entre plataformas que funciona com qualquer aplicativo
iOS, Android ou UWP e que pode ser acessado no código compartilhado, independentemente da forma
como a interface do usuário é criada.

Suporte de plataforma
O Xamarin.Essentials é compatível com os seguintes sistemas operacionais e plataformas:

PLATAFORMA VERSÃO

Android 4.4 (API 19) ou superior

iOS 10.0 ou superior

UWP 10.0.16299.0 ou superior

Instalação
O Xamarin.Essentials está disponível como um pacote NuGet que pode ser adicionado a qualquer
projeto, novo ou existente, através do Visual Studio.
1. Faça o download e instale o Visual Studio com as Ferramentas do Visual Studio para Xamarin.
2. Abra um projeto existente ou crie um novo projeto usando o modelo Aplicativo em branco no C#
do Visual Studio (Android, iPhone e iPad ou plataforma cruzada). Importante: Se adicionar a
um projeto UWP, verifique se o Build 16299 ou superior está definido nas propriedades do
projeto.
3. Adicione o pacote NuGet do Xamarin.Essentials a cada projeto:
Visual Studio
Visual Studio para Mac
No painel do Gerenciador de Soluções, clique com o botão direito do mouse no nome da solução
e escolha Gerenciar pacotes NuGet. Pesquise Xamarin.Essentials e instale o pacote em
TODOS os projetos, incluindo bibliotecas do Android, iOS, UWP e .NET Standard.
4. Adicione uma referência ao Xamarin.Essentials na classe C# para fazer referência às APIs.

using Xamarin.Essentials;

5. O Xamarin.Essentials requer uma configuração específica da plataforma:


Android
iOS
UWP
O Xamarin.Essentials é compatível com, no mínimo, a versão 4.4 do Android, correspondente ao
nível da API 19, mas, para compilação, a versão de destino do Android deve ser 9.0, que
corresponde ao nível da API 28. (No Visual Studio, essas duas versões são definidas na caixa de
diálogo Propriedades do Projeto para projetos do Android, na guia Manifesto do Android. No
Visual Studio para Mac, elas são definidas na caixa de diálogo Opções do Projeto para projetos do
Android, na guia Aplicativo Android).
O Xamarin.Essentials instala a versão 28.0.0.1 das bibliotecas Xamarin.Android.Support
necessárias. As outras bibliotecas Xamarin.Android.Support exigidas pelo aplicativo também
devem ser atualizadas para a versão 28.0.0.1 usando o gerenciador de pacotes NuGet. Todas as
bibliotecas Xamarin.Android.Support usadas pelo aplicativo devem ser as mesmas e devem ter,
pelo menos, a versão 28.0.0.1. Confira a página de solução de problemas se tiver problemas para
adicionar o NuGet do Xamarin.Essentials ou para atualizar NuGets na sua solução.
No MainLauncher do projeto do Android ou qualquer Activity que é iniciada, o
Xamarin.Essentials deve ser inicializado no método OnCreate :

protected override void OnCreate(Bundle savedInstanceState) {


//...
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState); // add this line to your code,
it may also be called: bundle
//...

Para lidar com permissões de tempo de execução no Android, o Xamarin.Essentials deve receber
qualquer OnRequestPermissionsResult . Adicione o seguinte código a todas as classes Activity :

public override void OnRequestPermissionsResult(int requestCode, string[] permissions,


[GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions,
grantResults);

base.OnRequestPermissionsResult(requestCode, permissions, grantResults);


}

6. Siga os guias do Xamarin.Essentials que permitem copiar e colar os trechos de código para cada
recurso.

Xamarin.Essentials – APIs multiplataforma para aplicativos móveis


(vídeo)

Outros recursos
Recomendamos que os novos desenvolvedores do Xamarin confiram a Introdução ao desenvolvimento
do Xamarin.
Visite o Repositório do GitHub do Xamarin.Essentials para ver o código-fonte atual, o que vem a seguir,
colocar exemplos em prática e clonar o repositório. Contribuições da comunidade são bem-vindas!
Navegue pela documentação da API de todos os recursos do Xamarin.Essentials.
Xamarin.Essentials: Acelerômetro
12/04/2019 • 4 minutes to read • Edit Online

A classe Accelerometer permite monitorar o sensor de acelerômetro do dispositivo que indica a aceleração do
dispositivo no espaço tridimensional.

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a biblioteca
esteja corretamente instalada e configurada em seus projetos.

Uso do acelerômetro
Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

A funcionalidade do Acelerômetro chama os métodos Start e Stop e escuta as alterações na aceleração. Todas
as alterações são enviadas de volta por meio do evento ReadingChanged . Veja um exemplo de uso:
public class AccelerometerTest
{
// Set speed delay for monitoring changes.
SensorSpeed speed = SensorSpeed.UI;

public AccelerometerTest()
{
// Register for reading changes, be sure to unsubscribe when finished
Accelerometer.ReadingChanged += Accelerometer_ReadingChanged;
}

void Accelerometer_ReadingChanged(object sender, AccelerometerChangedEventArgs e)


{
var data = e.Reading;
Console.WriteLine($"Reading: X: {data.Acceleration.X}, Y: {data.Acceleration.Y}, Z:
{data.Acceleration.Z}");
// Process Acceleration X, Y, and Z
}

public void ToggleAccelerometer()


{
try
{
if (Accelerometer.IsMonitoring)
Accelerometer.Stop();
else
Accelerometer.Start(speed);
}
catch (FeatureNotSupportedException fnsEx)
{
// Feature not supported on device
}
catch (Exception ex)
{
// Other error has occurred.
}
}
}

As leituras do acelerômetro são registradas em G. A G, uma unidade de força gravitacional equivalente à exercida
pelo campo gravitacional da Terra (9,81 m/s2).
O sistema de coordenadas é definido em relação à tela do telefone na orientação padrão. Os eixos não são
trocados quando a orientação da tela do dispositivo é alterada.
O eixo X é horizontal e aponta para a direita; o eixo Y é vertical e aponta para cima; o eixo Z aponta para a parte
externa da face frontal da tela. Nesse sistema, as coordenadas atrás da tela têm valores de Z negativos.
Exemplos:
Quando o dispositivo estiver em uma superfície plana e for empurrado da esquerda para a direita, o valor
de aceleração x será positivo.
Quando o dispositivo estiver em uma superfície plana, o valor de aceleração será +1,00 G ou (+9,81 m/s2),
o que corresponde à aceleração do dispositivo (0 m/s2) menos a força da gravidade (-9,81 m/s2) e
normalizado em G.
Quando o dispositivo estiver em uma superfície plana e for empurrado para cima com uma aceleração de
A m/s^2, o valor da aceleração será igual a A + 9,81, o que corresponde à aceleração do dispositivo (+A
m/s^2) menos a força da gravidade (-9,81 m/s^2) e normalizado em G.
Sensor de velocidade
Mais rápido – obtenha os dados do sensor o mais rápido possível (não é garantido retornar no thread de
interface do usuário).
Jogo – taxa adequada para jogos (não é garantido retornar no thread de interface do usuário).
Normal – taxa padrão adequada para alterações de orientação da tela.
Interface do usuário – taxa adequada para a interface do usuário geral.
Se o manipulador de eventos não tiver a garantia de ser executado no thread da interface do usuário e se precisar
acessar os elementos de interface do usuário, use o método MainThread.BeginInvokeOnMainThread para executar
esse código no thread da interface do usuário.

API
Código-fonte do acelerômetro
Documentação da API do acelerômetro

Vídeo relacionados

Saiba mais sobre o Xamarin Show no Channel 9 e no YouTube.


Xamarin.Essentials: Informações do aplicativo
12/04/2019 • 2 minutes to read • Edit Online

A classe AppInfo fornece informações sobre seu aplicativo.

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a biblioteca
esteja corretamente instalada e configurada em seus projetos.

Como usar AppInfo


Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

Obter informações do aplicativo:


As informações a seguir são expostas por meio da API:

// Application Name
var appName = AppInfo.Name;

// Package Name/Application Identifier (com.microsoft.testapp)


var packageName = AppInfo.PackageName;

// Application Version (1.0.0)


var version = AppInfo.VersionString;

// Application Build Number (1)


var build = AppInfo.BuildString;

Exibir as configurações do aplicativo


A classe AppInfo também pode exibir uma página de configurações mantidas pelo sistema operacional para o
aplicativo:

// Display settings page


AppInfo.ShowSettingsUI();

Esta página de configurações permite ao usuário alterar permissões do aplicativo e executar outras tarefas
específicas à plataforma.

Particularidades de implementação da plataforma


Android
iOS
UWP
Informações do aplicativo são obtidas do AndroidManifest.xml para os seguintes campos:
Build – android:versionCode no nó manifest
Name - android:label no nó application
PackageName: package no nó manifest
VersionString – android:versionName no nó application

API
Código-fonte de AppInfo
Documentação da API de AppInfo

Vídeo relacionados

Saiba mais sobre o Xamarin Show no Channel 9 e no YouTube.


Xamarin.Essentials: Barometer
12/04/2019 • 2 minutes to read • Edit Online

A classe Barometer permite que você monitore o sensor do barômetro do dispositivo. Esse sensor mede a
pressão.

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a biblioteca
esteja corretamente instalada e configurada em seus projetos.

Uso do Barometer
Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

A funcionalidade Barometer funciona chamando os métodos Start e Stop para escutar as alterações nas leituras
de pressão do barômetro em hectopascais. Todas as alterações são enviadas de volta por meio do evento
ReadingChanged . Veja um exemplo de uso:
public class BarometerTest
{
// Set speed delay for monitoring changes.
SensorSpeed speed = SensorSpeed.UI;

public BarometerTest()
{
// Register for reading changes.
Barometer.ReadingChanged += Barometer_ReadingChanged;
}

void Barometer_ReadingChanged(object sender, BarometerChangedEventArgs e)


{
var data = e.Reading;
// Process Pressure
Console.WriteLine($"Reading: Pressure: {data.PressureInHectopascals} hectopascals");
}

public void ToggleBarometer()


{
try
{
if (Barometer.IsMonitoring)
Barometer.Stop();
else
Barometer.Start(speed);
}
catch (FeatureNotSupportedException fnsEx)
{
// Feature not supported on device
}
catch (Exception ex)
{
// Other error has occurred.
}
}
}

Sensor de velocidade
Mais rápido – obtenha os dados do sensor o mais rápido possível (não é garantido retornar no thread de
interface do usuário).
Jogo – taxa adequada para jogos (não é garantido retornar no thread de interface do usuário).
Normal – taxa padrão adequada para alterações de orientação da tela.
Interface do usuário – taxa adequada para a interface do usuário geral.
Se o manipulador de eventos não tiver a garantia de ser executado no thread da interface do usuário e se precisar
acessar os elementos de interface do usuário, use o método MainThread.BeginInvokeOnMainThread para executar
esse código no thread da interface do usuário.

Particularidades de implementação da plataforma


Android
iOS
UWP
Sem detalhes da implementação específica da plataforma.
API
Código-fonte do Barometer
Documentação da API do Barometer
Xamarin.Essentials: Bateria
12/04/2019 • 5 minutes to read • Edit Online

A classe Battery permite que você verifique as informações sobre a bateria do dispositivo e monitore as
alterações, além de fornecer informações sobre o status de economia de energia do dispositivo, o que indica se o
dispositivo está em execução em um modo de baixa energia. Os aplicativos devem evitar o processamento em
segundo plano se o status da economia de energia do dispositivo estiver ativado.

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a biblioteca
esteja corretamente instalada e configurada em seus projetos.
Para acessar a funcionalidade Battery, a configuração específica da plataforma a seguir é necessária.
Android
iOS
UWP
A permissão Battery é necessária e deve ser configurada no projeto do Android. Ela pode ser usado das
seguintes maneiras:
Abra o arquivo AssemblyInfo.cs na pasta Propriedades e adicione:

[assembly: UsesPermission(Android.Manifest.Permission.BatteryStats)]

OU Atualize o Manifesto do Android:


Abra o arquivo AndroidManifest.xml na pasta Propriedades e adicione o seguinte dentro do nó do manifesto.

<uses-permission android:name="android.permission.BATTERY_STATS" />

Ou clique com o botão direito do mouse no projeto do Android e abra as propriedades do projeto. Em Manifesto
do Android, localize a área Permissões necessárias: e marque a permissão Bateria. Isso atualizará
automaticamente o arquivo AndroidManifest.xml.

Como usar Battery


Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

Verifique as informações atuais da bateria:


var level = Battery.ChargeLevel; // returns 0.0 to 1.0 or 1.0 when on AC or no battery.

var state = Battery.State;

switch (state)
{
case BatteryState.Charging:
// Currently charging
break;
case BatteryState.Full:
// Battery is full
break;
case BatteryState.Discharging:
case BatteryState.NotCharging:
// Currently discharging battery or not being charged
break;
case BatteryState.NotPresent:
// Battery doesn't exist in device (desktop computer)
case BatteryState.Unknown:
// Unable to detect battery state
break;
}

var source = Battery.PowerSource;

switch (source)
{
case BatteryPowerSource.Battery:
// Being powered by the battery
break;
case BatteryPowerSource.AC:
// Being powered by A/C unit
break;
case BatteryPowerSource.Usb:
// Being powered by USB cable
break;
case BatteryPowerSource.Wireless:
// Powered via wireless charging
break;
case BatteryPowerSource.Unknown:
// Unable to detect power source
break;
}

Sempre que qualquer uma das propriedades da bateria for alterada, um evento será disparado:

public class BatteryTest


{
public BatteryTest()
{
// Register for battery changes, be sure to unsubscribe when needed
Battery.BatteryInfoChanged += Battery_BatteryInfoChanged;
}

void Battery_BatteryInfoChanged(object sender, BatteryInfoChangedEventArgs e)


{
var level = e.ChargeLevel;
var state = e.State;
var source = e.PowerSource;
Console.WriteLine($"Reading: Level: {level}, State: {state}, Source: {source}");
}
}

Os dispositivos que funcionam com baterias podem ser colocados em um modo de baixo consumo de energia.
Por vezes, os dispositivos passam para este modo automaticamente, por exemplo, quando a bateria fica abaixo dos
20% de capacidade. O sistema operacional responde ao modo de economia de energia reduzindo atividades que
tendem a esgotar a bateria. Os aplicativos podem ajudar evitando o processamento em segundo plano ou outras
atividades que consomem muita energia quando o modo de economia de energia está ativado.
Obtenha o status atual da economia de energia do dispositivo usando a propriedade Battery.EnergySaverStatus
estática:

// Get energy saver status


var status = Battery.EnergySaverStatus;

Essa propriedade retorna um membro da enumeração EnergySaverStatus , que é On , Off ou Unknown . Se a


propriedade retornar On , o aplicativo deverá evitar o processamento em segundo plano ou outras atividades que
possam consumir muita energia.
O aplicativo também deve instalar um manipulador de eventos. A classe Power expõe um evento que é acionado
quando o status da economia de energia é alterado:

public class EnergySaverTest


{
public EnergySaverTest()
{
// Subscribe to changes of energy-saver status
Battery.EnergySaverStatusChanged += OnEnergySaverStatusChanged;
}

private void OnEnergySaverStatusChanged(EnergySaverStatusChangedEventArgs e)


{
// Process change
var status = e.EnergySaverStatus;
}
}

Se o status da economia de energia for alterado para On , o aplicativo deverá interromper a execução do
processamento em segundo plano. Se o status mudar para Unknown ou Off , o aplicativo poderá retomar o
processamento em segundo plano.

Diferenças entre plataformas


Android
iOS
UWP
Sem diferenças entre plataformas.

API
Código-fonte de Bateria
Documentação da API de Bateria

Vídeo relacionados
Saiba mais sobre o Xamarin Show no Channel 9 e no YouTube.
Xamarin.Essentials: Área de Transferência
12/04/2019 • 2 minutes to read • Edit Online

A classe Clipboard permite que você copie e cole o texto para a área de transferência do sistema entre aplicativos.

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a biblioteca
esteja corretamente instalada e configurada em seus projetos.

Como usar Clipboard


Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

Para verificar se a Área de Transferência tem algum texto pronto para ser colado:

var hasText = Clipboard.HasText;

Para definir o texto na Área de Transferência:

await Clipboard.SetTextAsync("Hello World");

Para ler o texto da Área de Transferência:

var text = await Clipboard.GetTextAsync();

API
Código-fonte de Área de Transferência
Documentação de API de Área de Transferência

Vídeo relacionados

Saiba mais sobre o Xamarin Show no Channel 9 e no YouTube.


Xamarin.Essentials: Conversores de cor
12/04/2019 • 2 minutes to read • Edit Online

A classe ColorConverters no Xamarin.Essentials fornece vários métodos auxiliares para System.Drawing.Color.

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a biblioteca
esteja corretamente instalada e configurada em seus projetos.

Usando conversores de cor


Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

Ao trabalhar com System.Drawing.Color , você pode usar os conversores internos do Xamarin.Forms para criar
uma cor de Hsl, Hex ou UInt.

var blueHex = ColorConverters.FromHex("#3498db");


var blueHsl = ColorConverters.FromHsl(204, 70, 53);
var blueUInt = ColorConverers.FromUInt(3447003);

Usando extensões de cor


Os métodos de extensão em System.Drawing.Color permitem aplicar propriedades diferentes:

var blue = ColorConverters.FromHex("#3498db");

// Multiplies the current alpha by 50%


var blueWithAlpha = blue.MultiplyAlpha(.5f);

Há vários outros métodos de extensão incluindo:


ToUInt
MultiplyAlpha
WithHue
WithAlpha
WithSaturation
WithLuminosity

Usando as extensões de plataforma


Além disso, você pode converter System.Drawing.Color para a estrutura de cor específica da plataforma. Esses
métodos só podem ser chamados do iOS, do Android e dos projetos UWP.
var system = System.Drawing.Color.FromArgb(255, 52, 152, 219);

// Extension to convert to Android.Graphics.Color, UIKit.UIColor, or Windows.UI.Color


var platform = system.ToPlatformColor();

var platform = new Android.Graphics.Color(52, 152, 219, 255);

// Back to System.Drawing.Color
var system = platform.ToSystemColor();

O método ToSystemColor se aplica a Android.Graphics.Color, UIKit.UIColor e Windows.UI.Color.

API
Código-fonte de conversores de cor
Documentação da API de conversores de cor
Código-fonte de extensões de cor
Documentação da API de extensões de cor
Xamarin.Essentials: Bússola
12/04/2019 • 4 minutes to read • Edit Online

A classe Compass permite que você monitore o norte magnético do dispositivo.

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a biblioteca
esteja corretamente instalada e configurada em seus projetos.

Como usar Compass


Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

A funcionalidade de Bússola funciona chamando os métodos Start e e fica atenta às alterações na bússola.
Stop
Todas as alterações são enviadas de volta por meio do evento ReadingChanged . Veja um exemplo:

public class CompassTest


{
// Set speed delay for monitoring changes.
SensorSpeed speed = SensorSpeed.UI;

public CompassTest()
{
// Register for reading changes, be sure to unsubscribe when finished
Compass.ReadingChanged += Compass_ReadingChanged;
}

void Compass_ReadingChanged(object sender, CompassChangedEventArgs e)


{
var data = e.Reading;
Console.WriteLine($"Reading: {data.HeadingMagneticNorth} degrees");
// Process Heading Magnetic North
}

public void ToggleCompass()


{
try
{
if (Compass.IsMonitoring)
Compass.Stop();
else
Compass.Start(speed);
}
catch (FeatureNotSupportedException fnsEx)
{
// Feature not supported on device
}
catch (Exception ex)
{
// Some other exception has occurred
}
}
}
Sensor de velocidade
Mais rápido – obtenha os dados do sensor o mais rápido possível (não é garantido retornar no thread de
interface do usuário).
Jogo – taxa adequada para jogos (não é garantido retornar no thread de interface do usuário).
Normal – taxa padrão adequada para alterações de orientação da tela.
Interface do usuário – taxa adequada para a interface do usuário geral.
Se o manipulador de eventos não tiver a garantia de ser executado no thread da interface do usuário e se precisar
acessar os elementos de interface do usuário, use o método MainThread.BeginInvokeOnMainThread para executar
esse código no thread da interface do usuário.

Particularidades de implementação da plataforma


Android
O Android não fornece uma API para recuperar a orientação da bússola. Utilizamos o acelerômetro e o
magnetômetro para calcular o norte magnético, o que é recomendado pelo Google.
Em casos raros, talvez você veja resultados inconsistentes devido à necessidade de calibração dos sensores, o que
envolve a movimentação do seu dispositivo em um movimento de figura 8. A melhor maneira de fazer isso é abrir
o Google Maps, tocar no ponto do seu local e selecionar Calibrar bússola.
Saiba que executar simultaneamente vários sensores em seu aplicativo pode ajustar a velocidade do sensor.

Filtro Passa Baixa


Devido ao modo como os valores da bússola do Android são atualizados e calculados, pode haver a necessidade
para suavizar os valores. É possível aplicar um Filtro de Passa Baixa que deixa na média os valores de seno e
cosseno dos ângulos por meio da definição da propriedade Start na classe bool applyLowPassFilter :

Compass.Start(SensorSpeed.UI, applyLowPassFilter: true);

Isso só é aplicado na plataforma Android, e o parâmetro é ignorado no iOS e UWP. Encontre mais informações
aqui.

API
Código-fonte da Bússola
Documentação da API de Bússola
Xamarin.Essentials: Conectividade
12/04/2019 • 4 minutes to read • Edit Online

A classe Connectivity permite monitorar alterações em condições de rede do dispositivo, verificar o acesso da
rede atual e como ele está conectado no momento.

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a biblioteca
esteja corretamente instalada e configurada em seus projetos.
Para acessar a funcionalidade Connectivity, a seguinte configuração específica da plataforma é necessária.
Android
iOS
UWP
A permissão AccessNetworkState é necessária e deve ser configurada no projeto do Android. Ela pode ser usado
das seguintes maneiras:
Abra o arquivo AssemblyInfo.cs na pasta Propriedades e adicione:

[assembly: UsesPermission(Android.Manifest.Permission.AccessNetworkState)]

OU Atualize o Manifesto do Android:


Abra o arquivo AndroidManifest.xml na pasta Propriedades e adicione o seguinte dentro do nó do manifesto.

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

Ou clique com o botão direito do mouse no projeto do Android e abra as propriedades do projeto. Em Manifesto
do Android, localize a área Permissões necessárias: e marque a permissão Acessar estado da rede. Isso
atualizará automaticamente o arquivo AndroidManifest.xml.

Uso de Connectivity
Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

Verifique o acesso à rede atual:

var current = Connectivity.NetworkAccess;

if (current == NetworkAccess.Internet)
{
// Connection to internet is available
}

O acesso à rede se enquadra às seguintes categorias:


Internet – acesso local e à Internet.
ConstrainedInternet – acesso limitado à Internet. Indica a conectividade do portal cativo, em que o acesso
local a um portal da Web é fornecido, mas o acesso à Internet exige que credenciais específicas sejam
fornecidas através de um portal.
Local – apenas acesso local à rede.
Nenhum – nenhuma conectividade disponível.
Desconhecido – não é possível determinar a conectividade com a internet.
É possível verificar que tipo de perfil de conexão o dispositivo está usando ativamente:

var profiles = Connectivity.ConnectionProfiles;


if (profiles.Contains(ConnectionProfile.WiFi))
{
// Active Wi-Fi connection.
}

Sempre que o perfil de conexão ou o acesso à rede mudar, você poderá receber um evento quando houver um
acionamento:

public class ConnectivityTest


{
public ConnectivityTest()
{
// Register for connectivity changes, be sure to unsubscribe when finished
Connectivity.ConnectivityChanged += Connectivity_ConnectivityChanged;
}

void Connectivity_ConnectivityChanged(object sender, ConnectivityChangedEventArgs e)


{
var access = e.NetworkAccess;
var profiles = e.ConnectionProfiles;
}
}

Limitações
É importante observar que é possível que Internet seja reportado pelo NetworkAccess . No entanto, o acesso
completo à Web não estará disponível. Devido ao funcionamento da conectividade em cada plataforma, só é
possível garantir que uma conexão disponível. Por exemplo, o dispositivo pode estar conectado a uma rede Wi-Fi,
mas o roteador está desconectado da Internet. Nesta instância, a Internet pode ser reportada, mas uma conexão
ativa não estará disponível.

API
Código-fonte de Connectivity
Documentação da API de Connectivity

Vídeo relacionados
Saiba mais sobre o Xamarin Show no Channel 9 e no YouTube.
Xamarin.Essentials: Detectar movimento
12/04/2019 • 3 minutes to read • Edit Online

A classe Accelerometer permite monitorar o sensor de acelerômetro do dispositivo, que indica a aceleração do
dispositivo no espaço tridimensional. Além disso, ele permite que você se registre para eventos quando o usuário
sacudir o dispositivo.

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a biblioteca
esteja corretamente instalada e configurada em seus projetos.

Usando a detecção de movimento


Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

Para detectar um movimento do dispositivo, você deve usar a funcionalidade do acelerômetro, chamando os
métodos Start e Stop para ouvir alterações na aceleração e detectar um movimento. Sempre que um
movimento for detectado, um evento ShakeDetected será disparado. Recomenda-se usar Game ou mais veloz para
o SensorSpeed . Veja um exemplo de uso:
public class DetectShakeTest
{
// Set speed delay for monitoring changes.
SensorSpeed speed = SensorSpeed.Game;

public DetectShakeTest()
{
// Register for reading changes, be sure to unsubscribe when finished
Accelerometer.ShakeDetected += Accelerometer_ShakeDetected ;
}

void Accelerometer_ShakeDetected (object sender, EventArgs e)


{
// Process shake event
}

public void ToggleAccelerometer()


{
try
{
if (Accelerometer.IsMonitoring)
Accelerometer.Stop();
else
Accelerometer.Start(speed);
}
catch (FeatureNotSupportedException fnsEx)
{
// Feature not supported on device
}
catch (Exception ex)
{
// Other error has occurred.
}
}
}

Sensor de velocidade
Mais rápido – obtenha os dados do sensor o mais rápido possível (não é garantido retornar no thread de
interface do usuário).
Jogo – taxa adequada para jogos (não é garantido retornar no thread de interface do usuário).
Normal – taxa padrão adequada para alterações de orientação da tela.
Interface do usuário – taxa adequada para a interface do usuário geral.
Se o manipulador de eventos não tiver a garantia de ser executado no thread da interface do usuário e se precisar
acessar os elementos de interface do usuário, use o método MainThread.BeginInvokeOnMainThread para executar
esse código no thread da interface do usuário.

Detalhes da implementação
A API de detecção de movimento usa leituras brutas do acelerômetro para calcular a aceleração. Ela usa um
mecanismo de fila simples para detectar se 3/4 dos eventos recentes do acelerômetro ocorreram na última
metade do segundo. A aceleração é calculada adicionando o quadrado das leituras de X, Y e Z do acelerômetro e
comparando com um limite específico.

API
Código-fonte do acelerômetro
Documentação da API do acelerômetro
Xamarin.Essentials: Informações sobre DeviceDisplay
12/04/2019 • 2 minutes to read • Edit Online

A classe DeviceDisplay fornece informações sobre as métricas de tela do dispositivo no qual o aplicativo está
sendo executado e pode solicitar para evitar que a tela fique suspensa quando o aplicativo está em execução.

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a biblioteca
esteja corretamente instalada e configurada em seus projetos.

Como usar DeviceDisplay


Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

Informações principais de Tela


Além das informações básicas do dispositivo, a classe DeviceDisplay contém informações sobre a tela e a
orientação do dispositivo.

// Get Metrics
var mainDisplayInfo = DeviceDisplay.MainDisplayInfo;

// Orientation (Landscape, Portrait, Square, Unknown)


var orientation = mainDisplayInfo.Orientation;

// Rotation (0, 90, 180, 270)


var rotation = mainDisplayInfo.Rotation;

// Width (in pixels)


var width = mainDisplayInfo.Width;

// Height (in pixels)


var height = mainDisplayInfo.Height;

// Screen density
var density = mainDisplayInfo.Density;

A classe DeviceDisplay também expõe um evento que pode ser assinado e que é disparado sempre que ocorre
alterações nas métricas da tela:
public class DisplayInfoTest
{
public DisplayInfoTest()
{
// Subscribe to changes of screen metrics
DeviceDisplay.MainDisplayInfoChanged += OnMainDisplayInfoChanged;
}

void OnMainDisplayInfoChanged(object sender, DisplayInfoChangedEventArgs e)


{
// Process changes
var displayInfo = e.DisplayInfo;
}
}

A classe DeviceDisplay expõe uma bool propriedade chamada KeepScreenOn que pode ser definida para tentar
evitar o bloqueio ou desligamento da tela do dispositivo.

public class KeepScreenOnTest


{
public void ToggleScreenLock()
{
DeviceDisplay.KeepScreenOn = !DeviceDisplay.KeepScreenOn;
}
}

Diferenças entre plataformas


Android
iOS
UWP
Sem diferenças.

API
Código-fonte de DeviceDisplay
Documentação da API de DeviceDisplay
Xamarin.Essentials: Informações sobre o dispositivo
12/04/2019 • 2 minutes to read • Edit Online

A classe DeviceInfo fornece informações sobre o dispositivo no qual o aplicativo está em execução.

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a biblioteca
esteja corretamente instalada e configurada em seus projetos.

Como usar DeviceInfo


Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

As informações a seguir são expostas por meio da API:

// Device Model (SMG-950U, iPhone10,6)


var device = DeviceInfo.Model;

// Manufacturer (Samsung)
var manufacturer = DeviceInfo.Manufacturer;

// Device Name (Motz's iPhone)


var deviceName = DeviceInfo.Name;

// Operating System Version Number (7.0)


var version = DeviceInfo.VersionString;

// Platform (Android)
var platform = DeviceInfo.Platform;

// Idiom (Phone)
var idiom = DeviceInfo.Idiom;

// Device Type (Physical)


var deviceType = DeviceInfo.DeviceType;

Plataformas
DeviceInfo.Platform correlaciona com uma cadeia de caracteres constante que mapeia para o sistema
operacional. Os valores podem ser verificados com a classe DevicePlatform :
DevicePlatform.iOS – iOS
DevicePlatform.Android – Android
DevicePlatform.UWP – UWP
DevicePlatform.Unknown – Desconhecido

Linguagens
DeviceInfo.Idiom correlaciona uma cadeia de caracteres constante que mapeia para o tipo de dispositivo em que
o aplicativo está sendo executado. Os valores podem ser verificados com a classe DeviceIdiom :
DeviceIdiom.Phone – Telefone
DeviceIdiom.Tablet – Tablet
DeviceIdiom.Desktop – Área de trabalho
DeviceIdiom.TV – TV
DeviceIdiom.Watch – Observação
DeviceIdiom.Unknown – Desconhecido

Tipo de dispositivo
DeviceInfo.DeviceType correlaciona uma enumeração para determinar se o aplicativo está em execução em um
dispositivo físico ou virtual. Um dispositivo virtual é um simulador ou emulador.

Particularidades de implementação da plataforma


iOS
O iOS não expõe uma API para os desenvolvedores obterem o nome do dispositivo iOS específico. Em vez disso,
um identificador de hardware retorna, como iPhone10.6, que se refere ao iPhone X. A Apple não fornece um
mapeamento desses identificadores, mas isso pode ser encontrado no The iPhone Wiki (uma fonte não oficial).

API
Código-fonte de DeviceInfo
Documentação da API de DeviceInfo
Xamarin.Essentials: Email
12/04/2019 • 2 minutes to read • Edit Online

A classe Email permite que um aplicativo abra o aplicativo de email padrão com uma informação especificada,
incluindo assunto, corpo e destinatários (PARA, CC, CCO ).

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a biblioteca
esteja corretamente instalada e configurada em seus projetos.

Como usar Email


Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

A funcionalidade de Email funciona chamando o método ComposeAsync com um EmailMessage que contém
informações sobre o email:

public class EmailTest


{
public async Task SendEmail(string subject, string body, List<string> recipients)
{
try
{
var message = new EmailMessage
{
Subject = subject,
Body = body,
To = recipients,
//Cc = ccRecipients,
//Bcc = bccRecipients
};
await Email.ComposeAsync(message);
}
catch (FeatureNotSupportedException fbsEx)
{
// Email is not supported on this device
}
catch (Exception ex)
{
// Some other exception occurred
}
}
}

Diferenças entre plataformas


Android
iOS
UWP
Nem todos os clientes de email para Android dão suporte para Html . Como não há nenhuma maneira de detectar
isso, é recomendável usar PlainText ao enviar emails.

Anexos de Arquivo

O envio de arquivos por email está disponível como uma versão prévia experimental no Xamarin.Essentials versão
1.1.0. Esse recurso permite que um aplicativo envie arquivos por email em clientes de email no dispositivo. Para
habilitar esse recurso, defina a propriedade a seguir no código de inicialização do aplicativo:

ExperimentalFeatures.Enable(ExperimentalFeatures.EmailAttachments);

Depois de habilitar o recurso, qualquer arquivo poderá ser enviado por email. O Xamarin.Essentials detectará
automaticamente o tipo de arquivo (MIME ) e solicitará que o arquivo seja adicionado como um anexo. Cada
cliente de email é diferente poderá ser compatível somente com extensões de arquivo específicas ou até mesmo
não ser com nenhuma.
Aqui está um exemplo de como gravar texto no disco e adicioná-lo como um anexo de email:

var message = new EmailMessage


{
Subject = "Hello",
Body = "World",
};

var fn = "Attachment.txt";
var file = Path.Combine(FileSystem.CacheDirectory, fn);
File.WriteAllText(file, "Hello World");

message.Attachments.Add(new EmailAttachment(file));

await Email.ComposeAsync(message);

API
Código-fonte de email
Documentação da API de email
Xamarin.Essentials: Auxiliares de sistema de arquivos
12/04/2019 • 3 minutes to read • Edit Online

A classe FileSystem contém uma série de auxiliares para localizar o cache e os diretórios de dados do aplicativo e
abrir arquivos dentro do pacote de aplicativos.

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a biblioteca
esteja corretamente instalada e configurada em seus projetos.

Como usar os auxiliares de sistema de arquivos


Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

Para fazer com que o diretório do aplicativo armazene dados de cache. Os dados de cache podem ser usados
para quaisquer dados que precisem permanecer mais tempo do que os dados temporários, mas que não devem
ser dados necessários para uma operação correta.

var cacheDir = FileSystem.CacheDirectory;

Para obter o diretório de nível superior do aplicativo para todos os arquivos que não são arquivos de dados do
usuário. O backup desses arquivos ocorre na estrutura de sincronização do sistema operacional. Veja abaixo as
particularidades de implementação da plataforma.

var mainDir = FileSystem.AppDataDirectory;

Para abrir um arquivo que está incluído no pacote de aplicativos:

using (var stream = await FileSystem.OpenAppPackageFileAsync(templateFileName))


{
using (var reader = new StreamReader(stream))
{
var fileContents = await reader.ReadToEndAsync();
}
}

Particularidades de implementação da plataforma


Android
iOS
UWP
CacheDirectory – Retorna o CacheDir do contexto atual.
AppDataDirectory – Retorna o FilesDir do contexto atual e realiza o backup usando o Backup Automático a
partir da API 23 e acima.
Adicione qualquer arquivo à pasta Ativos no projeto do Android e marque a Ação de Compilação como
AndroidAsset para usá-la com OpenAppPackageFileAsync .

API
Código-fonte de Auxiliares do sistema de arquivos
Documentação da API do Sistema de Arquivos
Xamarin.Essentials: Lanterna
12/04/2019 • 3 minutes to read • Edit Online

A classe Flashlight tem a capacidade de ativar ou desativar o flash da câmera do dispositivo para transformá-lo
em uma lanterna.

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a biblioteca
esteja corretamente instalada e configurada em seus projetos.
Para acessar a funcionalidade Flashlight, a seguinte configuração específica da plataforma é necessária.
Android
iOS
UWP
As permissões Flashlight e Camera são necessárias e devem ser configuradas no projeto do Android. Ela pode ser
usado das seguintes maneiras:
Abra o arquivo AssemblyInfo.cs na pasta Propriedades e adicione:

[assembly: UsesPermission(Android.Manifest.Permission.Flashlight)]
[assembly: UsesPermission(Android.Manifest.Permission.Camera)]

OU Atualize o Manifesto do Android:


Abra o arquivo AndroidManifest.xml na pasta Propriedades e adicione o seguinte dentro do nó do manifesto.

<uses-permission android:name="android.permission.FLASHLIGHT" />


<uses-permission android:name="android.permission.CAMERA" />

Ou clique com o botão direito do mouse no projeto do Android e abra as propriedades do projeto. Em Manifesto
do Android, localize a área Permissões necessárias: e marque as permissões FLASHLIGHT e CAMERA. Isso
atualizará automaticamente o arquivo AndroidManifest.xml.
Ao adicionar essas permissões, o Google Play filtrará automaticamente os dispositivos sem um hardware
específico. Você pode contornar isso adicionando o seguinte ao seu arquivo AssemblyInfo.cs em seu projeto do
Android:

[assembly: UsesFeature("android.hardware.camera", Required = false)]


[assembly: UsesFeature("android.hardware.camera.autofocus", Required = false)]

Como usar Flashlight


Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

A lanterna pode ser ativada e desativada por meio dos métodos TurnOnAsync e TurnOffAsync :
try
{
// Turn On
await Flashlight.TurnOnAsync();

// Turn Off
await Flashlight.TurnOffAsync();
}
catch (FeatureNotSupportedException fnsEx)
{
// Handle not supported on device exception
}
catch (PermissionException pEx)
{
// Handle permission exception
}
catch (Exception ex)
{
// Unable to turn on/off flashlight
}

Particularidades de implementação da plataforma


Android
iOS
UWP
A classe Flashlight foi otimizada com base no sistema operacional do dispositivo.
API nível 23 e superior
Em níveis mais recentes da API, o Modo Tocha será usado para ativar ou desativar a unidade de flash do
dispositivo.
API nível 22 e superior
Uma textura de superfície da câmera é criada para ativar ou desativar o FlashMode da unidade de câmera.

API
Código-fonte de Lanterna
Documentação da API de Lanterna
Xamarin.Essentials: Geocódigo
12/04/2019 • 3 minutes to read • Edit Online

A classe Geocoding fornece APIs para definir o código geográfico de um marcador de local para coordenadas
posicionais e reverter as coordenadas de código geográfico para um marcador de local.

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a biblioteca
esteja corretamente instalada e configurada em seus projetos.
Para acessar a funcionalidade Geocodificação, a seguinte configuração específica da plataforma é necessária.
Android
iOS
UWP
Não exige mais configurações.

Como usar Geocoding


Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

Obter coordenadas de local de um endereço:

try
{
var address = "Microsoft Building 25 Redmond WA USA";
var locations = await Geocoding.GetLocationsAsync(address);

var location = locations?.FirstOrDefault();


if (location != null)
{
Console.WriteLine($"Latitude: {location.Latitude}, Longitude: {location.Longitude}, Altitude:
{location.Altitude}");
}
}
catch (FeatureNotSupportedException fnsEx)
{
// Feature not supported on device
}
catch (Exception ex)
{
// Handle exception that may have occurred in geocoding
}

A altitude nem sempre está disponível. Se não estiver disponível, a propriedade Altitude poderá ser null ou o
valor poderá ser zero. Se a altitude estiver disponível, o valor estará em metros acima do nível do mar.

Uso da geocodificação reversa


Geocodificação reversa é o processo de obtenção de marcadores de local para um conjunto existente de
coordenadas:

try
{
var lat = 47.673988;
var lon = -122.121513;

var placemarks = await Geocoding.GetPlacemarksAsync(lat, lon);

var placemark = placemarks?.FirstOrDefault();


if (placemark != null)
{
var geocodeAddress =
$"AdminArea: {placemark.AdminArea}\n" +
$"CountryCode: {placemark.CountryCode}\n" +
$"CountryName: {placemark.CountryName}\n" +
$"FeatureName: {placemark.FeatureName}\n" +
$"Locality: {placemark.Locality}\n" +
$"PostalCode: {placemark.PostalCode}\n" +
$"SubAdminArea: {placemark.SubAdminArea}\n" +
$"SubLocality: {placemark.SubLocality}\n" +
$"SubThoroughfare: {placemark.SubThoroughfare}\n" +
$"Thoroughfare: {placemark.Thoroughfare}\n";

Console.WriteLine(geocodeAddress);
}
}
catch (FeatureNotSupportedException fnsEx)
{
// Feature not supported on device
}
catch (Exception ex)
{
// Handle exception that may have occurred in geocoding
}

Distância entre dois locais


As classes Location e LocationExtensions definem métodos para calcular a distância entre dois locais. Confira um
exemplo no artigo Xamarin.Essentials: geolocalização.

API
Código-fonte de Geocodificação
Documentação da API de Geocodificação
Xamarin.Essentials: Geolocalização
12/04/2019 • 7 minutes to read • Edit Online

A classe Geolocation fornece APIs para recuperar as coordenadas atuais de geolocalização do dispositivo.

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a biblioteca
esteja corretamente instalada e configurada em seus projetos.
Para acessar a funcionalidade de Geolocalização, a seguinte configuração específica da plataforma é necessária:
Android
iOS
UWP
As permissões Coarse Location e Fine Location são necessárias e devem ser configuradas no projeto do Android.
Além disso, se o seu aplicativo for destinado ao Android 5.0 (API nível 21) ou superior, você deverá declarar que
ele usa os recursos de hardware no arquivo de manifesto. Isso pode ser usado das seguintes maneiras:
Abra o arquivo AssemblyInfo.cs na pasta Propriedades e adicione:

[assembly: UsesPermission(Android.Manifest.Permission.AccessCoarseLocation)]
[assembly: UsesPermission(Android.Manifest.Permission.AccessFineLocation)]
[assembly: UsesFeature("android.hardware.location", Required = false)]
[assembly: UsesFeature("android.hardware.location.gps", Required = false)]
[assembly: UsesFeature("android.hardware.location.network", Required = false)]

Ou atualize o manifesto do Android:


Abra o arquivo AndroidManifest.xml na pasta Propriedades e adicione o seguinte dentro do nó do manifesto:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />


<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-feature android:name="android.hardware.location" android:required="false" />
<uses-feature android:name="android.hardware.location.gps" android:required="false" />
<uses-feature android:name="android.hardware.location.network" android:required="false" />

Ou clique com o botão direito no projeto do Android e abra as propriedades do projeto. Em Manifesto do
Android, localize a área Permissões necessárias: e marque as permissões ACCESS_COARSE_LOCATION e
ACCESS_FINE_LOCATION. Isso atualizará automaticamente o arquivo AndroidManifest.xml.

Usar a geolocalização
Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

A API de Geolocalização também solicitará ao usuário permissões quando for necessário.


Você pode obter o último local conhecido do dispositivo chamando o método GetLastKnownLocationAsync . Isso
geralmente é mais rápido do que fazer uma consulta completa, mas pode ser menos preciso.
try
{
var location = await Geolocation.GetLastKnownLocationAsync();

if (location != null)
{
Console.WriteLine($"Latitude: {location.Latitude}, Longitude: {location.Longitude}, Altitude:
{location.Altitude}");
}
}
catch (FeatureNotSupportedException fnsEx)
{
// Handle not supported on device exception
}
catch (FeatureNotEnabledException fneEx)
{
// Handle not enabled on device exception
}
catch (PermissionException pEx)
{
// Handle permission exception
}
catch (Exception ex)
{
// Unable to get location
}

A altitude nem sempre está disponível. Se não estiver disponível, a propriedade Altitude poderá ser null ou o
valor poderá ser zero. Se a altitude estiver disponível, o valor estará em metros acima do nível do mar.
Para consultar as coordenadas do local atual do dispositivo, use GetLocationAsync . É melhor passar um
GeolocationRequest e CancellationToken completo, pois pode demorar um pouco para obter o local do
dispositivo.

try
{
var request = new GeolocationRequest(GeolocationAccuracy.Medium);
var location = await Geolocation.GetLocationAsync(request);

if (location != null)
{
Console.WriteLine($"Latitude: {location.Latitude}, Longitude: {location.Longitude}, Altitude:
{location.Altitude}");
}
}
catch (FeatureNotSupportedException fnsEx)
{
// Handle not supported on device exception
}
catch (FeatureNotEnabledException fneEx)
{
// Handle not enabled on device exception
}
catch (PermissionException pEx)
{
// Handle permission exception
}
catch (Exception ex)
{
// Unable to get location
}
Precisão da geolocalização
A tabela a seguir descreve a precisão por plataforma:
O menor
PLATAFORMA DISTÂNCIA (EM METROS)

Android 500

iOS 3000

UWP 1.000–5.000

Baixo
PLATAFORMA DISTÂNCIA (EM METROS)

Android 500

iOS 1000

UWP 300–3.000

Médio (padrão )
PLATAFORMA DISTÂNCIA (EM METROS)

Android 100–500

iOS 100

UWP 30–500

Alta
PLATAFORMA DISTÂNCIA (EM METROS)

Android 0–100

iOS 10

UWP <= 10

Melhor
PLATAFORMA DISTÂNCIA (EM METROS)

Android 0–100

iOS ~0

UWP <= 10
Detectando locais fictícios
Alguns dispositivos podem retornar um local fictício do provedor ou por um aplicativo que fornece locais fictícios.
Você pode detectar isso usando o IsFromMockProvider em qualquer Location .

var request = new GeolocationRequest(GeolocationAccuracy.Medium);


var location = await Geolocation.GetLocationAsync(request);

if (location != null)
{
if(location.IsFromMockProvider)
{
// location is from a mock provider
}
}

Distância entre dois locais


As classes Location e LocationExtensions definem métodos CalculateDistance que permitem o cálculo da
distância entre duas localizações geográficas. Essa distância calculada não considera estradas ou outros caminhos
e é simplesmente a distância mais curta entre os dois pontos ao longo da superfície da Terra, também conhecido
como ortodromia ou, coloquialmente, a distância "em linha reta".
Veja um exemplo:

Location boston = new Location(42.358056, -71.063611);


Location sanFrancisco = new Location(37.783333, -122.416667);
double miles = Location.CalculateDistance(boston, sanFrancisco, DistanceUnits.Miles);

O construtor Location tem argumentos de latitude e longitude, nessa ordem. Os valores de latitude positiva estão
ao norte do Equador, e os valores de longitude positiva estão a leste do Meridiano primário. Use o argumento
final para CalculateDistance a fim de especificar milhas ou quilômetros. A classe UnitConverters também define
os métodos KilometersToMiles e MilesToKilometers para conversão entre as duas unidades.

API
Código-fonte de geolocalização
Documentação da API de Geolocalização
Xamarin.Essentials: Giroscópio
12/04/2019 • 2 minutes to read • Edit Online

A classe Gyroscope permite que você monitore o sensor de giroscópio do dispositivo, que mede a rotação em
torno dos três eixos principais do dispositivo.

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a biblioteca
esteja corretamente instalada e configurada em seus projetos.

Como usar o Giroscópio


Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

A funcionalidade de Giroscópio chama os métodos Start e Stop e fica atenta às alterações no giroscópio. Todas
as alterações são enviadas de volta por meio do evento ReadingChanged em rad/s. Veja um exemplo de uso:
public class GyroscopeTest
{
// Set speed delay for monitoring changes.
SensorSpeed speed = SensorSpeed.UI;

public GyroscopeTest()
{
// Register for reading changes.
Gyroscope.ReadingChanged += Gyroscope_ReadingChanged;
}

void Gyroscope_ReadingChanged(object sender, GyroscopeChangedEventArgs e)


{
var data = e.Reading;
// Process Angular Velocity X, Y, and Z reported in rad/s
Console.WriteLine($"Reading: X: {data.AngularVelocity.X}, Y: {data.AngularVelocity.Y}, Z:
{data.AngularVelocity.Z}");
}

public void ToggleGyroscope()


{
try
{
if (Gyroscope.IsMonitoring)
Gyroscope.Stop();
else
Gyroscope.Start(speed);
}
catch (FeatureNotSupportedException fnsEx)
{
// Feature not supported on device
}
catch (Exception ex)
{
// Other error has occurred.
}
}
}

Sensor de velocidade
Mais rápido – obtenha os dados do sensor o mais rápido possível (não é garantido retornar no thread de
interface do usuário).
Jogo – taxa adequada para jogos (não é garantido retornar no thread de interface do usuário).
Normal – taxa padrão adequada para alterações de orientação da tela.
Interface do usuário – taxa adequada para a interface do usuário geral.
Se o manipulador de eventos não tiver a garantia de ser executado no thread da interface do usuário e se precisar
acessar os elementos de interface do usuário, use o método MainThread.BeginInvokeOnMainThread para executar
esse código no thread da interface do usuário.

API
Código-fonte de Giroscópio
Documentação da API de Giroscópio
Xamarin.Essentials: Inicializador
12/04/2019 • 2 minutes to read • Edit Online

A classe Launcher permite que um aplicativo abra um URI pelo sistema. Isso geralmente é utilizado quando a
vinculação profunda é usada em esquemas de URI personalizados de outro aplicativo. Se quiser abrir o navegador
em um site, confira a API do Browser.

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a biblioteca
esteja corretamente instalada e configurada em seus projetos.

Uso do Launcher
Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

Para usar a funcionalidade Launcher, chame o método OpenAsync e passe uma string ou Uri para abrir.
Opcionalmente, o método CanOpenAsync pode ser usado para verificar se o esquema de URI pode ser tratado por
um aplicativo no dispositivo.

public class LauncherTest


{
public async Task OpenRideShareAsync()
{
var supportsUri = await Launcher.CanOpenAsync("lyft://");
if (supportsUri)
await Launcher.OpenAsync("lyft://ridetype?id=lyft_line");
}
}

Diferenças entre plataformas


Android
iOS
UWP
A Tarefa retornada de CanOpenAsync é concluída imediatamente.

API
Código-fonte do Inicializador
Documentação da API do Inicializador
Xamarin.Essentials: Magnetômetro
12/04/2019 • 2 minutes to read • Edit Online

A classe Magnetometer permite que você monitore o sensor do magnetômetro do dispositivo, que indica a
orientação do dispositivo em relação ao campo magnético da Terra.

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a biblioteca
esteja corretamente instalada e configurada em seus projetos.

Como usar Magnetometer


Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

A funcionalidade do Magnetometer chama os métodos Start e Stop para ficar atenta às alterações no
magnetômetro. Todas as alterações são enviadas de volta por meio do evento ReadingChanged . Veja um exemplo
de uso:
public class MagnetometerTest
{
// Set speed delay for monitoring changes.
SensorSpeed speed = SensorSpeed.UI;

public MagnetometerTest()
{
// Register for reading changes.
Magnetometer.ReadingChanged += Magnetometer_ReadingChanged;
}

void Magnetometer_ReadingChanged(object sender, MagnetometerChangedEventArgs e)


{
var data = e.Reading;
// Process MagneticField X, Y, and Z
Console.WriteLine($"Reading: X: {data.MagneticField.X}, Y: {data.MagneticField.Y}, Z:
{data.MagneticField.Z}");
}

public void ToggleMagnetometer()


{
try
{
if (Magnetometer.IsMonitoring)
Magnetometer.Stop();
else
Magnetometer.Start(speed);
}
catch (FeatureNotSupportedException fnsEx)
{
// Feature not supported on device
}
catch (Exception ex)
{
// Other error has occurred.
}
}
}

Todos os dados são retornados em µ (microteslas).

Sensor de velocidade
Mais rápido – obtenha os dados do sensor o mais rápido possível (não é garantido retornar no thread de
interface do usuário).
Jogo – taxa adequada para jogos (não é garantido retornar no thread de interface do usuário).
Normal – taxa padrão adequada para alterações de orientação da tela.
Interface do usuário – taxa adequada para a interface do usuário geral.
Se o manipulador de eventos não tiver a garantia de ser executado no thread da interface do usuário e se precisar
acessar os elementos de interface do usuário, use o método MainThread.BeginInvokeOnMainThread para executar
esse código no thread da interface do usuário.

API
Código-fonte de Magnetômetro
Documentação da API de Magnetômetro
Xamarin.Essentials: MainThread
12/04/2019 • 5 minutes to read • Edit Online

A classe MainThread permite que os aplicativos executem o código no thread de execução principal e
determinem se certo bloco de código está sendo executado no thread principal.

Informações preliminares
A maioria dos sistemas operacionais, incluindo iOS, Android e a Plataforma Universal do Windows, usa um
modelo de threading simples para o código que envolve a interface do usuário. Esse modelo é necessário para
serializar adequadamente os eventos da interface do usuário, incluindo pressionamentos de tecla e entrada de
toque. Este thread é frequentemente chamado de thread principal ou o thread da interface do usuário ou,
ainda, o thread da IU. A desvantagem desse modelo é que todo código que acessa os elementos da interface
do usuário deve ser executado no thread principal do aplicativo.
Às vezes, os aplicativos precisam usar eventos que chamam o manipulador de eventos em um thread de
execução secundário. (As classes Accelerometer , Compass , Gyroscope , Magnetometer e OrientationSensor do
Xamarin.Essentials podem todas retornar informações em um thread secundário, quando usadas com
velocidades mais rápidas). Se o manipulador de eventos precisar acessar os elementos da interface do usuário,
ele deverá executar esse código no thread principal. A classe MainThread permite que os aplicativos
executem esse código no thread principal.

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a
biblioteca esteja corretamente instalada e configurada em seus projetos.

Como executar códigos no Thread Principal


Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

Para executar o código no thread principal, chame o método MainThread.BeginInvokeOnMainThread estático. O


argumento é um objeto Action , que é simplesmente um método sem argumentos e sem valor de retorno:

MainThread.BeginInvokeOnMainThread(() =>
{
// Code to run on the main thread
});

Também é possível definir um método separado para o código que deverá ser executado no thread principal:

void MyMainThreadCode()
{
// Code to run on the main thread
}

Você pode executar esse método no thread principal fazendo referência a ele no método
BeginInvokeOnMainThread :

MainThread.BeginInvokeOnMainThread(MyMainThreadCode);

NOTE
O Xamarin.Forms tem um método chamado Device.BeginInvokeOnMainThread(Action) , que faz o mesmo que
MainThread.BeginInvokeOnMainThread(Action) . Embora você possa usar qualquer método em um aplicativo
Xamarin.Forms, considere se o código de chamada tem ou não alguma outra necessidade de dependência no
Xamarin.Forms. Caso contrário, é provável que MainThread.BeginInvokeOnMainThread(Action) seja uma opção
melhor.

Como determinar se o código está em execução no thread principal


A classe MainThread também permite que um aplicativo determine se certo bloco de código está em execução
no thread principal. A propriedade IsMainThread retorna true se o código que chama a propriedade estiver
em execução no thread principal. Um programa pode usar essa propriedade para executar um código
diferente no thread principal ou em um thread secundário:

if (MainThread.IsMainThread)
{
// Code to run if this is the main thread
}
else
{
// Code to run if this is a secondary thread
}

Você pode se perguntar se deve verificar se o código está sendo executado em um thread secundário antes de
chamar BeginInvokeOnMainThread , por exemplo:

if (MainThread.IsMainThread)
{
MyMainThreadCode();
}
else
{
MainThread.BeginInvokeOnMainThread(MyMainThreadCode);
}

Você pode suspeitar que essa verificação possa melhorar o desempenho se o bloco de código já estiver em
execução no thread principal.
No entanto, essa verificação não é necessária. As implementações da plataforma de BeginInvokeOnMainThread
verificam se a chamada é feita no thread principal. A perda de desempenho é pouca se você chamar
BeginInvokeOnMainThread quando não for realmente necessário.

API
Código-fonte do MainThread
Documentação da API do MainThread
Xamarin.Essentials: Mapa
12/04/2019 • 3 minutes to read • Edit Online

A classe Maps permite que um aplicativo abra o aplicativo de mapas instalado em um local ou marcador
específico.

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a biblioteca
esteja corretamente instalada e configurada em seus projetos.

Usando o mapa
Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

A funcionalidade Map funciona chamando o método OpenAsync com Location ou Placemark para abrir com
MapLaunchOptions opcional.

public class MapTest


{
public async Task NavigateToBuilding25()
{
var location = new Location(47.645160, -122.1306032);
var options = new MapLaunchOptions { Name = "Microsoft Building 25" };

await Map.OpenAsync(location, options);


}
}

Ao abrir com um Placemark , as seguintes informações são necessárias:


CountryName
AdminArea
Thoroughfare
Locality
public class MapTest
{
public async Task NavigateToBuilding25()
{
var placemark = new Placemark
{
CountryName = "United States",
AdminArea = "WA",
Thoroughfare = "Microsoft Building 25",
Locality = "Redmond"
};
var options = new MapLaunchOptions { Name = "Microsoft Building 25" };

await Map.OpenAsync(placemark, options);


}
}

Métodos de extensão
Se você já tiver uma referência a uma Location ou Placemark , use o método de extensão interno OpenMapAsync
com MapLaunchOptions opcional:

public class MapTest


{
public async Task OpenPlacemarkOnMap(Placemark placemark)
{
await placemark.OpenMapAsync();
}
}

Modo de direções
Se você chamar OpenMapAsync sem MapLaunchOptions , o mapa será iniciado no local especificado. Se quiser, tenha
uma rota de navegação calculada a partir da posição atual do dispositivo. Isso é feito definindo o NavigationMode
nas MapLaunchOptions :

public class MapTest


{
public async Task NavigateToBuilding25()
{
var location = new Location(47.645160, -122.1306032);
var options = new MapLaunchOptions { NavigationMode = NavigationMode.Driving };

await Map.OpenAsync(location, options);


}
}

Diferenças entre plataformas


Android
iOS
UWP
NavigationMode Compatível com Ciclismo, Condução de veículos e Caminhada.

Particularidades de implementação da plataforma


Android
iOS
UWP
O Android usa o esquema de Uri geo: para iniciar o aplicativo de mapas no dispositivo. Isso pode levar o usuário
a optar por um aplicativo existente que suporte esse esquema de Uri. O Xamarin.Essentials é testado com o
Google Maps, que é compatível com este esquema.

API
Código-fonte do Mapa
Documentação da API do Mapa

Vídeo relacionados
Saiba mais sobre o Xamarin Show no Channel 9 e no YouTube.
Xamarin.Essentials: Navegador
12/04/2019 • 2 minutes to read • Edit Online

A classe Browser permite que um aplicativo abra um link da Web no navegador preferido do sistema otimizado
ou no navegador externo.

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a biblioteca
esteja corretamente instalada e configurada em seus projetos.

Uso do Browser
Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

A funcionalidade Browser funciona chamando o método OpenAsync com Uri e BrowserLaunchMode .

public class BrowserTest


{
public async Task<bool> OpenBrowser(Uri uri)
{
return await Browser.OpenAsync(uri, BrowserLaunchMode.SystemPreferred);
}
}

Esse método retorna depois que o navegador foi iniciado e não necessariamente fechado pelo usuário. O bool
resultado indica se a inicialização foi bem-sucedida ou não.

Personalização
Ao usar o navegador preferencial do sistema, existem várias opções de personalização disponíveis para iOS e
Android. Isso inclui um TitleMode (somente Android) e opções de cores preferenciais para a Toolbar (iOS e
Android) e os Controls (somente iOS ) que são exibidos.
Essas opções são especificadas usando BrowserLaunchOptions ao chamar OpenAsync .

await Browser.OpenAsync(uri, new BrowserLaunchOptions


{
LaunchMode = BrowserLaunchMode.SystemPreferred,
TitleMode = BrowserTitleMode.Show,
PreferredToolbarColor = Color.AliceBlue,
PreferredControlColor = Color.Violet
});
Particularidades de implementação da plataforma
Android
iOS
UWP
O Modo de Inicialização determina como o navegador é iniciado:

Sistema preferido
As Custom Tabs do Chrome tentarão ser usadas para carregar o Uri e manter o reconhecimento da navegação.

Externo
Uma Intent será usada para solicitar o Uri que será aberto por meio do navegador normal dos sistemas.

API
Código-fonte do Browser
Documentação da API do Browser

Vídeo relacionados

Saiba mais sobre o Xamarin Show no Channel 9 e no YouTube.


Xamarin.Essentials: OrientationSensor
12/04/2019 • 7 minutes to read • Edit Online

A classe OrientationSensor permite monitorar a orientação de um dispositivo no espaço tridimensional.

NOTE
Essa classe é usada para determinar a orientação de um dispositivo no espaço tridimensional. Se for necessário determinar
se a exibição de vídeo do dispositivo está no modo retrato ou paisagem, use a propriedade Orientation do objeto
ScreenMetrics disponível na classe DeviceDisplay .

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a biblioteca
esteja corretamente instalada e configurada em seus projetos.

Uso do OrientationSensor
Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

O OrientationSensor é habilitado pela chamada do método Start , para monitorar as alterações da orientação do
dispositivo, e desabilitado chamando o método Stop . Todas as alterações são enviadas de volta por meio do
evento ReadingChanged . Veja um exemplo de uso:
public class OrientationSensorTest
{
// Set speed delay for monitoring changes.
SensorSpeed speed = SensorSpeed.UI;

public OrientationSensorTest()
{
// Register for reading changes, be sure to unsubscribe when finished
OrientationSensor.ReadingChanged += OrientationSensor_ReadingChanged;
}

void OrientationSensor_ReadingChanged(object sender, OrientationSensorChangedEventArgs e)


{
var data = e.Reading;
Console.WriteLine($"Reading: X: {data.Orientation.X}, Y: {data.Orientation.Y}, Z:
{data.Orientation.Z}, W: {data.Orientation.W}");
// Process Orientation quaternion (X, Y, Z, and W)
}

public void ToggleOrientationSensor()


{
try
{
if (OrientationSensor.IsMonitoring)
OrientationSensor.Stop();
else
OrientationSensor.Start(speed);
}
catch (FeatureNotSupportedException fnsEx)
{
// Feature not supported on device
}
catch (Exception ex)
{
// Other error has occurred.
}
}
}

As leituras OrientationSensor são apresentadas na forma de um Quaternion que descreve a orientação do


dispositivo com base em dois sistemas de coordenadas 3D:
O dispositivo (geralmente um telefone ou tablet) possui um sistema de coordenadas 3D com os seguintes eixos:
O eixo positivo X aponta para o canto direito do visor no modo retrato.
O eixo positivo Y aponta para o canto superior do dispositivo no modo retrato.
O eixo positivo Z aponta para fora da tela.
O sistema de coordenadas 3D da Terra tem os seguintes eixos:
O eixo positivo X é a tangente da superfície da Terra e aponta para leste.
O eixo positivo Y também é a tangente da superfície da Terra e aponta para norte.
O eixo positivo Z é perpendicular à superfície da Terra e aponta para cima.
O Quaternion descreve a rotação do sistema de coordenadas do dispositivo em relação ao sistema de
coordenadas da Terra.
Um valor Quaternion está muito intimamente relacionado à rotação em torno de um eixo. Se um eixo de rotação
for o vetor normalizado (ax, ay, az) e o ângulo de rotação for Θ, então, os componentes (X, Y, Z, W ) do quatérnio
serão:
(ax·sin(Θ/2), ay·sin(Θ/2), az·sin(Θ/2), cos(Θ/2))
x y z

Estes são sistemas de coordenadas à direita, portanto, com o polegar da mão direita apontado na direção positiva
do eixo de rotação, a curva dos dedos indica a direção da rotação para ângulos positivos.
Exemplos:
Os dois sistemas de coordenadas estarão alinhados quando o dispositivo estiver em uma mesa com a tela
voltada para cima e a parte superior do dispositivo (no modo retrato) estiver apontando para norte. O
valor Quaternion representa o quatérnio da identidade (0, 0, 0, 1). Todas as rotações podem ser analisadas
em relação a essa posição.
O valor Quaternion será (0, 0, 0.707, 0.707) quando dispositivo estiver em uma mesa com a tela voltada
para cima e a parte superior do dispositivo (no modo retrato) estiver apontando para oeste. O dispositivo
girou 90 graus em torno do eixo Z da Terra.
O dispositivo terá girado 90 graus ao redor do eixo X quando for colocado na posição vertical de modo
que a parte superior (no modo retrato) aponte para o céu e a parte de trás do dispositivo fique voltada para
norte. O valor Quaternion é (0.707, 0, 0, 0.707).
O dispositivo terá sido girado –90 graus ao redor do eixo Y (ou 90 graus ao redor do eixo negativo Y ) se
ele estiver posicionado de forma que sua borda esquerda esteja sobre uma mesa e os pontos superiores ao
norte. O valor Quaternion é (0, -0.707, 0, 0.707).

Sensor de velocidade
Mais rápido – obtenha os dados do sensor o mais rápido possível (não é garantido retornar no thread de
interface do usuário).
Jogo – taxa adequada para jogos (não é garantido retornar no thread de interface do usuário).
Normal – taxa padrão adequada para alterações de orientação da tela.
Interface do usuário – taxa adequada para a interface do usuário geral.
Se o manipulador de eventos não tiver a garantia de ser executado no thread da interface do usuário e se precisar
acessar os elementos de interface do usuário, use o método MainThread.BeginInvokeOnMainThread para executar
esse código no thread da interface do usuário.

API
Código-fonte do OrientationSensor
Documentação da API do OrientationSensor
Xamarin.Essentials: Discagem telefônica
12/04/2019 • 2 minutes to read • Edit Online

A classe PhoneDialer permite que um aplicativo abra um número de telefone pelo discador.

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a biblioteca
esteja corretamente instalada e configurada em seus projetos.

Como usar a Discagem telefônica


Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

A funcionalidade de Discagem telefônica chama o método Open com um número de telefone para abrir o
discador. Quando Open é solicitada, a API automaticamente tenta formatar o número com base no código de país,
caso tenha sido especificado.

public class PhoneDialerTest


{
public async Task PlacePhoneCall(string number)
{
try
{
PhoneDialer.Open(number);
}
catch (ArgumentNullException anEx)
{
// Number was null or white space
}
catch (FeatureNotSupportedException ex)
{
// Phone Dialer is not supported on this device.
}
catch (Exception ex)
{
// Other error has occurred.
}
}
}

API
Código-fonte de Discagem telefônica
Documentação da API de Discagem Telefônica
Xamarin.Essentials: Extensões de plataforma
12/04/2019 • 2 minutes to read • Edit Online

O Xamarin.Essentials fornece vários métodos de extensão de plataforma quando é preciso trabalhar com tipos de
plataforma, como retângulo, tamanho e o ponto. Isso significa que você pode converter entre a versão System
desses tipos para iOS, Android e tipos específicos de UWP.

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a biblioteca
esteja corretamente instalada e configurada em seus projetos.

Usando as extensões de plataforma


Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

Todas as extensões de plataforma só podem ser chamadas do iOS, do Android ou do projeto UWP.
Ponto

var system = new System.Drawing.Point(x, y);

// Convert to CoreGraphics.CGPoint, Android.Graphics.Point, and Windows.Foundation.Point


var platform = system.ToPlatformSize();

// Back to System.Drawing.Size
var system2 = platform.ToSystemSize();

Tamanho

var system = new System.Drawing.Size(width, height);

// Convert to CoreGraphics.CGSize, Android.Util.Size, and Windows.Foundation.Size


var platform = system.ToPlatformSize();

// Back to System.Drawing.Size
var system2 = platform.ToSystemSize();

Retângulo

var system = new System.Drawing.Rectangle(x, y, width, height);

// Convert to CoreGraphics.CGRect, Android.Graphics.Rect, and Windows.Foundation.Rect


var platform = system.ToPlatformSize();

// Back to System.Drawing.Size
var system2 = platform.ToSystemSize();

API
Código-fonte de conversores
Documentação da API de conversores de ponto
Documentação da API de conversores de retângulo
Documentação da API de conversores de tamanho
Xamarin.Essentials: Preferências
12/04/2019 • 4 minutes to read • Edit Online

A classe Preferences ajuda a armazenar as preferências do aplicativo em um repositório de chave/valor.

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a biblioteca
esteja corretamente instalada e configurada em seus projetos.

Como usar Preferences


Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

Para salvar um valor de uma determinada chave nas preferências:

Preferences.Set("my_key", "my_value");

Para recuperar um valor das preferências, ou um padrão, se não for definido:

var myValue = Preferences.Get("my_key", "default_value");

Para remover a chave das preferências:

Preferences.Remove("my_key");

Para remover todas as preferências:

Preferences.Clear();

Além desses métodos, cada uma pode receber um sharedName opcional que pode ser usado para criar
contêineres adicionais para preferência. Leia a seguir as particularidades de implementação da plataforma.

Tipos de dados com suporte


Os tipos de dados a seguir têm suporte em Preferences:
bool
double
int
float
long
string
DateTime
Detalhes da implementação
Os valores de DateTime são armazenados em um formato binário de 64 bits (inteiro longo) usando dois métodos
definidos pela classe DateTime : O método ToBinary é usado para codificar o valor DateTime , e o método
FromBinary decodifica o valor. Confira a documentação desses métodos para conhecer os ajustes que podem ser
feitos em valores decodificados ao armazenar um DateTime que não seja um valor UTC (Tempo Universal
Coordenado).

Particularidades de implementação da plataforma


Android
iOS
UWP
Todos os dados são armazenados em Preferências Compartilhadas. Se não houver um sharedName especificado,
as preferências compartilhadas padrão serão usadas, caso contrário, o nome será usado para obter preferências
compartilhadas privadas com o nome especificado.

Persistência
A desinstalação do aplicativo causará a remoção de todas as Preferências. Há uma exceção a isso para aplicativos
destinados ao Android 6.0 (API nível 23) ou posterior que usam Backup Automático. Esse recurso está ativado
por padrão e preserva os dados do aplicativo, incluindo Preferências Compartilhadas, que é o que a API de
Preferências utiliza. É possível desabilitar isso seguindo a documentação do Google.

Limitações
Ao armazenar uma cadeia de caracteres, essa API destina-se a armazenar pequenas quantidades de texto. O
desempenho pode ser abaixo da média se você tentar usá-lo para armazenar grandes quantidades de texto.

API
Código-fonte de Preferências
Documentação da API de Preferências

Vídeo relacionados
Saiba mais sobre o Xamarin Show no Channel 9 e no YouTube.
Xamarin.Essentials: Armazenamento seguro
18/04/2019 • 7 minutes to read • Edit Online

A classe SecureStorage ajuda a armazenar com segurança os pares de chave/valor simples.

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a biblioteca
esteja corretamente instalada e configurada em seus projetos.
Para acessar a funcionalidade SecureStorage, a seguinte configuração específica da plataforma é necessária:
Android
iOS
UWP

TIP
O Backup Automático para Aplicativos é um recurso do Android 6.0 (nível da API 23) e posterior que faz o backup dos dados
do aplicativo do usuário (preferências compartilhadas, arquivos no armazenamento interno do aplicativo e outros arquivos
específicos). Os dados são restaurados quando um aplicativo é reinstalado ou instalado em um novo dispositivo. Isso pode
afetar a SecureStorage , que utiliza as preferências de compartilhamento do backup e que não podem ser
descriptografadas quando a restauração ocorrer. O Xamarin.Essentials trata automaticamente desse caso removendo a chave
para que ela possa ser redefinida. No entanto, você pode avançar e desabilitar o Backup Automático.

Habilitar ou desabilitar o backup


Você pode optar por desabilitar o Backup Automático para todo o aplicativo definindo a configuração
android:allowBackup como falsa no arquivo AndroidManifest.xml . Essa abordagem só é recomendada se você
planeja restaurar dados de uma outra maneira.

<manifest ... >


...
<application android:allowBackup="false" ... >
...
</application>
</manifest>

Backup seletivo
O backup automático pode ser configurado para desabilitar o backup de um conteúdo específico. Você pode criar
uma regra personalizada definida para excluir itens do SecureStore de passarem por backup.
1. Defina o atributo android:fullBackupContent em seu AndroidManifest.xml:

<application ...
android:fullBackupContent="@xml/auto_backup_rules">
</application>

2. Crie um novo arquivo XML chamado auto_backup_rules.xml no diretório Resources/xml. Em seguida,


defina o seguinte conteúdo que inclui todas as preferências compartilhadas, exceto para SecureStorage :
<?xml version="1.0" encoding="utf-8"?>
<full-backup-content>
<include domain="sharedpref" path="."/>
<exclude domain="sharedpref" path="${applicationId}.xamarinessentials.xml"/>
</full-backup-content>

Uso do armazenamento seguro


Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

Para salvar um valor para uma determinada chave no armazenamento seguro:

try
{
await SecureStorage.SetAsync("oauth_token", "secret-oauth-token-value");
}
catch (Exception ex)
{
// Possible that device doesn't support secure storage on device.
}

Para recuperar um valor do armazenamento seguro:

try
{
var oauthToken = await SecureStorage.GetAsync("oauth_token");
}
catch (Exception ex)
{
// Possible that device doesn't support secure storage on device.
}

NOTE
Se não houver valores associados à chave solicitada, GetAsync retornará null .

Para remover uma chave específica, chame:

SecureStorage.Remove("oauth_token");

Para remover todas as chaves, chame:

SecureStorage.RemoveAll();

Particularidades de implementação da plataforma


Android
iOS
UWP
O Repositório de chaves do Android é usado para armazenar a chave de criptografia usada para criptografar o
valor antes que ele seja salvo em Preferências Compartilhadas com um nome de arquivo [ID -DO -SEU -PACOTE -
DE -APLICATIVO ].xamarinessentials. A chave usada no arquivo de preferências compartilhadas é um Hash
MD5 da chave passada para as APIs do SecureStorage .

Nível da API 23 e superior


Em níveis da API mais recentes, uma chave AES é obtida do Repositório de chaves do Android e usada com uma
cifra AES/GCM/NoPadding para criptografar o valor antes que ele seja armazenado no arquivo de preferências
compartilhadas.

Nível da API 22 e inferior


Em níveis de API mais antigos, o Repositório de chaves do Android só é compatível com o armazenamento de
chaves RSA, que é usado com uma cifra RSA/ECB/PKCS1Padding para criptografar uma chave AES
(aleatoriamente gerada no tempo de execução) e armazenado no arquivo de preferências compartilhadas sob a
chave SecureStorageKey, caso ainda não tenha sido gerado.
SecureStorage usa a API Preferências e segue a mesma persistência de dados descrita na documentação de
Preferências. Se um dispositivo fizer o upgrade do nível da API 22 ou inferior para o nível da API 23 e superior,
esse tipo de criptografia continuará a ser usado, a menos que o aplicativo seja desinstalado ou RemoveAll seja
chamado.

Limitações
Essa API destina-se a armazenar pequenas quantidades de texto. O desempenho pode ser lento se você tentar usá-
lo para armazenar grandes quantidades de texto.

API
Código-fonte de SecureStorage
Documentação da API de SecureStorage

Vídeo relacionados

Saiba mais sobre o Xamarin Show no Channel 9 e no YouTube.


Xamarin.Essentials: Compartilhar
12/04/2019 • 2 minutes to read • Edit Online

A classe Share permite que um aplicativo compartilhe dados, como links de texto e da Web com outros aplicativos
no dispositivo.

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a biblioteca
esteja corretamente instalada e configurada em seus projetos.

Usando o compartilhamento
Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

A funcionalidade Share funciona chamando o método RequestAsync com um conteúdo de solicitação de dados
que inclui informações para compartilhar com outros aplicativos. É possível combinar texto e Uri, e cada
plataforma tratará a filtragem com base no conteúdo.

public class ShareTest


{
public async Task ShareText(string text)
{
await Share.RequestAsync(new ShareTextRequest
{
Text = text,
Title = "Share Text"
});
}

public async Task ShareUri(string uri)


{
await Share.RequestAsync(new ShareTextRequest
{
Uri = uri,
Title = "Share Web Link"
});
}
}

Interface do usuário para compartilhar com aplicativo externo exibida quando uma solicitação é feita:
Diferenças entre plataformas
Android
iOS
UWP
Subject a propriedade é usada para o assunto desejado de uma mensagem.

Arquivos

O compartilhamento de arquivos está disponível como uma versão prévia experimental no Xamarin.Essentials
versão 1.1.0. Esse recurso permite que um aplicativo compartilhe arquivos com outros aplicativos no dispositivo.
Para habilitar esse recurso, defina a propriedade a seguir no código de inicialização do aplicativo:

ExperimentalFeatures.Enable(ExperimentalFeatures.ShareFileRequest);

Depois de habilitar o recurso, qualquer arquivo poderá ser compartilhado. O Xamarin.Essentials detectará
automaticamente o tipo de arquivo (MIME ) e solicitará um compartilhamento. Cada plataforma poderá ser
compatível somente com extensões de arquivo específicas.
Veja um exemplo de como gravar texto no disco e compartilhá-lo com outros aplicativos:

var fn = "Attachment.txt";
var file = Path.Combine(FileSystem.CacheDirectory, fn);
File.WriteAllText(file, "Hello World");

await Share.RequestAsync(new ShareFileRequest


{
Title = Title,
File = new ShareFile(file)
});

API
Compartilhar código-fonte
Compartilhar documentação da API

Vídeo relacionados
Saiba mais sobre o Xamarin Show no Channel 9 e no YouTube.
Xamarin.Essentials: SMS
12/04/2019 • 2 minutes to read • Edit Online

A classe Sms permite que um aplicativo abra o aplicativo de SMS padrão com uma determinada mensagem para
enviar para um destinatário.

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a biblioteca
esteja corretamente instalada e configurada em seus projetos.

Uso do SMS
Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

A funcionalidade do SMS funciona chamando o método ComposeAsync de uma SmsMessage que contém o
destinatário da mensagem e o corpo da mensagem, sendo ambos opcionais.

public class SmsTest


{
public async Task SendSms(string messageText, string recipient)
{
try
{
var message = new SmsMessage(messageText, new []{ recipient });
await Sms.ComposeAsync(message);
}
catch (FeatureNotSupportedException ex)
{
// Sms is not supported on this device.
}
catch (Exception ex)
{
// Other error has occurred.
}
}
}

Além disso, você pode passar vários destinatários para uma SmsMessage :
public class SmsTest
{
public async Task SendSms(string messageText, string[] recipients)
{
try
{
var message = new SmsMessage(messageText, recipients);
await Sms.ComposeAsync(message);
}
catch (FeatureNotSupportedException ex)
{
// Sms is not supported on this device.
}
catch (Exception ex)
{
// Other error has occurred.
}
}
}

API
Código-fonte do SMS
Documentação da API do SMS
Xamarin.Essentials: Conversão de texto em fala
12/04/2019 • 3 minutes to read • Edit Online

A classe TextToSpeech permite que um aplicativo utilize os mecanismos internos de conversão de texto em fala
para repetir o texto do dispositivo e, também, consulte os idiomas disponíveis, compatíveis com o mecanismo.

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a biblioteca
esteja corretamente instalada e configurada em seus projetos.

Uso da Conversão de Texto em Fala


Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

A Conversão de Texto em Fala funciona chamando o método SpeakAsync com texto e parâmetros opcionais e
retorna depois que a expressão é concluída.

public async Task SpeakNowDefaultSettings()


{
await TextToSpeech.SpeakAsync("Hello World");

// This method will block until utterance finishes.


}

public void SpeakNowDefaultSettings2()


{
TextToSpeech.SpeakAsync("Hello World").ContinueWith((t) =>
{
// Logic that will run after utterance finishes.

}, TaskScheduler.FromCurrentSynchronizationContext());
}

Esse método usa um recurso opcional CancellationToken para interromper a expressão após ela ser iniciada.

CancellationTokenSource cts;
public async Task SpeakNowDefaultSettings()
{
cts = new CancellationTokenSource();
await TextToSpeech.SpeakAsync("Hello World", cancelToken: cts.Token);

// This method will block until utterance finishes.


}

public void CancelSpeech()


{
if (cts?.IsCancellationRequested ?? false)
return;

cts.Cancel();
}
A Conversão de Texto em Fala automaticamente enfileirará as solicitações de voz do mesmo thread.

bool isBusy = false;


public void SpeakMultiple()
{
isBusy = true;
Task.Run(async () =>
{
await TextToSpeech.SpeakAsync("Hello World 1");
await TextToSpeech.SpeakAsync("Hello World 2");
await TextToSpeech.SpeakAsync("Hello World 3");
isBusy = false;
});

// or you can query multiple without a Task:


Task.WhenAll(
TextToSpeech.SpeakAsync("Hello World 1"),
TextToSpeech.SpeakAsync("Hello World 2"),
TextToSpeech.SpeakAsync("Hello World 3"))
.ContinueWith((t) => { isBusy = false; }, TaskScheduler.FromCurrentSynchronizationContext());
}

Configurações de fala
Para obter mais controle sobre como o áudio é falado com SpeechOptions , que permite definir o volume, o tom e a
localidade.

public async Task SpeakNow()


{
var settings = new SpeechOptions()
{
Volume = .75f,
Pitch = 1.0f
};

await TextToSpeech.SpeakAsync("Hello World", settings);


}

Veja a seguir os valores com suporte para esses parâmetros:

PARÂMETRO MÍNIMO MÁXIMO

Densidade 0 2.0

Volume 0 1.0

Localidades de fala
Cada plataforma suporta diferentes localidades, para responder em diferentes idiomas e sotaques. As plataformas
têm diferentes códigos e formas de especificar a localidade e é por isso que o Xamarin.Essentials fornece uma
classe Locale de plataforma cruzada e uma maneira de consultá-los com GetLocalesAsync .
public async Task SpeakNow()
{
var locales = await TextToSpeech.GetLocalesAsync();

// Grab the first locale


var locale = locales.FirstOrDefault();

var settings = new SpeechOptions()


{
Volume = .75f,
Pitch = 1.0f,
Locale = locale
};

await TextToSpeech.SpeakAsync("Hello World", settings);


}

Limitações
A fila de expressão não terá garantia se for chamada através de múltiplos threads.
Oficialmente, não há suporte para a reprodução de áudio em segundo plano.

API
Código-fonte TextToSpeech
Documentação da API do TextToSpeech
Xamarin.Essentials: Conversores de unidade
12/04/2019 • 2 minutes to read • Edit Online

A classe UnitConverters fornece vários conversores de unidade para ajudar os desenvolvedores ao usar o
Xamarin.Essentials.

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a biblioteca
esteja corretamente instalada e configurada em seus projetos.

Usando conversores de unidade


Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

Todos os conversores de unidade estão disponíveis com o uso da classe UnitConverters estática no
Xamarin.Essentials. Por exemplo, você pode converter facilmente Fahrenheit em Celsius.

var celcius = UnitConverters.FahrenheitToCelsius(32.0);

Veja esta lista das conversões disponíveis:


FahrenheitToCelsius
CelsiusToFahrenheit
CelsiusToKelvin
KelvinToCelsius
MilesToMeters
MilesToKilometers
KilometersToMiles
DegreesToRadians
RadiansToDegrees
DegreesPerSecondToRadiansPerSecond
RadiansPerSecondToDegreesPerSecond
DegreesPerSecondToHertz
RadiansPerSecondToHertz
HertzToDegreesPerSecond
HertzToRadiansPerSecond
KilopascalsToHectopascals
HectopascalsToKilopascals
KilopascalsToPascals
HectopascalsToPascals
AtmospheresToPascals
PascalsToAtmospheres
CoordinatesToMiles
CoordinatesToKilometers

API
Código-fonte de conversores de unidade
Documentação da API de conversores de unidade
Xamarin.Essentials: Controle de versão
12/04/2019 • 2 minutes to read • Edit Online

A classe VersionTracking permite que você verifique a versão e os números de build dos aplicativos, junto com
informações adicionais, por exemplo, se é a primeira vez que o aplicativo é iniciado ou, para a versão atual, obter
informações do build anterior e muito mais.

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a biblioteca
esteja corretamente instalada e configurada em seus projetos.

Como usar Version Tracking


Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

A primeira vez que você usar a classe VersionTracking, ela começará a acompanhar a versão atual. Chame
Track antecipadamente em seu aplicativo sempre que ele for carregado, a fim de garantir que as informações da
versão atual sejam rastreadas:

VersionTracking.Track();

Após a chamada da Track inicial, é possível ler as informações de versão:


// First time ever launched application
var firstLaunch = VersionTracking.IsFirstLaunchEver;

// First time launching current version


var firstLaunchCurrent = VersionTracking.IsFirstLaunchForCurrentVersion;

// First time launching current build


var firstLaunchBuild = VersionTracking.IsFirstLaunchForCurrentBuild;

// Current app version (2.0.0)


var currentVersion = VersionTracking.CurrentVersion;

// Current build (2)


var currentBuild = VersionTracking.CurrentBuild;

// Previous app version (1.0.0)


var previousVersion = VersionTracking.PreviousVersion;

// Previous app build (1)


var previousBuild = VersionTracking.PreviousBuild;

// First version of app installed (1.0.0)


var firstVersion = VersionTracking.FirstInstalledVersion;

// First build of app installed (1)


var firstBuild = VersionTracking.FirstInstalledBuild;

// List of versions installed (1.0.0, 2.0.0)


var versionHistory = VersionTracking.VersionHistory;

// List of builds installed (1, 2)


var buildHistory = VersionTracking.BuildHistory;

Particularidades de implementação da plataforma


Todas as informações de versão são armazenadas usando a API de Preferências no Xamarin.Essentials, são
armazenadas com um nome de arquivo [ID -DO -PACOTE -DO -SEU -
APLICATIVO ].xamarinessentials.versiontracking, e seguem as mesmas persistência de dados descritas na
documentação de Preferences.

API
Código-fonte de Controle de Versão
Documentação da API de Controle de Versão
Xamarin.Essentials: Vibração
12/04/2019 • 2 minutes to read • Edit Online

A classe Vibration permite iniciar e interromper a funcionalidade de vibrar por um tempo desejado.

Introdução
Para começar a usar essa API, leia o guia de Introdução para Xamarin.Essentials a fim de garantir que a biblioteca
esteja corretamente instalada e configurada em seus projetos.
Para acessar a funcionalidade de Vibração, a seguinte configuração específica da plataforma é necessária.
Android
iOS
UWP
A permissão de Vibração é necessária e deve ser configurada no projeto do Android. Isso pode ser usado das
seguintes maneiras:
Abra o arquivo AssemblyInfo.cs na pasta Propriedades e adicione:

[assembly: UsesPermission(Android.Manifest.Permission.Vibrate)]

OU Atualize o Manifesto do Android:


Abra o arquivo AndroidManifest.xml na pasta Propriedades e adicione o seguinte dentro do nó do manifesto.

<uses-permission android:name="android.permission.VIBRATE" />

Ou clique com o botão direito do mouse no projeto do Android e abra as propriedades do projeto. Em Manifesto
do Android, localize a área Permissões necessárias: e marque a permissão VIBRAR. Isso atualizará
automaticamente o arquivo AndroidManifest.xml.

Como usar a Vibração


Adicione uma referência ao Xamarin.Essentials na classe:

using Xamarin.Essentials;

A funcionalidade de vibração pode ser solicitada por um determinado tempo ou pelo padrão de 500
milissegundos.
try
{
// Use default vibration length
Vibration.Vibrate();

// Or use specified time


var duration = TimeSpan.FromSeconds(1);
Vibration.Vibrate(duration);
}
catch (FeatureNotSupportedException ex)
{
// Feature not supported on device
}
catch (Exception ex)
{
// Other error has occurred.
}

O cancelamento da vibração do dispositivo pode ser solicitado com o método Cancel :

try
{
Vibration.Cancel();
}
catch (FeatureNotSupportedException ex)
{
// Feature not supported on device
}
catch (Exception ex)
{
// Other error has occurred.
}

Diferenças entre plataformas


Android
iOS
UWP
Sem diferenças entre plataformas.

API
Código-fonte de Vibração
Documentação da API de Vibração
Xamarin.Essentials: Solução de problemas
12/04/2019 • 2 minutes to read • Edit Online

Erro: conflito de versão detectado para


Xamarin.Android.Support.Compat
O erro a seguir pode ocorrer ao atualizar pacotes NuGet (ou adicionar um novo pacote) com um projeto
Xamarin.Forms que usa o Xamarin.Essentials:

NU1107: Version conflict detected for Xamarin.Android.Support.Compat. Reference the package directly from the
project to resolve this issue.
MyApp -> Xamarin.Essentials 1.1.0 -> Xamarin.Android.Support.CustomTabs 28.0.0.1 ->
Xamarin.Android.Support.Compat (= 28.0.0.1)
MyApp -> Xamarin.Forms 3.1.0.583944 -> Xamarin.Android.Support.v4 25.4.0.2 -> Xamarin.Android.Support.Compat
(= 25.4.0.2).

O problema são dependências sem correspondência para os dois NuGets. Isso pode ser resolvido adicionando
manualmente uma versão específica da dependência (nesse caso, Xamarin.Android.Support.Compat) que
pode ser compatível com ambas.
Para fazer isso, adicione o NuGet que é a origem do conflito manualmente e use a lista Versão para selecionar
uma versão específica. No momento, a versão 28.0.0.1 do NuGet do Xamarin.Android.Support.Compat e do
Xamarin.Android.Support.Core.Util resolverão esse erro.
Confira esta postagem no blog para obter mais informações e um vídeo sobre como resolver o problema.
Se encontrar problemas ou localizar um bug, relate o que ocorreu no repositório GitHub do Xamarin.Essentials
GitHub.
Serviços de dados e de nuvem
12/04/2019 • 5 minutes to read

Aplicativos xamarin. Forms podem consumir serviços da web implementado usando uma ampla variedade de
tecnologias e este guia examinará como fazer isso.
Para obter uma introdução para o consumo do serviço web de plataforma cruzada na plataforma Xamarin,
consulte Introdução aos serviços Web.

Noções básicas da amostra


Este artigo fornece uma explicação detalhada sobre o aplicativo xamarin. Forms de exemplo que demonstra como
se comunicar com serviços web diferentes. Os tópicos abordados incluem a anatomia do aplicativo, as páginas, o
modelo de dados e chamar operações de serviço web.

Consumo de Serviços Web


Este guia demonstra como se comunicar com serviços web diferentes para fornecer criar, ler, atualizar e excluir
(CRUD ) funcionalidade a um aplicativo xamarin. Forms. Os tópicos abordados estão se comunicando serviços
ASMX, serviços WCF, serviços REST, e aplicativos móveis do Azure.

Autenticar o acesso as Serviços Web


Este guia explica como integrar serviços de autenticação em um aplicativo xamarin. Forms para permitir que os
usuários compartilham um back-end tendo apenas o acesso a seus próprios dados. Os tópicos abordados incluem
usando a autenticação básica com um serviço REST, usando o componente Xamarin.Auth para autenticar em
relação a provedores de identidade OAuthe o uso da autenticação embutida mecanismos oferecidos pelo
aplicativos móveis do Azure.

Sincronizar dados com Serviços Web


Este artigo explica como adicionar a funcionalidade de sincronização offline para um aplicativo xamarin. Forms.
Sincronização offline permite que os usuários interagem com um aplicativo móvel, exibir, adicionar ou modificar
dados, mesmo que não tem uma conexão de rede. As alterações são armazenadas em um banco de dados local e,
depois que o dispositivo estiver online, as alterações podem ser sincronizadas com o serviço web.

Enviar notificações por push


Este artigo demonstra como adicionar notificações por push a um aplicativo xamarin. Forms. Hubs de notificação
do Azure oferecem uma infraestrutura de push escalonável para enviar notificações por push de qualquer back-
end para qualquer plataforma móvel, eliminando a complexidade de um back-end precisar se comunicar com
sistemas de notificação de plataforma diferente.

Armazenar arquivos na nuvem


Este artigo demonstra como usar o xamarin. Forms para armazenar texto e dados binários no armazenamento do
Azure e como acessar os dados. Armazenamento do Azure é uma solução de armazenamento de nuvem
escalonáveis que pode ser usada para armazenar dados estruturados e não estruturados.

Pesquisar dados na nuvem


Este artigo demonstra como usar a biblioteca de pesquisa do Microsoft Azure para integrar a pesquisa do Azure
em um aplicativo xamarin. Forms. Pesquisa do Azure é um serviço de nuvem que fornece a indexação e consulta
de recursos para os dados carregados. Isso remove os requisitos de infraestrutura e as complexidades de algoritmo
de pesquisa normalmente associadas ao implementar a funcionalidade de pesquisa em um aplicativo.

Armazenar dados em um banco de dados de documento


Este guia demonstra como usar a biblioteca de cliente .NET padrão do Azure Cosmos DB para integrar um banco
de dados de documento de banco de dados do Azure Cosmos em um aplicativo xamarin. Forms. Um banco de
dados de documento de banco de dados do Azure Cosmos é um banco de dados NoSQL que fornece acesso de
baixa latência para documentos JSON, oferecendo um serviço de banco de dados rápida, altamente disponível e
dimensionável para aplicativos que necessitam de replicação global e escala contínua.

Adicionar inteligência com Serviços Cognitivos


Este guia explica como usar algumas das APIs Microsoft cognitivas serviços em um aplicativo xamarin. Forms.
Serviços cognitivos são um conjunto de APIs, SDKs e serviços disponíveis para os desenvolvedores a criar
aplicativos mais inteligente adicionando recursos, como reconhecimento facial, reconhecimento de fala e
compreensão de idioma.
Noções básicas da amostra
12/04/2019 • 9 minutes to read

baixar o exemplo
Este tópico fornece um passo a passo do aplicativo de exemplo do xamarin. Forms que demonstra como se
comunicar com serviços web diferentes. Enquanto a cada serviço web usa um aplicativo de exemplo separado,
elas são funcionalmente semelhantes e compartilharem classes comuns.
O aplicativo de lista de tarefas pendentes de exemplo descrito abaixo é usado para demonstrar como acessar os
diferentes tipos de back-ends da web de serviço com o xamarin. Forms. Ele fornece funcionalidade para:
Exiba uma lista de tarefas.
Adicionar, editar e excluir tarefas.
Defina o status da tarefa para 'concluído'.
Fale os campos de nome e Observações da tarefa.
Em todos os casos, as tarefas são armazenadas em um back-end que é acessado por meio de um serviço web.
Quando o aplicativo é iniciado, é exibida uma página que lista as tarefas recuperadas do serviço web e permite
que o usuário crie uma nova tarefa. Clicar em uma tarefa navega o aplicativo em uma segunda página em que a
tarefa pode ser editada, salvo, excluída e falada. O aplicativo final é mostrado abaixo:
Cada tópico deste guia fornece um link de download para um diferentes versão do aplicativo que demonstra um
tipo específico de back-end de serviço web. Baixe o código de exemplo relevante na página relacionadas ao estilo
de cada serviço web.

Noções básicas sobre a anatomia do aplicativo


O projeto PCL para cada aplicativo de exemplo consiste em três pastas principais:

PASTA FINALIDADE

Dados Contém as classes e interfaces usadas para gerenciar itens de


dados e se comunicar com o serviço web. No mínimo, isso
inclui o TodoItemManager classe, que é exposta por meio de
uma propriedade no App classe para invocar operações de
serviço web.

Modelos Contém as classes de modelo de dados para o aplicativo. No


mínimo, isso inclui o TodoItem classe, que modela um único
item de dados usados pelo aplicativo. A pasta também pode
incluir quaisquer classes adicionais usados para modelar
dados de usuário.

Exibições Contém as páginas do aplicativo. Isso geralmente consiste de


TodoListPage e TodoItemPage classes e as classes
adicionais usadas para fins de autenticação.

O projeto PCL para cada aplicativo também consiste em um número de arquivos importantes:

ARQUIVO FINALIDADE

Constants.cs O Constants classe, que especifica as constantes usadas


pelo aplicativo para se comunicar com o serviço web. Essas
constantes exigem a atualização para acessar seu serviço de
back-end pessoal criada em um provedor.

ITextToSpeech.cs O ITextToSpeech interface, que especifica que o Speak


método deve ser fornecido por qualquer classe de
implementação.
ARQUIVO FINALIDADE

Todo.cs O App classe que é responsável por instanciar os dois a


primeira página que será exibida pelo aplicativo em cada
plataforma, e o TodoItemManager classe que é usado para
chamar operações de serviço web.

Exibindo páginas
A maioria dos aplicativos de exemplo contém pelo menos duas páginas:
TodoListPage – esta página exibe uma lista de TodoItem instâncias e um ícone de tique se o TodoItem.Done é
de propriedade true . Clicar em um item navega para o TodoItemPage . Além disso, novos itens podem ser
criados, clicando na + símbolo.
TodoItemPage – esta página exibe os detalhes para o selecionado TodoItem e permite que ele seja editado,
salvo, excluído e falado.
Além disso, alguns aplicativos de exemplo contêm páginas adicionais que são usadas para gerenciar o processo
de autenticação do usuário.
Modelagem de dados
Cada aplicativo de exemplo usa o TodoItem classe para modelar os dados que são exibidos e enviados para o
serviço web para o armazenamento. O exemplo de código a seguir mostra a classe TodoItem :

public class TodoItem


{
public string ID { get; set; }
public string Name { get; set; }
public string Notes { get; set; }
public bool Done { get; set; }
}

O ID propriedade é usada para identificar exclusivamente cada TodoItem instância e são usados por cada
serviço da web para identificar os dados a serem atualizados ou excluídos.
Invocar operações de serviço Web
Operações de serviço Web são acessadas por meio de TodoItemManager classe e uma instância da classe podem
ser acessados por meio do App.TodoManager propriedade. O TodoItemManager classe fornece os seguintes
métodos para chamar operações de serviço web:
GetTasksAsync – esse método é usado para preencher a ListView control na TodoListPage com o TodoItem
instâncias recuperadas do serviço web.
SaveTaskAsync – esse método é usado para criar ou atualizar um TodoItem instância no serviço web.
DeleteTaskAsync – esse método é usado para excluir um TodoItem instância no serviço web.
Além disso, alguns aplicativos de exemplo contêm métodos adicionais no TodoItemManager classe, que são usados
para gerenciar o processo de autenticação do usuário.
Em vez de invocar as operações de serviço web diretamente, o TodoItemManager métodos de invocam métodos
em uma classe dependente que é injetado no TodoItemManager construtor. Por exemplo, um aplicativo de exemplo
injeta a RestService de classe para o TodoItemManager construtor para fornecer a implementação que usa APIs
REST para acessar os dados.
Converter texto em fala
A maioria dos aplicativos de exemplo contêm funcionalidade de texto em fala (TTS ) falar os valores de
TodoItem.Name e TodoItem.Notes propriedades. Isso é feito usando o OnSpeakActivated manipulador de eventos
no TodoItemPage de classe, conforme mostrado no exemplo de código a seguir:

void OnSpeakActivated (object sender, EventArgs e)


{
var todoItem = (TodoItem)BindingContext;
App.Speech.Speak(todoItem.Name + " " + todoItem.Notes);
}

Esse método simplesmente chama o Speak método é implementado por uma plataforma específica Speech
classe. Cada Speech classe implementa o ITextToSpeech interface, e código de inicialização específica da
plataforma cria uma instância da Speech classe que pode ser acessado por meio do App.Speech propriedade.

Resumo
Este tópico forneceu um passo a passo do aplicativo de exemplo de xamarin. Forms é usado para demonstrar
como se comunicar com serviços web diferentes. Enquanto a cada serviço web usa um aplicativo de exemplo
separados, eles se baseiam na mesma lógica de negócios e de interface do usuário conforme descrito acima -
apenas o mecanismo de armazenamento do web service dados é diferente.

Links relacionados
Versão ASMX (amostra)
Versão do WCF (amostra)
Versão REST (amostra)
Versão do Azure (exemplo)
Consumir serviços da Web
12/04/2019 • 3 minutes to read

Es_te guia demonstra como se comunicar com serviços web diferentes para fornecer criar, ler, atualizar e excluir
(CRUD ) funcionalidade a um aplicativo xamarin. Forms. Os tópicos abordados incluem a se comunicar com
serviços ASMX, os serviços WCF, serviços REST e aplicativos móveis do Azure.

Consumir um serviço Web do ASP.NET (ASMX)


Serviços Web do ASP.NET (ASMX) fornecem a capacidade de criar serviços web que enviam mensagens via HTTP
usando o protocolo de acesso a objeto simples (SOAP ). SOAP é um protocolo independente de plataforma e
independente de linguagem para criar e acessar serviços da web. Não é necessário que os consumidores de um
serviço ASMX sabe nada sobre a plataforma, um modelo de objeto ou uma linguagem de programação usada
para implementar o serviço. Eles só precisam entender como enviar e receber mensagens SOAP. Este artigo
demonstra como consumir um serviço da web ASMX de um aplicativo xamarin. Forms.

Consumir um serviço Web do Windows Communication Foundation


(WCF)
O WCF é a estrutura unificada da Microsoft para criar aplicativos orientados a serviços. Ele permite aos
desenvolvedores compilar aplicativos distribuídos seguros, confiáveis, transacionados e interoperáveis. Há
diferenças entre os serviços de Web do ASP.NET (ASMX) e WCF, mas é importante entender que o WCF suporta
as mesmas capacidades ASMX fornece — mensagens SOAP sobre HTTP. Este artigo demonstra como consumir
um serviço WCF SOAP de um aplicativo xamarin. Forms.

Consumir um serviço Web RESTful


REST Representational State Transfer () é um estilo de arquitetura para a criação de serviços web. Solicitações
REST são feitas via HTTP usando os mesmos verbos HTTP que navegadores da web usam para recuperar as
páginas da web e para enviar dados para servidores. Este artigo demonstra como consumir um serviço web
RESTful a partir de um aplicativo xamarin. Forms.

Consumo de um aplicativo móvel do Azure


Aplicativos móveis do Azure permitem que você desenvolva aplicativos com o back-ends escalonável hospedado
no serviço de aplicativo do Azure, com suporte para autenticação móvel, sincronização offline e notificações por
push. Neste artigo, que só é aplicável a aplicativos móveis do Azure que usam um back-end node. js, explica como
consultar, inserir, atualizar e excluir dados armazenados em uma tabela em uma instância dos aplicativos móveis do
Azure.

Links relacionados
Introdução aos serviços Web
Visão geral do suporte assíncrono
Consumir um serviço Web ASP.NET (ASMX)
18/04/2019 • 12 minutes to read

baixar o exemplo
ASMX fornece a capacidade de criar serviços web que enviam mensagens usando o SOAP Simple Object Access
Protocol (). SOAP é um protocolo independente de plataforma e linguagem para criar e acessar serviços web. Os
consumidores de um serviço ASMX não precisam saber nada sobre a plataforma, um modelo de objeto ou uma
linguagem de programação usada para implementar o serviço. Eles só precisam entender como enviar e receber
mensagens SOAP. Este artigo demonstra como consumir um serviço ASMX SOAP de um aplicativo xamarin.
Forms.
Uma mensagem SOAP é um documento XML que contém os seguintes elementos:
Um elemento raiz chamado Envelope que identifica o documento XML como uma mensagem SOAP.
Um recurso opcional cabeçalho elemento que contém informações específicas do aplicativo, como dados de
autenticação. Se o cabeçalho elemento está presente ele deve ser o primeiro elemento filho do Envelope
elemento.
Obrigatória corpo elemento que contém a mensagem SOAP para o destinatário.
Um recurso opcional falha elemento que é usado para indicar as mensagens de erro. Se o falhas elemento
estiver presente, ele deve ser um elemento filho do corpo elemento.
SOAP pode operar em vários protocolos de transporte, incluindo HTTP, SMTP, TCP e UDP. No entanto, um
serviço ASMX só pode operar sobre HTTP. A plataforma Xamarin dá suporte a implementações padrão de SOAP
1.1 via HTTP, e isso inclui suporte para muitas das configurações de serviço padrão do ASMX.
Este exemplo inclui os aplicativos móveis que são executados em dispositivos físicos ou emulados e um serviço
ASMX que fornece métodos para obter, adicionar, editar e excluir dados. Quando os aplicativos móveis são
executados, eles se conectam ao serviço ASMX hospedado localmente conforme mostrado na seguinte captura de
tela:
NOTE
No iOS 9 e superior, a segurança de transporte de aplicativo (ATS) impõe conexões seguras entre recursos da internet (como
o servidor de back-end do aplicativo) e o aplicativo, impedindo assim a divulgação acidental de informações confidenciais.
Desde que o ATS é habilitado por padrão em aplicativos criados para o iOS 9, todas as conexões serão sujeitos a requisitos
de segurança ATS. Se as conexões não atender a esses requisitos, eles falharão com uma exceção. ATS poderá ser aceito de se
ele não é possível usar o HTTPS de protocolo e proteger a comunicação para recursos da internet. Isso pode ser feito
atualizando o aplicativo Info. plist arquivo. Para obter mais informações, consulte segurança de transporte de aplicativo.

Consumir o serviço web


O serviço ASMX oferece as seguintes operações:

OPERAÇÃO DESCRIÇÃO PARÂMETROS

GetTodoItems Obter uma lista de itens pendentes

CreateTodoItem Criar um novo item pendente Um XML serializado TodoItem

EditTodoItem Atualizar um item pendente Um XML serializado TodoItem

DeleteTodoItem Excluir um item pendente Um XML serializado TodoItem

Para obter mais informações sobre o modelo de dados usado no aplicativo, consulte modelagem de dados.

Criar o proxy TodoService


Uma classe de proxy, chamada TodoService , estende SoapHttpClientProtocol e fornece métodos para se
comunicar com o serviço ASMX em HTTP. O proxy é gerado, adicionando uma referência web para cada projeto
específico da plataforma no 2019 do Visual Studio ou Visual Studio 2017. A referência web gera métodos e
eventos para cada ação definida no documento de descrição linguagem WSDL (Web Services) do serviço.
Por exemplo, o GetTodoItemsação de serviço resulta em um GetTodoItemsAsync método e um
GetTodoItemsCompleted eventos no proxy. O método gerado tem um tipo de retorno void e invoca o GetTodoItems
ação pai SoapHttpClientProtocol classe. Quando o método invocado recebe uma resposta do serviço, ele aciona o
GetTodoItemsCompleted evento e fornece os dados de resposta dentro do evento Result propriedade.

Criar a implementação de ISoapService


Para habilitar o projeto compartilhado e de plataforma cruzada trabalhar com o serviço, o exemplo define o
ISoapService da interface, que segue o modelo de programação assíncrona de tarefa em C# . Cada plataforma
implementa o ISoapService para expor o proxy específico da plataforma. O exemplo usa TaskCompletionSource
objetos para expor o proxy como uma interface de tarefa assíncrona. Detalhes sobre como usar
TaskCompletionSource são encontrados nas implementações de cada tipo de ação nas seções a seguir.

O exemplo SoapService :
1. Cria uma instância de TodoService como uma instância de nível de classe
2. Cria uma coleção chamada Items para armazenar TodoItem objetos
3. Especifica um ponto de extremidade personalizado para opcional Url propriedade sobre a TodoService

public class SoapService : ISoapService


{
ASMXService.TodoService todoService;
public List<TodoItem> Items { get; private set; } = new List<TodoItem>();

public SoapService ()
{
todoService = new ASMXService.TodoService ();
todoService.Url = Constants.SoapUrl;
...
}
}

Criar objetos de transferência de dados


O aplicativo de exemplo usa o TodoItem classe para dados de modelo. Para armazenar um TodoItem item no
serviço da web, ele deve primeiro ser convertido para o proxy gerado TodoItem tipo. Isso é feito usando o
ToASMXServiceTodoItem método, conforme mostrado no exemplo de código a seguir:

ASMXService.TodoItem ToASMXServiceTodoItem (TodoItem item)


{
return new ASMXService.TodoItem {
ID = item.ID,
Name = item.Name,
Notes = item.Notes,
Done = item.Done
};
}

Esse método cria uma nova ASMService.TodoItem da instância e define cada propriedade para a propriedade
idêntica do TodoItem instância.
Da mesma forma, quando os dados são recuperados do serviço da web, ele deve ser convertido do proxy gerado
TodoItem de tipo para um TodoItem instância. Isso é feito com o FromASMXServiceTodoItem método, conforme
mostrado no exemplo de código a seguir:
static TodoItem FromASMXServiceTodoItem (ASMXService.TodoItem item)
{
return new TodoItem {
ID = item.ID,
Name = item.Name,
Notes = item.Notes,
Done = item.Done
};
}

Esse método recupera os dados do proxy gerado TodoItem de tipo e define-a no recém-criado TodoItem instância.
Recuperar dados
O ISoapService interface espera que o RefreshDataAsync método retorne um Task com a coleção de itens. No
entanto, o TodoService.GetTodoItemsAsync método retorna void. Para satisfazer o padrão de interface, você deve
chamar GetTodoItemsAsync , aguarde até que o GetTodoItemsCompleted evento seja acionado e popular a coleção.
Isso permite que você retorne uma coleção válida para a interface do usuário.
O exemplo a seguir cria um novo TaskCompletionSource , inicia a chamada assíncrona na RefreshDataAsync método
e aguarda o Task fornecidos pelo TaskCompletionSource . Quando o TodoService_GetTodoItemsCompleted
manipulador de eventos é invocado ele preenche os Items coleção e atualizações a TaskCompletionSource :
public class SoapService : ISoapService
{
TaskCompletionSource<bool> getRequestComplete = null;
...

public SoapService()
{
...
todoService.GetTodoItemsCompleted += TodoService_GetTodoItemsCompleted;
}

public async Task<List<TodoItem>> RefreshDataAsync()


{
getRequestComplete = new TaskCompletionSource<bool>();
todoService.GetTodoItemsAsync();
await getRequestComplete.Task;
return Items;
}

private void TodoService_GetTodoItemsCompleted(object sender, ASMXService.GetTodoItemsCompletedEventArgs


e)
{
try
{
getRequestComplete = getRequestComplete ?? new TaskCompletionSource<bool>();

Items = new List<TodoItem>();


foreach (var item in e.Result)
{
Items.Add(FromASMXServiceTodoItem(item));
}
getRequestComplete?.TrySetResult(true);
}
catch (Exception ex)
{
Debug.WriteLine(@"\t\tERROR {0}", ex.Message);
}
}

...
}

Para obter mais informações, consulte modelo de programação assíncrona e .NET Framework programação
assíncrona tradicional e TPL.
Criar ou editar dados
Quando você cria ou edita dados, você deve implementar o ISoapService.SaveTodoItemAsync método. Este método
detecta se o TodoItem é um item novo ou atualizado e chama o método apropriado no todoService objeto. O
CreateTodoItemCompleted e EditTodoItemCompleted manipuladores de eventos devem ser implementados para que
você saiba quando o todoService recebeu uma resposta do serviço ASMX (eles podem ser combinados em um
único manipulador porque elas executam a mesma operação). O exemplo a seguir demonstra as implementações
de manipulador de interface e eventos, bem como o TaskCompletionSource objeto usado para operar de maneira
assíncrona:
public class SoapService : ISoapService
{
TaskCompletionSource<bool> saveRequestComplete = null;
...

public SoapService()
{
...
todoService.CreateTodoItemCompleted += TodoService_SaveTodoItemCompleted;
todoService.EditTodoItemCompleted += TodoService_SaveTodoItemCompleted;
}

public async Task SaveTodoItemAsync (TodoItem item, bool isNewItem = false)


{
try
{
var todoItem = ToASMXServiceTodoItem(item);
saveRequestComplete = new TaskCompletionSource<bool>();
if (isNewItem)
{
todoService.CreateTodoItemAsync(todoItem);
}
else
{
todoService.EditTodoItemAsync(todoItem);
}
await saveRequestComplete.Task;
}
catch (SoapException se)
{
Debug.WriteLine("\t\t{0}", se.Message);
}
catch (Exception ex)
{
Debug.WriteLine("\t\tERROR {0}", ex.Message);
}
}

private void TodoService_SaveTodoItemCompleted(object sender,


System.ComponentModel.AsyncCompletedEventArgs e)
{
saveRequestComplete?.TrySetResult(true);
}

...
}

Excluir dados
A exclusão de dados requer uma implementação semelhante. Definir um TaskCompletionSource , implemente um
manipulador de eventos e o ISoapService.DeleteTodoItemAsync método:
public class SoapService : ISoapService
{
TaskCompletionSource<bool> deleteRequestComplete = null;
...

public SoapService()
{
...
todoService.DeleteTodoItemCompleted += TodoService_DeleteTodoItemCompleted;
}

public async Task DeleteTodoItemAsync (string id)


{
try
{
deleteRequestComplete = new TaskCompletionSource<bool>();
todoService.DeleteTodoItemAsync(id);
await deleteRequestComplete.Task;
}
catch (SoapException se)
{
Debug.WriteLine("\t\t{0}", se.Message);
}
catch (Exception ex)
{
Debug.WriteLine("\t\tERROR {0}", ex.Message);
}
}

private void TodoService_DeleteTodoItemCompleted(object sender,


System.ComponentModel.AsyncCompletedEventArgs e)
{
deleteRequestComplete?.TrySetResult(true);
}

...
}

Testar o serviço web


Teste físicos ou emulados dispositivos com um serviço hospedado localmente requer a configuração
personalizada do IIS, endereços de ponto de extremidade e regras de firewall para estar em vigor. Para obter mais
detalhes sobre como configurar seu ambiente de teste, consulte o configurar o acesso remoto para o IIS Express.
A única diferença entre o teste de WCF e ASMX é o número da porta do TodoService.

Links relacionados
TodoASMX (amostra)
IAsyncResult
Consumir um serviço Web do Windows
Communication Foundation (WCF)
12/04/2019 • 24 minutes to read

[![Dbaixar exemplo](~/media/shared/download.png) Baixar a amostra]


(https://developer.xamarin.com/samples/xamarin-forms/WebServices/TodoWCF/)
O WCF é a estrutura unificada da Microsoft para a criação de aplicativos orientados a serviço. Ele permite aos
desenvolvedores compilar aplicativos distribuídos seguros, confiáveis, transacionados e interoperáveis. Este artigo
demonstra como consumir um serviço WCF SOAP Simple Object Access Protocol () de um aplicativo xamarin.
Forms.
WCF descreve um serviço com uma variedade de contratos diferentes incluindo:
Contratos de dados – definir as estruturas de dados que formam a base para o conteúdo dentro de uma
mensagem.
Contratos de mensagem – compor mensagens de contratos de dados existente.
Contratos de falha – permitir que as falhas SOAP personalizadas sejam especificados.
Contratos de serviço – especificar as operações que dão suporte a serviços e as mensagens necessárias para
interagir com cada operação. Eles também pode especificar qualquer comportamento de falha personalizado
que pode ser associado a operações em cada serviço.
Há diferenças entre dá suporte a serviços de Web do ASP.NET (ASMX) e o WCF, mas o WCF os mesmos recursos
que fornece ASMX – mensagens SOAP sobre HTTP. Para obter mais informações sobre como consumir um
serviço ASMX, consulte consumindo ASP.NET Web Services (ASMX).

IMPORTANT
O suporte de plataforma do Xamarin para o WCF é limitado a texto codificado mensagens SOAP sobre HTTP/HTTPS usando
o BasicHttpBinding classe.
Suporte do WCF requer o uso das ferramentas disponíveis somente em um ambiente do Windows para gerar o proxy e
hospedar o TodoWCFService. Compilar e testar o aplicativo iOS exigirá a implantação de TodoWCFService em um
computador Windows ou como um serviço web do Azure.
Aplicativos nativos do Xamarin. Forms normalmente compartilham código com uma biblioteca de classes .NET Standard. No
entanto, .NET Core não suporta no momento WCF para que o projeto compartilhado deve ser uma biblioteca de classes
portátil herdado. Para obter informações sobre o suporte do WCF no .NET Core, consulte escolhendo entre o .NET Core e
.NET Framework para aplicativos de servidor.

A solução de aplicativo de exemplo inclui um serviço WCF que pode ser executado localmente e é mostrado na
seguinte captura de tela:
NOTE
No iOS 9 e superior, a segurança de transporte de aplicativo (ATS) impõe conexões seguras entre recursos da internet (como
o servidor de back-end do aplicativo) e o aplicativo, impedindo assim a divulgação acidental de informações confidenciais.
Desde que o ATS é habilitado por padrão em aplicativos criados para o iOS 9, todas as conexões serão sujeitos a requisitos de
segurança ATS. Se as conexões não atender a esses requisitos, eles falharão com uma exceção.
ATS poderá ser aceito de se ele não é possível usar o HTTPS de protocolo e proteger a comunicação para recursos da
internet. Isso pode ser feito atualizando o aplicativo Info. plist arquivo. Para obter mais informações, consulte segurança de
transporte de aplicativo.

Consumir o serviço web


O serviço WCF fornece as seguintes operações:

OPERAÇÃO DESCRIÇÃO PARÂMETROS

GetTodoItems Obter uma lista de itens pendentes

CreateTodoItem Criar um novo item pendente Um XML serializado TodoItem

EditTodoItem Atualizar um item pendente Um XML serializado TodoItem

DeleteTodoItem Excluir um item pendente Um XML serializado TodoItem

Para obter mais informações sobre o modelo de dados usado no aplicativo, consulte modelagem de dados.
Um proxy deve ser gerado para consumir um serviço WCF, que permite que o aplicativo para se conectar ao
serviço. O proxy é construído por consumo metadados de serviço que definem os métodos e a configuração de
serviço associado. Esses metadados são expostos na forma de um documento de descrição linguagem WSDL
(Web Services) que é gerado pelo serviço web. O proxy pode ser compilado usando o Microsoft WCF Web Service
Reference Provider no Visual Studio 2017 para adicionar uma referência de serviço para o serviço web a uma
biblioteca .NET Standard. Uma alternativa para criar o proxy usando o Microsoft WCF Web Service Reference
Provider no Visual Studio 2017 é usar a ferramenta Utilitário de metadados de ServiceModel (svcutil.exe). Para
obter mais informações, consulte ferramenta de utilitário de metadados ServiceModel (Svcutil.exe).
As classes de proxy geradas fornecem métodos para consumir os serviços web que usam o padrão de design do
modelo de programação assíncrona (APM ). Nesse padrão, uma operação assíncrona é implementada como dois
métodos chamados BeginOperationName e EndOperationName, que começam e terminam a operação
assíncrona.
O BeginOperationName método inicia a operação assíncrona e retorna um objeto que implementa o
IAsyncResult interface. Depois de chamar BeginOperationName, um aplicativo pode continuar a executar as
instruções no thread de chamada, enquanto a operação assíncrona ocorre em um pool de threads.
Para cada chamada para BeginOperationName, o aplicativo também deve chamar EndOperationName para obter
os resultados da operação. O valor de retorno EndOperationName é do mesmo tipo retornado pelo método de
serviço da web síncronas. Por exemplo, o EndGetTodoItems método retorna uma coleção de TodoItem instâncias. O
EndOperationName método também inclui um IAsyncResult parâmetro deve ser definido como a instância
retornada pela chamada correspondente para o BeginOperationName método.
A tarefa paralela TPL (biblioteca) pode simplificar o processo de consumir um par de métodos de início/término
do APM, encapsulando as operações assíncronas no mesmo Task objeto. Esse encapsulamento é fornecido pelas
várias sobrecargas do TaskFactory.FromAsync método.
Para obter mais informações sobre o APM, consulte modelo de programação assíncrona e .NET Framework
programação assíncrona tradicional e TPL no MSDN.
Criar o objeto TodoServiceClient
Fornece a classe proxy gerada a TodoServiceClient classe, que é usado para se comunicar com o serviço WCF por
meio de HTTP. Ele fornece funcionalidade para invocar métodos de serviço web, como operações assíncronas de
um URI identificado a instância de serviço. Para obter mais informações sobre as operações assíncronas, consulte
visão geral do suporte assíncrono.
O TodoServiceClient instância é declarada no nível de classe, de modo que o objeto reside para desde que o
aplicativo precisa consumir o serviço WCF, conforme mostrado no exemplo de código a seguir:

public class SoapService : ISoapService


{
ITodoService todoService;
...

public SoapService ()
{
todoService = new TodoServiceClient (
new BasicHttpBinding (),
new EndpointAddress (Constants.SoapUrl));
}
...
}

O TodoServiceClient instância é configurada com informações e um endereço de ponto de extremidade de


associação. Uma associação é usada para especificar o transporte, codificação e detalhes de protocolo necessários
para aplicativos e serviços para se comunicar entre si. O BasicHttpBinding Especifica que as mensagens SOAP
texto codificado serão enviadas através do protocolo de transporte HTTP. Especificação de um endereço de ponto
de extremidade permite que o aplicativo para se conectar a diferentes instâncias do serviço do WCF, desde que há
várias instâncias publicadas.
Para obter mais informações sobre como configurar a referência de serviço, consulte Configurando a referência de
serviço.
Criar objetos de transferência de dados
O aplicativo de exemplo usa o TodoItem classe para dados de modelo. Para armazenar um TodoItem item no
serviço da web, ele deve primeiro ser convertido para o proxy gerado TodoItem tipo. Isso é feito usando o
ToWCFServiceTodoItem método, conforme mostrado no exemplo de código a seguir:

TodoWCFService.TodoItem ToWCFServiceTodoItem (TodoItem item)


{
return new TodoWCFService.TodoItem
{
ID = item.ID,
Name = item.Name,
Notes = item.Notes,
Done = item.Done
};
}

Esse método simplesmente cria um novo TodoWCFService.TodoItem da instância e define cada propriedade para a
propriedade idêntica do TodoItem instância.
Da mesma forma, quando os dados são recuperados do serviço da web, ele deve ser convertido do proxy gerado
TodoItem de tipo para um TodoItem instância. Isso é feito com o FromWCFServiceTodoItem método, conforme
mostrado no exemplo de código a seguir:

static TodoItem FromWCFServiceTodoItem (TodoWCFService.TodoItem item)


{
return new TodoItem
{
ID = item.ID,
Name = item.Name,
Notes = item.Notes,
Done = item.Done
};
}

Esse método simplesmente recupera os dados do proxy gerado TodoItem de tipo e define-a no recém-criado
TodoItem instância.

Recuperar dados
O TodoServiceClient.BeginGetTodoItems e TodoServiceClient.EndGetTodoItems métodos são usados para chamar o
GetTodoItems operação fornecidos pelo serviço web. Esses métodos assíncronos são encapsulados em um Task
do objeto, conforme mostrado no exemplo de código a seguir:
public async Task<List<TodoItem>> RefreshDataAsync ()
{
...
var todoItems = await Task.Factory.FromAsync <ObservableCollection<TodoWCFService.TodoItem>> (
todoService.BeginGetTodoItems,
todoService.EndGetTodoItems,
null,
TaskCreationOptions.None);

foreach (var item in todoItems)


{
Items.Add (FromWCFServiceTodoItem (item));
}
...
}

O Task.Factory.FromAsync método cria uma Task que executa o TodoServiceClient.EndGetTodoItems método uma
vez o TodoServiceClient.BeginGetTodoItems método é concluído, com o null parâmetro que indica que nenhum
dado está sendo passado para o BeginGetTodoItems delegar. Por fim, o valor da TaskCreationOptions enumeração
que especifica que o comportamento padrão para a criação e execução de tarefas deve ser usado.
O TodoServiceClient.EndGetTodoItems método retorna um ObservableCollection de TodoWCFService.TodoItem
instâncias, que, em seguida, é convertido em um List de TodoItem instâncias para exibição.
Criar dados
O TodoServiceClient.BeginCreateTodoItem e TodoServiceClient.EndCreateTodoItem métodos são usados para
chamar o CreateTodoItem operação fornecidos pelo serviço web. Esses métodos assíncronos são encapsulados em
um Task do objeto, conforme mostrado no exemplo de código a seguir:

public async Task SaveTodoItemAsync (TodoItem item, bool isNewItem = false)


{
...
var todoItem = ToWCFServiceTodoItem (item);
...
await Task.Factory.FromAsync (
todoService.BeginCreateTodoItem,
todoService.EndCreateTodoItem,
todoItem,
TaskCreationOptions.None);
...
}

O Task.Factory.FromAsync método cria uma Task que executa o TodoServiceClient.EndCreateTodoItem método


uma vez o TodoServiceClient.BeginCreateTodoItem método é concluído, com o todoItem parâmetro sendo os
dados que são passados para o BeginCreateTodoItem delegado para especificar o TodoItem a ser criado pelo
serviço web. Por fim, o valor da TaskCreationOptions enumeração que especifica que o comportamento padrão
para a criação e execução de tarefas deve ser usado.
A web service lança um FaultException se ele falhar ao criar o TodoItem , que é tratada pelo aplicativo.
Atualizar dados
O TodoServiceClient.BeginEditTodoItem e TodoServiceClient.EndEditTodoItem métodos são usados para chamar o
EditTodoItem operação fornecidos pelo serviço web. Esses métodos assíncronos são encapsulados em um Task
do objeto, conforme mostrado no exemplo de código a seguir:
public async Task SaveTodoItemAsync (TodoItem item, bool isNewItem = false)
{
...
var todoItem = ToWCFServiceTodoItem (item);
...
await Task.Factory.FromAsync (
todoService.BeginEditTodoItem,
todoService.EndEditTodoItem,
todoItem,
TaskCreationOptions.None);
...
}

O Task.Factory.FromAsync método cria uma Task que executa o TodoServiceClient.EndEditTodoItem método uma
vez o TodoServiceClient.BeginCreateTodoItem método é concluído, com o todoItem parâmetro sendo os dados que
são passados para o BeginEditTodoItem delegado para especificar o TodoItem a ser atualizado pelo serviço web.
Por fim, o valor da TaskCreationOptions enumeração que especifica que o comportamento padrão para a criação e
execução de tarefas deve ser usado.
A web service lança um FaultException se ele não conseguir localizar ou atualizar o TodoItem , que é tratada pelo
aplicativo.
Excluir dados
O TodoServiceClient.BeginDeleteTodoItem e TodoServiceClient.EndDeleteTodoItem métodos são usados para
chamar o DeleteTodoItem operação fornecidos pelo serviço web. Esses métodos assíncronos são encapsulados em
um Task do objeto, conforme mostrado no exemplo de código a seguir:

public async Task DeleteTodoItemAsync (string id)


{
...
await Task.Factory.FromAsync (
todoService.BeginDeleteTodoItem,
todoService.EndDeleteTodoItem,
id,
TaskCreationOptions.None);
...
}

O Task.Factory.FromAsync método cria uma Task que executa o TodoServiceClient.EndDeleteTodoItem método


uma vez o TodoServiceClient.BeginDeleteTodoItem método é concluído, com o id parâmetro sendo os dados que
são passados para o BeginDeleteTodoItem delegado para especificar o TodoItem a ser excluído pelo serviço web.
Por fim, o valor da TaskCreationOptions enumeração que especifica que o comportamento padrão para a criação e
execução de tarefas deve ser usado.
A web service lança um FaultException se ele não conseguir localizar ou excluir o TodoItem , que é tratada pelo
aplicativo.

Configurar o acesso remoto para o IIS Express


No Visual Studio 2017 ou Visual Studio de 2019, você deve ser capaz de testar o aplicativo UWP em um PC sem
nenhuma configuração adicional. Testar os clientes do Android e iOS pode exigir que as etapas adicionais nesta
seção. Ver conectar-se a serviços da Web locais do iOS simuladores e emuladores Android para obter mais
informações.
Por padrão, o IIS Express só responderá a solicitações para localhost . Dispositivos remotos (como um dispositivo
Android, um iPhone ou até mesmo um simulador) não terá acesso ao seu serviço WCF local. Você precisará saber
seu endereço IP de estação de trabalho do Windows 10 na rede local. Nesse exemplo, suponha que sua estação de
trabalho tem o endereço IP 192.168.1.143 . As etapas a seguir explicam como configurar o Windows 10 e o IIS
Express para aceitar conexões remotas e conecte-se ao serviço de um dispositivo físico ou virtual:
1. Adicionar uma exceção ao Firewall do Windows. Você deve abrir uma porta por meio do Firewall do
Windows que os aplicativos em sua sub-rede podem usar para se comunicar com o serviço WCF. Crie uma
regra de entrada abrindo 49393 de porta no firewall. Em um prompt de comando administrativo, execute
este comando:

netsh advfirewall firewall add rule name="TodoWCFService" dir=in protocol=tcp localport=49393


profile=private remoteip=localsubnet action=allow

2. Configurar o IIS Express para conexões remotas aceitar. Você pode configurar o IIS Express editando
o arquivo de configuração para o IIS Express na [diretório da
solução].vs\config\applicationhost.config. Localizar o site elemento com o nome TodoWCFService .
Ele deve ser semelhante ao seguinte XML:

<site name="TodoWCFService" id="2">


<application path="/" applicationPool="Clr4IntegratedAppPool">
<virtualDirectory path="/" physicalPath="C:\Users\tom\TodoWCF\TodoWCFService\TodoWCFService" />
</application>
<bindings>
<binding protocol="http" bindingInformation="*:49393:localhost" />
</bindings>
</site>

Você precisará adicionar dois binding elementos para abrir a porta 49393 para o tráfego externo e o
emulador do Android. A associação usa um [IP address]:[port]:[hostname] formato que especifica como o
IIS Express irão responder às solicitações. As solicitações externas terão nomes de host que devem ser
especificado como um binding . Adicione o seguinte XML para o bindings elemento, substituindo o
endereço IP com seu próprio endereço IP:

<binding protocol="http" bindingInformation="*:49393:192.168.1.143" />


<binding protocol="http" bindingInformation="*:49393:127.0.0.1" />

Depois das alterações a bindings elemento deve ser semelhante ao seguinte:

<site name="TodoWCFService" id="2">


<application path="/" applicationPool="Clr4IntegratedAppPool">
<virtualDirectory path="/" physicalPath="C:\Users\tom\TodoWCF\TodoWCFService\TodoWCFService" />
</application>
<bindings>
<binding protocol="http" bindingInformation="*:49393:localhost" />
<binding protocol="http" bindingInformation="*:49393:192.168.1.143" />
<binding protocol="http" bindingInformation="*:49393:127.0.0.1" />
</bindings>
</site>

IMPORTANT
Por padrão, o IIS Express não aceita conexões de fontes externas, por motivos de segurança. Para habilitar conexões
de dispositivos remotos você deve executar o IIS Express com permissões administrativas. A maneira mais fácil de
fazer isso é executar o Visual Studio 2017 com permissões administrativas. Isso inicializará o IIS Express com
permissões administrativas ao executar o TodoWCFService.

Com essas etapas concluídas, você deve ser capaz de executar o TodoWCFService e conecte-se com outros
dispositivos na sua sub-rede. Você pode testar isso executando seu aplicativo e visitar
http://localhost:49393/TodoService.svc . Se você receber um solicitação incorreta erros ao visitar essa
URL e sua bindings pode estar incorreto na configuração IIS Express (a solicitação está alcançando o IIS
Express, mas está sendo rejeitada). Se você receber um erro diferente pode ser que seu aplicativo não está
em execução ou seu firewall está configurado incorretamente.
Para permitir que o IIS Express manter em execução e que atende o serviço, desative o editar e continuar
opção propriedades do projeto > Web > depuradores.
3. Personalizar o ponto de extremidade dispositivos usam para acessar o serviço. Esta etapa envolve a
configuração do aplicativo cliente, em execução em um dispositivo físico ou emulado, para acessar o serviço
do WCF.
O emulador do Android utiliza um proxy interno que impede que o emulador acessem diretamente da
máquina host localhost endereço. Em vez disso, o endereço 10.0.2.2 o emulador é roteado para
localhost no computador host por meio de um proxy interno. Essas solicitações com proxy terá 127.0.0.1
como o nome do host no cabeçalho da solicitação, que é por isso que você criou a associação do IIS Express
para esse nome de host nas etapas acima.
O iOS Simulator é executado em um Mac build host, mesmo se você estiver usando o remoto de iOS
Simulator para Windows. Solicitações de rede pelo simulador terá o IP de estação de trabalho na rede local
como o nome do host (neste exemplo tem 192.168.1.143 , mas seu endereço IP real provavelmente será
diferente). Isso é por isso que você criou a associação do IIS Express para esse nome de host nas etapas
acima.
Verifique se o SoapUrl propriedade no Constants.cs arquivo no projeto TodoWCF (portátil) têm valores
que estão corretos para sua rede:

public static string SoapUrl


{
get
{
var defaultUrl = "http://localhost:49393/TodoService.svc";

if (Device.RuntimePlatform == Device.Android)
{
defaultUrl = "http://10.0.2.2:49393/TodoService.svc";
}
else if (Device.RuntimePlatform == Device.iOS)
{
defaultUrl = "http://192.168.1.143:49393/TodoService.svc";
}

return defaultUrl;
}
}

Depois de configurar o Constants.cs com pontos de extremidade apropriados, você deve ser capaz de
conectar-se para o TodoWCFService em execução em sua estação de trabalho do Windows 10 de
dispositivos físicos ou virtuais.

Links relacionados
TodoWCF (amostra)
Como: Criar um cliente do Windows Communication Foundation
Ferramenta de utilitário de metadados ServiceModel (svcutil.exe)
Consumir um serviço Web RESTful
12/04/2019 • 15 minutes to read

baixar o exemplo
Integrar um serviço web em um aplicativo é um cenário comum. Este artigo demonstra como consumir um
serviço web RESTful em um aplicativo xamarin. Forms.
REST Representational State Transfer () é um estilo de arquitetura para a criação de serviços da web. Solicitações
REST são feitas por HTTP, usando os mesmos verbos HTTP que navegadores da web usam para recuperar as
páginas da web e para enviar dados para servidores. Os verbos são:
OBTER – esta operação é usada para recuperar dados do serviço web.
POST – esta operação é usada para criar um novo item de dados no serviço web.
COLOCAR – esta operação é usada para atualizar um item de dados no serviço web.
PATCH – esta operação é usada para atualizar um item de dados no serviço web, descrevendo um conjunto de
instruções sobre como o item deve ser modificado. Esse verbo não é usado no aplicativo de exemplo.
Excluir – esta operação é usada para excluir um item de dados no serviço web.
APIs que aderem ao restante do serviço da Web são chamados de APIs RESTful e são definidos usando:
Um URI de base.
Métodos HTTP, como GET, POST, PUT, PATCH ou DELETE.
Um tipo de mídia para os dados, como o objeto notação JSON (JavaScript).
Serviços web rESTful normalmente usam mensagens JSON para retornar dados ao cliente. JSON é um formato
de troca de dados baseado em texto que gera conteúdos de compact, que resulta em reduzida requisitos de
largura de banda ao enviar dados. O aplicativo de exemplo usa o software livre biblioteca NewtonSoft JSON.NET
para serializar e desserializar mensagens.
A simplicidade do REST ajudou a torná-lo o principal método para acessar os serviços da web em aplicativos
móveis.
Quando o aplicativo de exemplo é executado, ele se conecte a um serviço REST hospedado localmente, conforme
mostrado na seguinte captura de tela:
NOTE
No iOS 9 e superior, a segurança de transporte de aplicativo (ATS) impõe conexões seguras entre recursos da internet (como
o servidor de back-end do aplicativo) e o aplicativo, impedindo assim a divulgação acidental de informações confidenciais.
Desde que o ATS é habilitado por padrão em aplicativos criados para o iOS 9, todas as conexões serão sujeitos a requisitos
de segurança ATS. Se as conexões não atender a esses requisitos, eles falharão com uma exceção.
ATS poderá ser aceito de se ele não é possível usar o HTTPS de protocolo e proteger a comunicação para recursos da
internet. Isso pode ser feito atualizando o aplicativo Info. plist arquivo. Para obter mais informações, consulte segurança de
transporte de aplicativo.

Consumir o serviço Web


O serviço REST é gravado usando o ASP.NET Core e fornece as seguintes operações:

OPERAÇÃO MÉTODO HTTP URI RELATIVO PARÂMETROS

Obter uma lista de itens OBTER / API/todoitems /


pendentes

Criar um novo item POSTAR / API/todoitems / Um JSON formatado


pendente TodoItem

Atualizar um item pendente PUT / API/todoitems / Um JSON formatado


TodoItem

Excluir um item pendente DELETE /api/todoitems/{id}

A maioria dos URIs inclui o ID no caminho. Por exemplo, para excluir o TodoItem cuja ID é
TodoItem
6bb8a868-dba1-4f1a-93b7-24ebce87e243 , o cliente envia uma solicitação de exclusão
http://hostname/api/todoitems/6bb8a868-dba1-4f1a-93b7-24ebce87e243 . Para obter mais informações sobre o
modelo de dados usado no aplicativo de exemplo, consulte modelagem de dados.
Quando a estrutura da API Web recebe uma solicitação, ele encaminha a solicitação para uma ação. Essas ações
são simplesmente público em métodos de TodoItemsController classe. A estrutura usa uma tabela de roteamento
para determinar qual ação a ser invocada em resposta a uma solicitação, que é mostrada no exemplo de código a
seguir:

config.Routes.MapHttpRoute(
name: "TodoItemsApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { controller="todoitems", id = RouteParameter.Optional }
);

A tabela de roteamento contém um modelo de rota e quando a estrutura da API Web recebe uma solicitação
HTTP, ele tenta corresponder o URI em relação ao modelo de rota na tabela de roteamento. Se uma
correspondência de rota não foi encontrada que o cliente recebe um erro de 404 (não encontrado). Se uma rota
correspondente for encontrada, API da Web selecionará o controlador e a ação da seguinte maneira:
Para localizar o controlador, API da Web adiciona "controller" como o valor da {controlador } variável.
Para localizar a ação, a API Web examina o método HTTP e examina a ações do controlador são decoradas
com o mesmo método HTTP como um atributo.
O {id } variável de espaço reservado é mapeado para um parâmetro de ação.
O serviço REST usa autenticação básica. Para obter mais informações, consulte autenticar um serviço web
RESTful. Para obter mais informações sobre o roteamento do ASP.NET Web API, consulte roteamento na API
Web ASP.NET no site do ASP.NET. Para obter mais informações sobre como criar o serviço REST usando o
ASP.NET Core, consulte criação de serviços de back-end para aplicativos móveis nativos.
O HttpClient classe é usada para enviar e receber solicitações via HTTP. Ele fornece funcionalidade para enviar
solicitações HTTP e receber respostas HTTP de um URI identificou o recurso. Cada solicitação é enviada como
uma operação assíncrona. Para obter mais informações sobre as operações assíncronas, consulte visão geral do
suporte assíncrono.
O HttpResponseMessage classe representa uma mensagem de resposta HTTP recebida do serviço da web depois
que foi feita uma solicitação HTTP. Ele contém informações sobre a resposta, incluindo o código de status,
cabeçalhos e qualquer corpo. O HttpContent classe representa o corpo de HTTP e cabeçalhos de conteúdo, como
Content-Type e Content-Encoding . O conteúdo pode ser lido usando qualquer um dos ReadAs métodos, tais
como ReadAsStringAsync e ReadAsByteArrayAsync , dependendo do formato dos dados.
Criando o objeto HTTPClient
O HttpClient instância é declarada no nível de classe, de modo que o objeto reside para desde que o aplicativo
precisa fazer solicitações HTTP, conforme mostrado no exemplo de código a seguir:

public class RestService : IRestService


{
HttpClient _client;
...

public RestService ()
{
_client = new HttpClient ();
}
...
}

Recuperando dados
O HttpClient.GetAsync método é usado para enviar a solicitação GET para o serviço web especificado pelo URI e,
em seguida, receber a resposta do serviço da web, conforme mostrado no exemplo de código a seguir:
public async Task<List<TodoItem>> RefreshDataAsync ()
{
...
var uri = new Uri (string.Format (Constants.TodoItemsUrl, string.Empty));
...
var response = await _client.GetAsync (uri);
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync ();
Items = JsonConvert.DeserializeObject <List<TodoItem>> (content);
}
...
}

O serviço REST envia um código de status HTTP no HttpResponseMessage.IsSuccessStatusCode propriedade para


indicar se a solicitação HTTP foi bem-sucedida ou falhou. Para esta operação restante serviço envia o código de
status HTTP 200 (Okey) na resposta, que indica se a solicitação foi bem-sucedida e que as informações solicitadas
estão na resposta.
Se a operação HTTP foi bem-sucedida, o conteúdo da resposta é lido, para exibição. O
HttpResponseMessage.Content propriedade representa o conteúdo da resposta HTTP e o
HttpContent.ReadAsStringAsync método grava de forma assíncrona o conteúdo HTTP em uma cadeia de
caracteres. Este conteúdo é então convertido de JSON para um List de TodoItem instâncias.
Criação de dados
O HttpClient.PostAsync método é usado para enviar a solicitação POST para o serviço web especificado pelo URI
e, em seguida, para receber a resposta do serviço da web, conforme mostrado no exemplo de código a seguir:

public async Task SaveTodoItemAsync (TodoItem item, bool isNewItem = false)


{
var uri = new Uri (string.Format (Constants.TodoItemsUrl, string.Empty));

...
var json = JsonConvert.SerializeObject (item);
var content = new StringContent (json, Encoding.UTF8, "application/json");

HttpResponseMessage response = null;


if (isNewItem)
{
response = await _client.PostAsync (uri, content);
}
...

if (response.IsSuccessStatusCode)
{
Debug.WriteLine (@"\tTodoItem successfully saved.");

}
...
}

O TodoItem instância é convertida em uma carga JSON para enviar para o serviço web. Essa carga, em seguida, é
inserida no corpo do conteúdo HTTP que será enviado ao serviço web antes que a solicitação é feita com o
PostAsync método.

O serviço REST envia um código de status HTTP no HttpResponseMessage.IsSuccessStatusCode propriedade para


indicar se a solicitação HTTP foi bem-sucedida ou falhou. As respostas comuns para essa operação são:
201 (criado) – a solicitação resultou em um novo recurso que está sendo criado antes que a resposta foi
enviada.
400 (solicitação incorreta) – a solicitação não é entendida pelo servidor.
409 (conflito) – a solicitação não pôde ser realizada devido a um conflito no servidor.
Atualizando dados
O HttpClient.PutAsync método é usado para enviar a solicitação PUT para o serviço web especificado pelo URI e,
em seguida, receber a resposta do serviço da web, conforme mostrado no exemplo de código a seguir:

public async Task SaveTodoItemAsync (TodoItem item, bool isNewItem = false)


{
...
response = await _client.PutAsync (uri, content);
...
}

A operação do PutAsync método é idêntico de PostAsync método que é usado para a criação de dados no serviço
web. No entanto, as respostas possíveis enviadas do serviço web são diferentes.
O serviço REST envia um código de status HTTP no HttpResponseMessage.IsSuccessStatusCode propriedade para
indicar se a solicitação HTTP foi bem-sucedida ou falhou. As respostas comuns para essa operação são:
204 (sem conteúdo) – a solicitação foi processada com êxito e a resposta está intencionalmente em branco.
400 (solicitação incorreta) – a solicitação não é entendida pelo servidor.
404 (não encontrado) – o recurso solicitado não existe no servidor.
Excluindo dados
O HttpClient.DeleteAsync método é usado para enviar a solicitação de exclusão para o serviço web especificado
pelo URI e, em seguida, receber a resposta do serviço da web, conforme mostrado no exemplo de código a seguir:

public async Task DeleteTodoItemAsync (string id)


{
var uri = new Uri (string.Format (Constants.TodoItemsUrl, id));
...
var response = await _client.DeleteAsync (uri);
if (response.IsSuccessStatusCode)
{
Debug.WriteLine (@"\tTodoItem successfully deleted.");
}
...
}

O serviço REST envia um código de status HTTP no HttpResponseMessage.IsSuccessStatusCode propriedade para


indicar se a solicitação HTTP foi bem-sucedida ou falhou. As respostas comuns para essa operação são:
204 (sem conteúdo) – a solicitação foi processada com êxito e a resposta está intencionalmente em branco.
400 (solicitação incorreta) – a solicitação não é entendida pelo servidor.
404 (não encontrado) – o recurso solicitado não existe no servidor.

Links relacionados
Criando Serviços de Back-end para Aplicativos Móveis Nativos
TodoREST (amostra)
HttpClient
Consumir um aplicativo móvel do Azure
12/04/2019 • 10 minutes to read

baixar o exemplo
Aplicativos móveis do Azure permitem que você desenvolva aplicativos com back-ends dimensionável
hospedado no serviço de aplicativo do Azure com suporte para autenticação móvel, sincronização offline e
notificações por push. Neste artigo, que só é aplicável aos aplicativos móveis do Azure que usam um back-end
do Node. js, explica como consultar, inserir, atualizar e excluir os dados armazenados em uma tabela em uma
instância de aplicativos móveis do Azure.

NOTE
Iniciando em 30 de junho, todos os novos aplicativos de móveis do Azure serão criados com o TLS 1.2 por padrão. Além
disso, também é recomendado que os aplicativos móveis do Azure ser reconfigurados para usar o TLS 1.2. Para obter
informações sobre como impor o TLS 1.2 no aplicativo móvel do Azure, consulte versões impor o TLS. Para obter
informações sobre como configurar projetos do Xamarin para usar TLS 1.2, consulte Transport Layer Security (TLS) 1.2.

Para obter informações sobre como criar uma instância de aplicativos móveis do Azure que pode ser consumida
por xamarin. Forms, consulte criar um aplicativo xamarin. Forms. Depois de seguir essas instruções, o aplicativo
de exemplo para download pode ser configurado para consumir a instância de aplicativos móveis do Azure,
definindo o Constants.ApplicationURL para a URL da instância de aplicativos móveis do Azure. Em seguida,
quando o aplicativo de exemplo for executado ele se conecte à instância de aplicativos móveis do Azure,
conforme mostrado na seguinte captura de tela:
Acesso a aplicativos móveis do Azure é por meio de SDK do Azure Mobile Client, e todas as conexões do
aplicativo de exemplo do xamarin. Forms para o Azure são feitas por HTTPS.

NOTE
No iOS 9 e superior, a segurança de transporte de aplicativo (ATS) impõe conexões seguras entre recursos da internet
(como o servidor de back-end do aplicativo) e o aplicativo, impedindo assim a divulgação acidental de informações
confidenciais. Desde que o ATS é habilitado por padrão em aplicativos criados para o iOS 9, todas as conexões serão
sujeitos a requisitos de segurança ATS. Se as conexões não atender a esses requisitos, eles falharão com uma exceção. ATS
poderá ser aceito de se ele não é possível usar o HTTPS de protocolo e proteger a comunicação para recursos da internet.
Isso pode ser feito atualizando o aplicativo Info. plist arquivo. Para obter mais informações, consulte segurança de
transporte de aplicativo.

Consumindo uma instância de aplicativo móvel do Azure


O SDK do Azure Mobile Client fornece o MobileServiceClient classe, que é usado por um aplicativo xamarin.
Forms para acessar a instância de aplicativos móveis do Azure, conforme mostrado no exemplo de código a
seguir:

IMobileServiceTable<TodoItem> todoTable;
MobileServiceClient client;

public TodoItemManager ()
{
client = new MobileServiceClient (Constants.ApplicationURL);
todoTable = client.GetTable<TodoItem> ();
}

Quando o MobileServiceClient instância é criada, uma URL de aplicativo deve ser especificada para identificar a
instância de aplicativos móveis do Azure. Esse valor pode ser obtido a partir do painel para o aplicativo móvel na
Portal do Microsoft Azure.
Uma referência para o TodoItem tabela armazenada na instância de aplicativos móveis do Azure deve ser obtida
antes de operações podem ser executadas nessa tabela. Isso é feito chamando o GetTable método em de
MobileServiceClient da instância, que retorna um IMobileServiceTable<TodoItem> referência.

Consultar Dados
O conteúdo de uma tabela pode ser recuperado chamando o IMobileServiceTable.ToEnumerableAsync método que
avalia a consulta e retorna os resultados de forma assíncrona. Dados também podem ser filtradas do lado do
servidor, incluindo um Where cláusula na consulta. O Where cláusula aplica um predicado à consulta na tabela, a
filtragem de linha conforme mostrado no exemplo de código a seguir:

public async Task<ObservableCollection<TodoItem>> GetTodoItemsAsync (bool syncItems = false)


{
...
IEnumerable<TodoItem> items = await todoTable
.Where (todoItem => !todoItem.Done)
.ToEnumerableAsync ();

return new ObservableCollection<TodoItem> (items);


}

Esta consulta retorna todos os itens do TodoItem tabela cujos Done propriedade é igual a false . Os resultados
da consulta, em seguida, são colocados em um ObservableCollection para exibição.
Inserindo dados
Ao inserir dados na instância de aplicativos móveis do Azure, novas colunas serão geradas automaticamente na
tabela conforme necessário, fornecido o esquema dinâmico está habilitado na instância de aplicativos móveis do
Azure. O IMobileServiceTable.InsertAsync método é usado para inserir uma nova linha de dados na tabela
especificada, conforme mostrado no exemplo de código a seguir:

public async Task SaveTaskAsync (TodoItem item)


{
...
await todoTable.InsertAsync (item);
...
}

Quando você faz uma solicitação de inserção, uma ID não deve ser especificada nos dados que está sendo
passados para a instância de aplicativos móveis do Azure. Se a solicitação de inserção contém uma ID de um
MobileServiceInvalidOperationException será lançada.

Após o InsertAsync método for concluído, a ID dos dados na instância de aplicativos móveis do Azure será
preenchida na TodoItem instância no aplicativo xamarin. Forms.
Atualizando dados
Ao atualizar dados na instância de aplicativos móveis do Azure, novas colunas serão geradas automaticamente
na tabela conforme necessário, fornecido o esquema dinâmico está habilitado na instância de aplicativos móveis
do Azure. O IMobileServiceTable.UpdateAsync método é usado para atualizar os dados existentes com novas
informações, conforme mostrado no exemplo de código a seguir:

public async Task SaveTaskAsync (TodoItem item)


{
...
await todoTable.UpdateAsync (item);
...
}

Quando você faz uma solicitação de atualização, uma ID deve ser especificada para que a instância de aplicativos
móveis do Azure possa identificar os dados a serem atualizados. Esse valor de ID é armazenado no TodoItem.ID
propriedade. Se a solicitação de atualização não contém uma ID não é possível para a instância de aplicativos
móveis do Azure determinar os dados a ser atualizado e, portanto, um MobileServiceInvalidOperationException
será lançada.
Excluindo dados
O IMobileServiceTable.DeleteAsync método é usado para excluir dados de uma tabela de aplicativos móveis do
Azure, conforme mostrado no exemplo de código a seguir:

public async Task DeleteTaskAsync (TodoItem item)


{
...
await todoTable.DeleteAsync(item);
...
}

Quando você faz uma solicitação de exclusão, uma ID deve ser especificada para que o aplicativo móvel do Azure
sinstance possa identificar os dados a ser excluído. Esse valor de ID é armazenado no TodoItem.ID propriedade.
Se a solicitação de exclusão não contém uma ID, não há nenhuma maneira para a instância de aplicativos móveis
do Azure determinar os dados a serem excluídos e, portanto, um MobileServiceInvalidOperationException será
lançada.
Resumo
Este artigo explicou como usar o SDK do Azure Mobile Client para consultar, inserir, atualizar e excluir os dados
armazenados em uma tabela em uma instância de aplicativos móveis do Azure. O SDK fornece o
MobileServiceClient classe que é usado por um aplicativo xamarin. Forms para acessar a instância de aplicativos
móveis do Azure.

Links relacionados
TodoAzure (amostra)
Criar um aplicativo xamarin. Forms
SDK de cliente móvel do Azure
MobileServiceClient
Autenticando o acesso a serviços Web
12/04/2019 • 3 minutes to read

Este guia explica como integrar serviços de autenticação em um aplicativo xamarin. Forms para permitir que os
usuários compartilham um back-end tendo apenas o acesso a seus próprios dados. Os tópicos abordados incluem
o uso de autenticação básica com um serviço REST usando o componente Xamarin.Auth para autenticar em
relação a provedores de identidade OAuth, e usar os mecanismos de autenticação internos oferecidos pelos
provedores diferentes.

Autenticar um serviço Web RESTful


HTTP oferece suporte ao uso de vários mecanismos de autenticação para controlar o acesso aos recursos.
Autenticação básica oferece acesso aos recursos somente a clientes que possuem as credenciais corretas. Este
artigo demonstra como usar a autenticação básica para proteger o acesso aos recursos de serviço web RESTful.

Autenticação de usuários com um provedor de identidade


Xamarin.Auth é um SDK de plataforma cruzada para autenticar usuários e armazenar suas contas. Ele inclui
autenticadores de OAuth que oferecem suporte para o consumo de provedores de identidade, como Google,
Microsoft, Facebook e Twitter. Este artigo explica como usar Xamarin.Auth para gerenciar o processo de
autenticação em um aplicativo xamarin. Forms.

Autenticação de usuários com aplicativos móveis do Azure


Aplicativos móveis do Azure usam uma variedade de provedores de identidade externa para dar suporte a
autenticação e autorização de usuários do aplicativo. Em seguida, podem ser definidas permissões nas tabelas para
restringir o acesso somente para usuários autenticados. Este artigo explica como usar os aplicativos móveis do
Azure para gerenciar o processo de autenticação em um aplicativo xamarin. Forms.

Autenticação de usuários com o Azure Active Directory B2C


B2C de diretório ativo do Azure é uma solução de gerenciamento de identidade de nuvem para aplicativos web
voltado ao consumidor e móveis. Este artigo demonstra como usar a biblioteca de autenticação da Microsoft
(MSAL ) e o Azure Active Directory B2C para integrar o gerenciamento de identidades de consumidor em um
aplicativo xamarin. Forms.

Integração do Azure Active Directory B2C com Aplicativos Móveis do


Azure
B2C de diretório ativo do Azure pode ser usado para gerenciar o fluxo de trabalho de autenticação para aplicativos
móveis do Azure. Com essa abordagem, a experiência de gerenciamento de identidade está totalmente definida na
nuvem e pode ser modificada sem alterar o código do aplicativo móvel. Este artigo demonstra como usar o Azure
Active Directory B2C para fornecer autenticação e autorização para uma instância de aplicativos do Azure Mobile
xamarin. Forms.

Links relacionados
Introdução aos serviços Web
Visão geral do suporte assíncrono
Autenticar um serviço Web RESTful
12/04/2019 • 6 minutes to read

HTTP oferece suporte ao uso de vários mecanismos de autenticação para controlar o acesso aos recursos.
Autenticação básica oferece acesso a recursos somente a clientes que possuem as credenciais corretas. Este artigo
demonstra como usar a autenticação básica para proteger o acesso aos recursos do serviço web RESTful.

NOTE
No iOS 9 e superior, a segurança de transporte de aplicativo (ATS) impõe conexões seguras entre recursos da internet (como
o servidor de back-end do aplicativo) e o aplicativo, impedindo assim a divulgação acidental de informações confidenciais.
Desde que o ATS é habilitado por padrão em aplicativos criados para o iOS 9, todas as conexões serão sujeitos a requisitos
de segurança ATS. Se as conexões não atender a esses requisitos, eles falharão com uma exceção. ATS poderá ser aceito de
se ele não é possível usar o HTTPS de protocolo e proteger a comunicação para recursos da internet. Isso pode ser feito
atualizando o aplicativo Info. plist arquivo. Para obter mais informações, consulte segurança de transporte de aplicativo.

Autenticar usuários via HTTP


Autenticação básica é o mecanismo de autenticação mais simples compatível com HTTP e envolve o cliente que
envia o nome de usuário e a senha como texto não criptografado codificado na base64. Ele funciona da seguinte
maneira:
Se um serviço web recebe uma solicitação para um recurso protegido, ele rejeita a solicitação com um código
de status HTTP 401 (acesso negado) e define o cabeçalho de resposta WWW -Authenticate, conforme
mostrado no diagrama a seguir:

Se um serviço web recebe uma solicitação para um recurso protegido, com o Authorization cabeçalho
definido corretamente, o web serviço responde com um código de status HTTP 200, que indica se a solicitação
foi bem-sucedida e que as informações solicitadas estão na resposta. Este cenário é mostrado no diagrama a
seguir:

NOTE
Autenticação básica deve ser usada apenas ao longo de uma conexão HTTPS. Quando usado em uma conexão HTTP, o
Authorization cabeçalho pode ser decodificado com facilidade se o tráfego HTTP é capturado por um invasor.
Especificar a autenticação básica em uma solicitação da Web
Uso da autenticação básica é especificado da seguinte maneira:
1. A cadeia de caracteres "Básico" é adicionado para o Authorization cabeçalho da solicitação.
2. O nome de usuário e senha são combinados em uma cadeia de caracteres com o formato "nomedeusuario:
senha", que é, em seguida, na Base 64 codificados e adicionado ao Authorization cabeçalho da solicitação.
Portanto, com um nome de usuário de 'XamarinUser' e uma senha de 'XamarinPassword', o cabeçalho se torna:

Authorization: Basic WGFtYXJpblVzZXI6WGFtYXJpblBhc3N3b3Jk

O HttpClient classe pode definir o valor do cabeçalho no


Authorization
HttpClient.DefaultRequestHeaders.Authorization propriedade. Porque o HttpClient instância existe em várias
solicitações, o Authorization cabeçalho só precisa ser definida uma vez, em vez de quando fazer cada solicitação,
conforme mostrado no exemplo de código a seguir:

public class RestService : IRestService


{
HttpClient _client;
...

public RestService ()
{
var authData = string.Format ("{0}:{1}", Constants.Username, Constants.Password);
var authHeaderValue = Convert.ToBase64String (Encoding.UTF8.GetBytes (authData));

_client = new HttpClient ();


_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue ("Basic", authHeaderValue);
}
...
}

Em seguida, quando é feita uma solicitação para uma operação de serviço da web a solicitação é assinada com o
Authorization cabeçalho, que indica se o usuário tem permissão para invocar a operação.

NOTE
Embora esse código armazena as credenciais como constantes, eles não devem ser armazenados em um formato inseguro
em um aplicativo publicado. O Xamarith.Auth NuGet fornece funcionalidade para armazenar com segurança as credenciais.
Para obter mais informações, consulte armazenando e recuperando informações da conta em dispositivos.

Processamento do lado do servidor de cabeçalho de autorização


O serviço REST deve decorar cada ação com o [BasicAuthentication] atributo. Esse atributo é usado para
analisar a Authorization cabeçalho e determinar se as credenciais de codificada em base64 são válidas,
comparando-os com base nos valores armazenados no Web. config. Embora essa abordagem é adequada para
um serviço de exemplo, ele requer a extensão para um serviço da web voltados ao público.
O módulo de autenticação básica usada pelo IIS, os usuários são autenticados em relação às suas credenciais do
Windows. Portanto, os usuários devem ter contas de domínio do servidor. No entanto, o modelo de autenticação
básica pode ser configurado para permitir a autenticação personalizada, em que as contas de usuário são
autenticadas em relação a uma fonte externa, como um banco de dados. Para obter mais informações, consulte
autenticação básica na API Web ASP.NET no site do ASP.NET.
NOTE
Autenticação básica não foi projetada para gerenciar o log de. Portanto, é a abordagem de autenticação básica padrão para
fazer logoff encerrar a sessão.

Links relacionados
Consumir um serviço web RESTful
HttpClient
Autenticar usuários com um provedor de identidade
12/04/2019 • 25 minutes to read

baixar o exemplo
AUTH é um SDK de plataforma cruzada para autenticar usuários e armazenar suas contas. Ele inclui os
autenticadores de OAuth que oferecem suporte para o consumo de provedores de identidade, como Google,
Microsoft, Facebook e Twitter. Este artigo explica como usar auth para gerenciar o processo de autenticação em
um aplicativo xamarin. Forms.
OAuth é um padrão aberto para autenticação e permite que o proprietário do recurso notificar um provedor de
recursos que a permissão deve ser concedida a um terceiro para acessar suas informações sem compartilhar a
identidade de proprietários de recurso. Um exemplo disso seria ser habilitação de um usuário notificar um
provedor de identidade (por exemplo, Google, Microsoft, Facebook ou Twitter) que deve ser concedida permissão
a um aplicativo para acessar seus dados, sem compartilhar a identidade do usuário. Normalmente, ele é usado
como uma abordagem para que os usuários para entrar para sites e aplicativos usando um provedor de
identidade, mas sem expor sua senha para o site ou aplicativo.
Uma visão geral do fluxo de autenticação durante o consumo de um provedor de identidade OAuth é da seguinte
maneira:
1. O aplicativo navega de um navegador para uma URL do provedor de identidade.
2. O provedor de identidade lida com a autenticação de usuário e retorna um código de autorização para o
aplicativo.
3. O aplicativo troca o código de autorização para um token de acesso do provedor de identidade.
4. O aplicativo usa o token de acesso para acessar as APIs no provedor de identidade, como uma API para
solicitar dados básicos do usuário.
O aplicativo de exemplo demonstra como usar auth para implementar um fluxo de autenticação nativa no Google.
Enquanto o Google é usado como o provedor de identidade neste tópico, a abordagem é igualmente aplicável a
outros provedores de identidade. Para obter mais informações sobre autenticação usando o ponto de extremidade
do Google OAuth 2.0, consulte OAuth2.0 usando APIs do Google acesso no site do Google.

NOTE
No iOS 9 e superior, a segurança de transporte de aplicativo (ATS) impõe conexões seguras entre recursos da internet (como
o servidor de back-end do aplicativo) e o aplicativo, impedindo assim a divulgação acidental de informações confidenciais.
Desde que o ATS é habilitado por padrão em aplicativos criados para o iOS 9, todas as conexões serão sujeitos a requisitos
de segurança ATS. Se as conexões não atender a esses requisitos, eles falharão com uma exceção. ATS poderá ser aceito de
se ele não é possível usar o HTTPS de protocolo e proteger a comunicação para recursos da internet. Isso pode ser feito
atualizando o aplicativo Info. plist arquivo. Para obter mais informações, consulte segurança de transporte de aplicativo.

Usando auth para autenticar usuários


AUTH dá suporte a duas abordagens para os aplicativos interagem com o ponto de extremidade de autorização
do provedor de identidade:
1. Usando uma exibição da web incorporadas. Embora isso tenha sido uma prática comum, ele não é mais
recomendado pelos seguintes motivos:
O aplicativo que hospeda a exibição da web pode acessar a credencial do usuário autenticação
completa, não apenas a concessão de autorização do OAuth foi destinada para o aplicativo. Isso viola o
princípio de privilégios mínimos, que o aplicativo tenha acesso a credenciais mais poderosas do que o
necessário, possivelmente, aumentando a superfície de ataque do aplicativo.
O aplicativo host pode capturar os nomes de usuário e senhas, automaticamente enviar formulários e
ignorar o consentimento do usuário e copiar os cookies de sessão e usá-los para executar ações
autenticadas como o usuário.
Modos de exibição da web incorporadas não compartilham o estado de autenticação com outros
aplicativos ou navegador da web do dispositivo, exigir que o usuário entrar para cada solicitação de
autorização que é considerada uma experiência de usuário de qualidade inferior.
Alguns pontos de extremidade de autorização tomar medidas para detectar e bloquear solicitações de
autorização que vêm de exibições da web.
2. Usando o navegador da web do dispositivo, que é a abordagem recomendada. Usar o navegador do
dispositivo para solicitações do OAuth melhora a usabilidade de um aplicativo, como os usuários precisam
apenas entrar para o provedor de identidade uma vez por dispositivo, melhorando as taxas de conversão
de fluxos de entrada e autorização no aplicativo. O navegador do dispositivo também fornece segurança
aprimorada como os aplicativos capazes de inspecionar e modificar o conteúdo em uma exibição da web,
mas não os conteúdo exibido no navegador. Isso é a abordagem usada neste artigo e exemplo de
aplicativo.
Uma visão geral de como o aplicativo de exemplo usa auth para autenticar usuários e recuperar seus dados
básicos é mostrada no diagrama a seguir:

O aplicativo faz uma solicitação de autenticação usando o Google o OAuth2Authenticator classe. Uma resposta de
autenticação é retornada, depois que o usuário foi autenticado com êxito com o Google por meio de sua página
de entrada, que inclui um token de acesso. O aplicativo, em seguida, faz uma solicitação para o Google para dados
de usuário básico, usando o OAuth2Request classe, com o token de acesso que está sendo incluído na solicitação.
Configuração
Um projeto de Console de API do Google deve ser criado para integrar o logon do Google com um aplicativo
xamarin. Forms. Isso pode ser feito da seguinte maneira:
1. Vá para o Console de API do Google site e entre com as credenciais de conta do Google.
2. Do projeto lista suspensa, selecione um projeto existente ou crie um novo.
3. Na barra lateral em "Gerenciador de API", selecione credenciais, em seguida, selecione o guia de tela de
consentimento de OAuth. Escolha uma endereço de Email, especifique um nome do produto mostrado
aos usuáriose pressione salvar.
4. No credenciais guia, selecione o criar credenciais lista suspensa lista e escolha ID do cliente OAuth.
5. Sob tipo de aplicativo, selecione a plataforma que serão executados no aplicativo móvel (iOS ou Android).
6. Preencha os detalhes necessários e selecione o criar botão.

NOTE
Uma ID de cliente permite que um aplicativo acessar Google APIs habilitadas e para aplicativos móveis é exclusiva para uma
única plataforma. Portanto, uma ID do cliente OAuth deve ser criado para cada plataforma que usarão logon do Google.
Depois de executar essas etapas, AUTH pode ser usado para iniciar um fluxo de autenticação OAuth2 com o
Google.
Criando e configurando um autenticador
Do AUTH OAuth2Authenticator classe é responsável por gerenciar o fluxo de autenticação OAuth. O exemplo de
código a seguir mostra a instanciação do OAuth2Authenticator classe ao executar a autenticação usando o
navegador da web do dispositivo:

var authenticator = new OAuth2Authenticator(


clientId,
null,
Constants.Scope,
new Uri(Constants.AuthorizeUrl),
new Uri(redirectUri),
new Uri(Constants.AccessTokenUrl),
null,
true);

O OAuth2Authenticator classe requer um número de parâmetros, que são da seguinte maneira:


ID do cliente – Isso identifica o cliente que está fazendo a solicitação e pode ser recuperado do projeto na
Console de API do Google.
Segredo do cliente – isso deve ser null ou string.Empty .
Escopo – Isso identifica o acesso de API que está sendo solicitado pelo aplicativo e o valor informa à tela de
consentimento é mostrada ao usuário. Para obter mais informações sobre escopos, consulte solicitação de API
autorizando no site do Google.
Autorizar URL – Isso identifica a URL em que o código de autorização será obtido do.
URL de redirecionamento – Isso identifica a URL em que a resposta será enviada. O valor desse parâmetro
deve corresponder a um dos valores que aparecem na credenciais guia para o projeto na Console de
desenvolvedores do Google.
Url de AccessToken – Isso identifica a URL usada para solicitar tokens de acesso depois que um código de
autorização é obtido.
GetUserNameAsync Func – um opcional Func que será usado para recuperar o nome da conta de usuário
depois que ele é foi autenticado com êxito.
Use a interface do usuário nativa – um boolean valor que indica se deve usar o navegador da web do
dispositivo para executar a solicitação de autenticação.
Configurar manipuladores de eventos de autenticação
Antes de apresentar a interface do usuário, um manipulador de eventos para o OAuth2Authenticator.Completed
evento deve ser registrado, conforme mostrado no exemplo de código a seguir:

authenticator.Completed += OnAuthCompleted;

Esse evento será acionado quando o usuário é autenticado com êxito ou cancela na entrada.
Opcionalmente, um manipulador de eventos para o OAuth2Authenticator.Error eventos também podem ser
registrados.
Apresentando a Interface do usuário de entrada
A interface do usuário de entrada pode ser apresentada ao usuário por meio de um apresentador de logon AUTH,
que deve ser inicializado em cada projeto de plataforma. O exemplo de código a seguir mostra como inicializar
um apresentador de logon na AppDelegate classe no projeto do iOS:
global::Xamarin.Auth.Presenters.XamarinIOS.AuthenticationConfiguration.Init();

O exemplo de código a seguir mostra como inicializar um apresentador de logon na MainActivity classe no
projeto do Android:

global::Xamarin.Auth.Presenters.XamarinAndroid.AuthenticationConfiguration.Init(this, bundle);

O projeto de biblioteca .NET Standard pode, em seguida, invoque o apresentador de logon da seguinte maneira:

var presenter = new Xamarin.Auth.Presenters.OAuthLoginPresenter();


presenter.Login(authenticator);

Observe que o argumento para o Xamarin.Auth.Presenters.OAuthLoginPresenter.Login método é o


OAuth2Authenticator instância. Quando o Login método é invocado, a interface do usuário de entrada é
apresentada ao usuário em uma guia do navegador da web do dispositivo, que é mostrado nas capturas de tela
seguir:

Processar a URL de redirecionamento


Depois que o usuário concluir o processo de autenticação, controle retornará para o aplicativo da guia do
navegador da web. Isso é feito registrando um esquema de URL personalizado para a URL de redirecionamento
que é retornada para o processo de autenticação e, em seguida, detectar e manipular a URL personalizada quando
ele é enviado.
Ao escolher um esquema de URL personalizado a ser associado a um aplicativo, os aplicativos devem usar um
esquema com base em um nome de seu controle. Isso pode ser feito usando o nome do identificador de pacote
no iOS e o nome do pacote no Android e, em seguida, revertendo-las para tornar o esquema de URL. No entanto,
alguns provedores de identidade, como Google, atribua os identificadores de cliente com base em nomes de
domínio, que, em seguida, são revertidos e usados como o esquema de URL. Por exemplo, se o Google cria uma
id do cliente do 902730282010-ks3kd03ksoasioda93jldas93jjj22kr.apps.googleusercontent.com , o esquema de URL
será com.googleusercontent.apps.902730282010-ks3kd03ksoasioda93jldas93jjj22kr . Observe que somente um único
/ pode aparecer após o componente de esquema. Portanto, é um exemplo completo de uma URL de
redirecionamento utilizando um esquema de URL personalizado
com.googleusercontent.apps.902730282010-ks3kd03ksoasioda93jldas93jjj22kr:/oauth2redirect .

Quando o navegador da web recebe uma resposta do provedor de identidade que contém um esquema de URL
personalizado, ele tenta carregar a URL, que falhará. Em vez disso, o esquema de URL personalizado é relatado
para o sistema operacional, gerando um evento. O sistema operacional, em seguida, verifica para esquemas
registradas e, caso seja encontrado, o sistema operacional inicie o aplicativo que registrou o esquema e enviá-lo a
URL de redirecionamento.
O mecanismo para registrar um esquema de URL personalizado com o sistema operacional e lidar com o
esquema é específico para cada plataforma.
iOS
No iOS, um esquema de URL personalizado é registrado no Info. plist, conforme mostrado na seguinte captura
de tela:

O identificador valor pode ser qualquer coisa e o função valor deve ser definido como visualizador. O
esquemas de Url valor, que começa com com.googleusercontent.apps , pode ser obtido da id do cliente iOS para o
projeto no Console de API do Google.
Quando o provedor de identidade conclui a solicitação de autorização, ele redireciona para a URL de
redirecionamento do aplicativo. Como a URL usa um esquema personalizado, ele resulta na inicialização do
aplicativo do iOS, passando a URL como um parâmetro de inicialização, onde ela é processada pelo OpenUrl
substituir da caixa de diálogo AppDelegate classe, que é mostrado no exemplo de código a seguir:

public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options)


{
// Convert NSUrl to Uri
var uri = new Uri(url.AbsoluteString);

// Load redirectUrl page


AuthenticationState.Authenticator.OnPageLoading(uri);

return true;
}

O OpenUrl método converte a URL recebida de um NSUrl para um .NET Uri , antes de processar a URL de
redirecionamento com o OnPageLoading método de um público OAuth2Authenticator objeto. Isso faz com que
auth para fechar a guia do navegador da web e analisar os dados recebidos do OAuth.
Android
No Android, um esquema de URL personalizado está registrado com a especificação de um IntentFilter
atributo o Activity que irá manipular o esquema. Quando o provedor de identidade conclui a solicitação de
autorização, ele redireciona para a URL de redirecionamento do aplicativo. Como a URL usa um esquema
personalizado, ele resulta na inicialização do aplicativo do Android, passando a URL como um parâmetro de
inicialização, onde ela é processada pelo OnCreate método da Activity registrado para manipular o esquema de
URL personalizado. O exemplo de código a seguir mostra a classe do aplicativo de exemplo que manipula o
esquema de URL personalizado:

[Activity(Label = "CustomUrlSchemeInterceptorActivity", NoHistory = true, LaunchMode = LaunchMode.SingleTop )]


[IntentFilter(
new[] { Intent.ActionView },
Categories = new [] { Intent.CategoryDefault, Intent.CategoryBrowsable },
DataSchemes = new [] { "<insert custom URL here>" },
DataPath = "/oauth2redirect")]
public class CustomUrlSchemeInterceptorActivity : Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);

// Convert Android.Net.Url to Uri


var uri = new Uri(Intent.Data.ToString());

// Load redirectUrl page


AuthenticationState.Authenticator.OnPageLoading(uri);

Finish();
}
}

O DataSchemes propriedade do IntentFilter deve ser definido como o identificador de cliente invertido é obtido
da id do cliente Android para o projeto no Console de API do Google.
O OnCreate método converte a URL recebida de um Android.Net.Url para um .NET Uri , antes de processar a
URL de redirecionamento com o OnPageLoading método de um público OAuth2Authenticator objeto. Isso faz com
que AUTH fechar a guia do navegador da web e analisar os dados recebidos do OAuth.

IMPORTANT
No Android, AUTH usa a CustomTabs API para se comunicar com o navegador da web e o sistema operacional. No
entanto, ele terá assegurado que não um CustomTabs navegador compatível será instalado no dispositivo do usuário.

Examinar a resposta do OAuth


Depois de analisar os dados recebidos do OAuth, AUTH irá gerar o OAuth2Authenticator.Completed eventos. No
manipulador de eventos para esse evento, o AuthenticatorCompletedEventArgs.IsAuthenticated propriedade pode
ser usada para identificar se a autenticação foi bem-sucedida, conforme mostrado no exemplo de código a seguir:
async void OnAuthCompleted(object sender, AuthenticatorCompletedEventArgs e)
{
...
if (e.IsAuthenticated)
{
...
}
}

Os dados coletados de uma autenticação bem-sucedida estão disponíveis no


AuthenticatorCompletedEventArgs.Account propriedade. Isso inclui um token de acesso, que pode ser usado para
assinar as solicitações de dados para uma API fornecida pelo provedor de identidade.
Fazer solicitações para dados
Depois que o aplicativo obtém um token de acesso, ele é usado para fazer uma solicitação para o
https://www.googleapis.com/oauth2/v2/userinfo API para solicitar dados de usuário básico do provedor de
identidade. Essa solicitação é feita do AUTH OAuth2Request classe, que representa uma solicitação que é
autenticada usando uma conta recuperada de um OAuth2Authenticator da instância, conforme mostrado no
exemplo de código a seguir:

// UserInfoUrl = https://www.googleapis.com/oauth2/v2/userinfo
var request = new OAuth2Request ("GET", new Uri (Constants.UserInfoUrl), null, e.Account);
var response = await request.GetResponseAsync ();
if (response != null)
{
string userJson = response.GetResponseText ();
var user = JsonConvert.DeserializeObject<User> (userJson);
}

Bem como o método HTTP e a URL da API, o OAuth2Request também especifica uma instância de um Account
instância que contém o token de acesso que faz a solicitação para a URL especificada pelo Constants.UserInfoUrl
propriedade. O provedor de identidade, em seguida, retorna dados básicos do usuário como uma resposta JSON,
incluindo o nome dos usuários e o endereço de email, desde que ele reconhece o token de acesso como válido. A
resposta JSON, em seguida, é lida e desserializada para o user variável.
Para obter mais informações, consulte chamar uma API do Google no portal de desenvolvedores do Google.
Armazenar e recuperar informações de conta em dispositivos
AUTH armazena com segurança Account objetos em uma conta de repositório para que os aplicativos nem
sempre têm a autenticar novamente os usuários. O AccountStore classe é responsável por armazenar
informações de conta e é apoiada por serviços de conjunto de chaves no iOS e o KeyStore classe no Android.
O seguinte exemplo de código mostra como um Account objeto é salvo com segurança:

AccountStore.Create ().Save (e.Account, Constants.AppName);

Contas salvas são identificadas exclusivamente usando uma chave composta da conta de Username propriedade e
uma ID de serviço, que é uma cadeia de caracteres que é usada ao buscar contas do repositório de conta. Se um
Account foi salvo anteriormente, chamar o Save método novamente irá substituí-la.

Account objetos para um serviço pode ser recuperado chamando o FindAccountsForService método, conforme
mostrado no exemplo de código a seguir:

var account = AccountStore.Create ().FindAccountsForService (Constants.AppName).FirstOrDefault();


O FindAccountsForService método retorna um IEnumerable coleção de Account objetos, com o primeiro item na
coleção que está sendo definido como a conta correspondente.

Resumo
Este artigo explicou como usar auth para gerenciar o processo de autenticação em um aplicativo xamarin. Forms.
AUTH fornece o OAuth2Authenticator e OAuth2Request classes que são usadas por aplicativos do xamarin. Forms
para consumir provedores de identidade, como Google, Microsoft, Facebook e Twitter.

Links relacionados
OAuthNativeFlow (amostra)
OAuth 2.0 para aplicativos nativos
Usando o OAuth 2.0 para acessar as APIs do Google
AUTH (NuGet)
AUTH (GitHub)
Autenticar usuários com aplicativos móveis do Azure
12/04/2019 • 12 minutes to read

baixar o exemplo
Aplicativos móveis do Azure usam uma variedade de provedores de identidade externos para dar suporte à
autenticação e autorização de usuários do aplicativo, incluindo o Facebook, Google, Microsoft, Twitter e Active
Directory do Azure. Permissões podem ser definidas em tabelas para restringir o acesso somente aos usuários
autenticados. Este artigo explica como usar aplicativos móveis do Azure para gerenciar o processo de
autenticação em um aplicativo xamarin. Forms.

Visão geral
O processo de ter os aplicativos móveis do Azure a gerenciar o processo de autenticação em um aplicativo
xamarin. Forms é da seguinte maneira:
1. Registrar seu aplicativo móvel do Azure no site do provedor de identidade e, em seguida, defina as credenciais
geradas pelo provedor no back-end dos aplicativos móveis. Para obter mais informações, consulte registrar
seu aplicativo para autenticação e configurar serviços de aplicativos.
2. Defina um novo esquema de URL para seu aplicativo xamarin. Forms, que permite que o sistema de
autenticação redirecionar de volta para o aplicativo xamarin. Forms depois que o processo de autenticação for
concluído. Para obter mais informações, consulte adicionar seu aplicativo para a permissão URLs de
redirecionamento externo.
3. Restringir o acesso para o back-end de aplicativos móveis do Azure para somente aos clientes autenticados.
Para obter mais informações, consulte restringir permissões a usuários autenticados.
4. Invocar a autenticação do aplicativo xamarin. Forms. Para obter mais informações, consulte adicionar
autenticação à biblioteca de classes portátil, adicionar autenticação ao aplicativo do iOS, adicionar autenticação
ao aplicativo do Androide Adicionar autenticação a projetos de aplicativo do Windows 10.

NOTE
No iOS 9 e superior, a segurança de transporte de aplicativo (ATS) impõe conexões seguras entre recursos da internet (como
o servidor de back-end do aplicativo) e o aplicativo, impedindo assim a divulgação acidental de informações confidenciais.
Desde que o ATS é habilitado por padrão em aplicativos criados para o iOS 9, todas as conexões serão sujeitos a requisitos
de segurança ATS. Se as conexões não atender a esses requisitos, eles falharão com uma exceção. ATS poderá ser aceito de
se ele não é possível usar o HTTPS de protocolo e proteger a comunicação para recursos da internet. Isso pode ser feito
atualizando o aplicativo Info. plist arquivo. Para obter mais informações, consulte segurança de transporte de aplicativo.

Historicamente, os aplicativos móveis usou modos de exibição da web incorporadas para realizar a autenticação
com o provedor de identidade. Isso não é mais recomendável pelos seguintes motivos:
O aplicativo que hospeda a exibição da web pode acessar a credencial do usuário autenticação completa, não
apenas a concessão de autorização foi destinada para o aplicativo. Isso viola o princípio de privilégios
mínimos, que o aplicativo tenha acesso a credenciais mais poderosas do que o necessário, possivelmente,
aumentando a superfície de ataque do aplicativo.
O aplicativo host pode capturar os nomes de usuário e senhas, automaticamente enviar formulários e ignorar
o consentimento do usuário e copiar os cookies de sessão e usá-los para executar ações autenticadas como o
usuário.
Modos de exibição da web incorporadas não compartilham o estado de autenticação com outros aplicativos
ou navegador da web do dispositivo, exigir que o usuário entrar para cada solicitação de autorização que é
considerada uma experiência de usuário de qualidade inferior.
Alguns pontos de extremidade de autorização tomar medidas para detectar e bloquear solicitações de
autorização que vêm de exibições da web.
A alternativa é usar o navegador da web do dispositivo para realizar a autenticação, que é a abordagem usada
pela versão mais recente do SDK do Azure Mobile Client. Usando o navegador do dispositivo para as solicitações
de autenticação melhora a usabilidade de um aplicativo, como os usuários precisam apenas entrar para o
provedor de identidade uma vez por dispositivo, melhorando as taxas de conversão de fluxos de entrada e
autorização no aplicativo. O navegador do dispositivo também fornece segurança aprimorada como os
aplicativos capazes de inspecionar e modificar o conteúdo em uma exibição da web, mas não os conteúdo exibido
no navegador.

Usando uma instância de aplicativos móveis do Azure


O SDK do Azure Mobile Client fornece o MobileServiceClient classe, que é usado por um aplicativo xamarin.
Forms para acessar a instância de aplicativos móveis do Azure.
O aplicativo de exemplo usa o Google como provedor de identidade, que permite que os usuários com contas do
Google para fazer logon no aplicativo xamarin. Forms. Enquanto o Google é usado como o provedor de
identidade neste artigo, a abordagem é igualmente aplicável a outros provedores de identidade.
Fazer logon de usuários
A tela de logon no aplicativo de exemplo é mostrada nas capturas de tela seguir:

Enquanto o Google é usado como o provedor de identidade, uma variedade de outros provedores de identidade
pode ser usada, incluindo a Microsoft, Facebook, Twitter e Active Directory do Azure.
O exemplo de código a seguir mostra como o processo de logon é invocado:

async void OnLoginButtonClicked(object sender, EventArgs e)


{
...
if (App.Authenticator != null)
{
authenticated = await App.Authenticator.AuthenticateAsync();
}
...
}
O App.Authenticator propriedade é um IAuthenticate instância que é definida por cada projeto específico da
plataforma. O IAuthenticate interface especifica um AuthenticateAsync operação que deve ser fornecida por
cada projeto da plataforma. Por isso, invocar o App.Authenticator.AuthenticateAsync método executa o
IAuthenticate.AuthenticateAsync método em um projeto de plataforma.

Todas a plataforma IAuthenticate.AuthenticateAsync chamada de métodos de MobileServiceClient.LoginAsync


método para exibir dados de interface e o cache de um logon. O seguinte exemplo de código mostra o
LoginAsync método para a plataforma iOS:

public async Task<bool> AuthenticateAsync()


{
...
// The authentication provider could also be Facebook, Twitter, or Microsoft
user = await TodoItemManager.DefaultManager.CurrentClient.LoginAsync(
UIApplication.SharedApplication.KeyWindow.RootViewController,
MobileServiceAuthenticationProvider.Google,
Constants.URLScheme);
...
}

O seguinte exemplo de código mostra o LoginAsync método para a plataforma Android:

public async Task<bool> AuthenticateAsync()


{
...
// The authentication provider could also be Facebook, Twitter, or Microsoft
user = await TodoItemManager.DefaultManager.CurrentClient.LoginAsync(
this,
MobileServiceAuthenticationProvider.Google,
Constants.URLScheme);
...
}

O seguinte exemplo de código mostra o LoginAsync método para a plataforma Universal do Windows:

public async Task<bool> AuthenticateAsync()


{
...
// The authentication provider could also be Facebook, Twitter, or Microsoft
user = await TodoItemManager.DefaultManager.CurrentClient.LoginAsync(
MobileServiceAuthenticationProvider.Google,
Constants.URLScheme);
...
}

Em todas as plataformas, o MobileServiceAuthenticationProvider enumeração é usada para especificar o provedor


de identidade que será usado no processo de autenticação. Quando o MobileServiceClient.LoginAsync método é
invocado, aplicativos móveis do Azure inicia um fluxo de autenticação, exibindo a página de logon do provedor
selecionado e gerando um token de autenticação após um logon bem-sucedido com o provedor de identidade. O
MobileServiceClient.LoginAsync método retorna um MobileServiceUser que será armazenada na instância a
MobileServiceClient.CurrentUser propriedade. Esta propriedade fornece UserId e
MobileServiceAuthenticationToken propriedades. Elas representam o usuário autenticado e um token de
autenticação para o usuário. O token de autenticação será incluído em todas as solicitações feitas para a instância
de aplicativos móveis do Azure, permitindo que o aplicativo xamarin. Forms executar ações na instância do
aplicativo móvel do Azure que exigem permissões de usuário autenticado.
Fazer logoff de usuários
O exemplo de código a seguir mostra como o processo de logoff é invocado:

async void OnLogoutButtonClicked(object sender, EventArgs e)


{
bool loggedOut = false;

if (App.Authenticator != null)
{
loggedOut = await App.Authenticator.LogoutAsync ();
}
...
}

O App.Authenticator propriedade é um IAuthenticate instância que é definida por cada platformproject. O


IAuthenticate interface especifica um LogoutAsync operação que deve ser fornecida por cada projeto da
plataforma. Por isso, invocar o App.Authenticator.LogoutAsync método executa o IAuthenticate.LogoutAsync
método em um projeto de plataforma.
Todas a plataforma IAuthenticate.LogoutAsync chamada de métodos de MobileServiceClient.LogoutAsync método
desprovisionar autenticar o usuário fez logon com o provedor de identidade. O seguinte exemplo de código
mostra o LogoutAsync método para a plataforma iOS:

public async Task<bool> LogoutAsync()


{
...
foreach (var cookie in NSHttpCookieStorage.SharedStorage.Cookies)
{
NSHttpCookieStorage.SharedStorage.DeleteCookie (cookie);
}
await TodoItemManager.DefaultManager.CurrentClient.LogoutAsync();
...
}

O seguinte exemplo de código mostra o LogoutAsync método para a plataforma Android:

public async Task<bool> LogoutAsync()


{
...
CookieManager.Instance.RemoveAllCookie();
await TodoItemManager.DefaultManager.CurrentClient.LogoutAsync();
...
}

O seguinte exemplo de código mostra o LogoutAsync método para a plataforma Universal do Windows:

public async Task<bool> LogoutAsync()


{
...
await TodoItemManager.DefaultManager.CurrentClient.LogoutAsync();
...
}

Quando o IAuthenticate.LogoutAsync método é invocado, os cookies definidos pelo provedor de identidade


estiverem desmarcados, antes de MobileServiceClient.LogoutAsync método é invocado para desprovisionar
autenticar o usuário fez logon com o provedor de identidade.

Resumo
Este artigo explicou como usar aplicativos móveis do Azure para gerenciar o processo de autenticação em um
aplicativo xamarin. Forms. Aplicativos móveis do Azure usam uma variedade de provedores de identidade
externos para dar suporte à autenticação e autorização de usuários do aplicativo, incluindo o Facebook, Google,
Microsoft, Twitter e Active Directory do Azure. O MobileServiceClient classe é usada pelo aplicativo xamarin.
Forms para controlar o acesso à instância de aplicativos móveis do Azure.

Links relacionados
TodoAzureAuth (amostra)
Consumir um aplicativo móvel do Azure
Adicionar autenticação ao aplicativo xamarin. Forms
SDK de cliente móvel do Azure
MobileServiceClient
Autenticar usuários com o Azure Active Directory
B2C
12/04/2019 • 16 minutes to read

baixar o exemplo
Azure Active Directory B2C do diretório é uma solução de gerenciamento de identidade de nuvem para
aplicativos móveis e web voltados ao consumidor. Este artigo demonstra como usar a biblioteca de autenticação
da Microsoft e o Azure Active Directory B2C para integrar o gerenciamento de identidade do consumidor em um
aplicativo móvel.

NOTE
O biblioteca de autenticação da Microsoft ainda está em visualização, mas é adequado para uso em um ambiente de
produção. No entanto, há podem ser alterações significativas para a API, formato de cache interno e outros mecanismos
para a biblioteca, que podem afetar seu aplicativo.

Visão geral
Azure Active Directory B2C do diretório é um serviço de gerenciamento de identidade para aplicativos voltados
ao consumidor, que permite que os consumidores entrar no seu aplicativo por:
Usando suas contas sociais existentes (Microsoft, Google, Facebook, Amazon, LinkedIn).
Criando novas credenciais (endereço de email e senha, ou nome de usuário e senha). Essas credenciais são
denominadas local contas.
O processo para integrar o serviço de gerenciamento de identidade do Azure Active Directory B2C em um
aplicativo móvel é da seguinte maneira:
1. Crie um locatário do Azure Active Directory B2C. Para obter mais informações, consulte criar um locatário do
Azure Active Directory B2C no portal do Azure.
2. Registre seu aplicativo móvel com o locatário do Azure Active Directory B2C. O processo de registro atribui
uma ID do aplicativo que identifica exclusivamente o seu aplicativo e um URL de redirecionamento que
pode ser usado para direcionar as respostas de volta ao seu aplicativo. Para obter mais informações, consulte
Azure Active Directory B2C: registrar seu aplicativo.
3. Crie uma política de inscrição e entrada. Essa política definirá as experiências pelas quais os consumidores
passarão durante a inscrição e entrada e também especifica o conteúdo dos tokens que o aplicativo receberá
bem-sucedido inscrever-se ou entrar. Para obter mais informações, consulte Azure Active Directory B2C:
políticas internas.
4. Use o biblioteca de autenticação da Microsoft (MSAL ) em seu aplicativo móvel para iniciar um fluxo de
trabalho de autenticação com seu locatário do Azure Active Directory B2C.
NOTE
Bem como integrar o gerenciamento de identidades do Azure Active Directory B2C em aplicativos móveis, a MSAL também
pode ser usada para integrar o gerenciamento de identidade do Active Directory do Azure em aplicativos móveis. Isso pode
ser feito ao registrar um aplicativo móvel com o Azure Active Directory na Portal de registro de aplicativo. O processo de
registro atribui uma ID do aplicativo que identifica exclusivamente o seu aplicativo, que deve ser especificado ao usar a
MSAL. Para obter mais informações, consulte como registrar um aplicativo com o ponto de extremidade v 2.0, e autenticar
seu Mobile Apps usando biblioteca de autenticação Microsoft no blog do Xamarin.

MSAL usa um navegador da web do dispositivo para realizar a autenticação. Isso melhora a usabilidade de um
aplicativo, como os usuários precisam apenas entrar depois por dispositivo, melhorar as taxas de conversão de
entrada e autorização fluxos no aplicativo. O navegador do dispositivo também fornece segurança aprimorada.
Depois que o usuário concluir o processo de autenticação, controle retornará para o aplicativo da guia do
navegador da web. Isso é feito registrando um esquema de URL personalizado para a URL de redirecionamento
que é retornada para o processo de autenticação e, em seguida, detectar e manipular a URL personalizada
quando ele é enviado. Para obter mais informações sobre como escolher um esquema de URL personalizado,
consulte escolhendo um URI de redirecionamento do aplicativo nativo.

NOTE
O mecanismo para registrar um esquema de URL personalizado com o sistema operacional e lidar com o esquema é
específico para cada plataforma.

Cada solicitação é enviada a um locatário do Azure Active Directory B2C Especifica uma diretiva. As políticas
descrevem experiências de identidade do consumidor, como inscrição ou entrada. Por exemplo, uma política de
inscrição permite que o comportamento do locatário do Azure Active Directory B2C para ser configurado por
meio das seguintes configurações:
Tipos de conta que os consumidores podem usar para entrar no aplicativo.
Dados a serem coletados junto ao consumidor durante a inscrição.
A autenticação multifator.
Conteúdo da página de inscrição.
Declarações de token que o aplicativo móvel recebe quando a política foi executada.
Um locatário do Azure Active Directory pode conter várias políticas de tipos diferentes, que podem ser usados
em seu aplicativo conforme necessário. Além disso, as políticas podem ser reutilizadas em aplicativos, permitindo
que você definir e modificar experiências de identidade do consumidor sem alterar seu código. Para obter mais
informações sobre políticas, consulte Azure Active Directory B2C: políticas internas.

Configuração
A biblioteca do NuGet da biblioteca de autenticação da Microsoft (MSAL ) deve ser adicionada ao projeto de
biblioteca de classe portátil (PCL ) e projetos de plataforma em uma solução do xamarin. Forms. As seções a
seguir fornecem instruções de configuração adicionais para usar MSAL para se comunicar com um locatário do
Azure Active Directory B2C em um aplicativo móvel.
Biblioteca de Classes Portátil
PCLs que consomem MSAL precisará ser redirecionados para usar Profile7. Para obter mais informações sobre
PCLs, consulte Introduction to Portable Class Libraries (Introdução às bibliotecas de classes portáteis).
iOS
No iOS, o esquema de URL personalizado que foi registrado com o Azure Active Directory B2C deve ser
registrado no Info. plist, conforme mostrado na seguinte captura de tela:
Quando o Azure Active Directory B2C conclui a solicitação de autorização, ele redireciona para a URL de
redirecionamento registrado. Como a URL usa um esquema personalizado, ele resulta na inicialização do
aplicativo móvel do iOS, passando a URL como um parâmetro de inicialização, onde ela é processada pelo
OpenUrl substituir da caixa de diálogo AppDelegate classe, que é mostrado no código a seguir exemplo:

using Microsoft.Identity.Client;

namespace TodoAzure.iOS
{
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
...
public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options)
{
AuthenticationContinuationHelper.SetAuthenticationContinuationEventArgs(url);
return true;
}
}
}

O código a OpenURL método garante que o controle retorna para a MSAL depois que a parte interativa do fluxo
de trabalho de autenticação terminou.
Android
No Android, o esquema de URL personalizado que foi registrado com o Azure Active Directory B2C deve ser
registrado no androidmanifest. XML, com a adição de uma <activity> elemento dentro de existente
<application> elemento. O <activity> elemento Especifica a IntentFilter sobre o Activity que lida com o
esquema e é mostrado no exemplo a seguir:

<application ...>
<activity android:name="microsoft.identity.client.BrowserTabActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="INSERT_URL_SCHEME_HERE" android:host="auth" />
</intent-filter>
</activity>
</application>

Quando o Azure Active Directory B2C conclui a solicitação de autorização, ele redireciona para a URL de
redirecionamento registrado. Como a URL usa um esquema personalizado, ele resulta na inicialização do
aplicativo móvel do Android, passando a URL como um parâmetro de inicialização, onde ela é processada pelo
microsoft.identity.client.BrowserTabActivity . Observe que o data android:scheme propriedade deve ser
definida para o esquema de URL personalizado que está registrado com o aplicativo do Azure Active Directory
B2C.
Além disso, o MainActivity classe deve ser modificada, conforme mostrado no exemplo de código a seguir:
using Microsoft.Identity.Client;

namespace TodoAzure.Droid
{
...
public class MainActivity : FormsAppCompatActivity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);

global::Xamarin.Forms.Forms.Init(this, bundle);
Microsoft.WindowsAzure.MobileServices.CurrentPlatform.Init();
LoadApplication(new App());
App.UiParent = new UIParent(this);
}

protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)


{
base.OnActivityResult(requestCode, resultCode, data);
AuthenticationContinuationHelper.SetAuthenticationContinuationEventArgs(requestCode, resultCode,
data);
}
}
}

O OnCreate método é modificado, atribuindo um UIParent da instância para o App.UiParent propriedade. Isso
garante que o fluxo de autenticação ocorre no contexto da atividade atual.
O código a OnActivityResult método garante que o controle retorna para a MSAL depois que a parte interativa
do fluxo de trabalho de autenticação terminou.
Plataforma Universal do Windows
Na plataforma Universal do Windows, nenhuma configuração adicional é necessário para usar a MSAL.

Inicialização
A biblioteca de autenticação da Microsoft usa os membros de PublicClientApplication classe iniciar um fluxo de
trabalho de autenticação. O aplicativo de exemplo declara e inicializa um public propriedade desse tipo,
chamado ADB2CClient , no AuthenticationProvider classe. O exemplo de código a seguir mostra como essa
propriedade é inicializada:

ADB2CClient = new PublicClientApplication(Constants.ClientID, Constants.Authority);

Quando o aplicativo móvel foi registrado com o locatário do Azure Active Directory B2C, o processo de registro é
atribuído um ID do aplicativo. Essa ID deve ser especificada na PublicClientApplication construtor, junto com
um Authority constante que consiste em uma URL base e a política do Azure Active Directory B2C para ser
executado.

Entrar
A tela de entrada no aplicativo de exemplo é mostrada nas capturas de tela seguir:
Entrar com provedores de identidade social, ou com uma conta local, são permitidos. Embora a Microsoft, Google
e Facebook, como mostrado acima, são usados como provedores de identidade social, outros provedores de
identidade também podem ser usados.
O exemplo de código a seguir mostra como o processo de logon é invocado:

using Microsoft.Identity.Client;

public async Task<bool> LoginAsync(bool useSilent = false)


{
...
AuthenticationResult authenticationResult = await ADB2CClient.AcquireTokenAsync(
Constants.Scopes,
GetUserByPolicy(ADB2CClient.Users, Constants.PolicySignUpSignIn),
App.UiParent);
...
}

O AcquireTokenAsync método inicia o navegador da web do dispositivo e exibe as opções de autenticação


definidas na política do Azure Active Directory B2C é especificada pela política referenciada por meio de
Constants.Authority constante. Essa política define as experiências pelas quais os consumidores passarão
durante a inscrição e entrar e as declarações que o aplicativo receberá bem-sucedido inscrever-se ou entrar.
O resultado do AcquireTokenAsync chamada de método é um AuthenticationResult instância. Se a autenticação
for bem-sucedida, o AuthenticationResult instância conterá um token de identidade, que será armazenado
localmente. Se a autenticação for bem-sucedida, o AuthenticationResult instância conterá os dados que indicam
por que a autenticação falhou.
No aplicativo de exemplo, se a autenticação for bem-sucedida, o TodoList página é navegada.
Reautenticação silenciosa
Quando o LoginPage no exemplo de aplicativo for exibido, é feita uma tentativa de recuperar um token de
usuário sem mostrar qualquer interface do usuário de autenticação. Isso é feito com o AcquireTokenSilentAsync
método, conforme demonstrado no exemplo de código a seguir:

public async Task<bool> LoginAsync(bool useSilent = false)


{
...
AuthenticationResult authenticationResult;

if (useSilent)
{
authenticationResult = await ADB2CClient.AcquireTokenSilentAsync(
Constants.Scopes,
GetUserByPolicy(ADB2CClient.Users, Constants.PolicySignUpSignIn),
Constants.Authority,
false);
}
...
}

O AcquireTokenSilentAsync método tenta recuperar um token de usuário do cache, sem exigir que o usuário
entrar. Ele lida com o cenário em que um token adequado pode já estar presente no cache de sessões anteriores.
Se a tentativa de obter um token for bem-sucedida, o TodoList página é navegada. Se a tentativa de obter um
token não for bem-sucedida, nada acontece e o usuário terá a opção para iniciar um novo fluxo de trabalho de
autenticação.

Sair
O exemplo de código a seguir mostra como o processo de saída é invocado:

public async Task<bool> LogoutAsync()


{
...
foreach (var user in ADB2CClient.Users)
{
ADB2CClient.Remove(user);
}
...
}

Isso limpa todos os tokens de autenticação do cache local.

Resumo
Este artigo demonstrou como usar a biblioteca de autenticação da Microsoft (MSAL ) e o Azure Active Directory
B2C para integrar o gerenciamento de identidade do consumidor em um aplicativo móvel. Azure Active Directory
B2C do diretório é uma solução de gerenciamento de identidade de nuvem para aplicativos móveis e web
voltados ao consumidor.

Links relacionados
AzureADB2CAuth (amostra)
Azure Active Directory B2C
Biblioteca de autenticação da Microsoft
A integração do Azure Active Directory B2C com
aplicativos móveis do Azure
12/04/2019 • 19 minutes to read

baixar o exemplo
Azure Active Directory B2C do diretório é uma solução de gerenciamento de identidade de nuvem para
aplicativos móveis e web voltados ao consumidor. Este artigo demonstra como usar o Azure Active Directory B2C
para fornecer autenticação e autorização para uma instância de aplicativos móveis do Azure com o xamarin.
Forms.

NOTE
O biblioteca de autenticação da Microsoft ainda está em visualização, mas é adequado para uso em um ambiente de
produção. No entanto, há podem ser alterações significativas para a API, formato de cache interno e outros mecanismos para
a biblioteca, que podem afetar seu aplicativo.

Visão geral
Aplicativos móveis do Azure permitem que você desenvolva aplicativos com o back-ends dimensionável
hospedado no serviço de aplicativo do Azure com suporte para autenticação móvel, sincronização offline e
notificações por push. Para obter mais informações sobre aplicativos móveis do Azure, consulte consumir o
aplicativo móvel do Azure, e autenticando usuários com aplicativos móveis do Azure.
Azure Active Directory B2C do diretório é um serviço de gerenciamento de identidade para aplicativos voltados ao
consumidor, que permite que os consumidores entrar no seu aplicativo por:
Usando suas contas sociais existentes (Microsoft, Google, Facebook, Amazon, LinkedIn).
Criando novas credenciais (endereço de email e senha, ou nome de usuário e senha). Essas credenciais são
denominadas local contas.
Para obter mais informações sobre o Azure Active Directory B2C, consulte autenticando usuários com o Azure
Active Directory B2C.
Azure Active Directory B2C do diretório pode ser usado para gerenciar o fluxo de trabalho de autenticação para o
aplicativo móvel do Azure. Com essa abordagem, a experiência de gerenciamento de identidade está totalmente
definida na nuvem e pode ser modificada sem alterar o código do aplicativo móvel.
Há dois fluxos de trabalho de autenticação que podem ser adotados ao integrar um locatário do Azure Active
Directory B2C com uma instância de aplicativos móveis do Azure:
Cliente gerenciado – desta abordagem o iniciará o aplicativo móvel do xamarin. Forms o processo de
autenticação com o locatário do Azure Active Directory B2C e passa o token de autenticação recebidas para a
instância de aplicativos móveis do Azure.
Servidor gerenciado – nessa abordagem, os aplicativos móveis do Azure a instância usa o locatário do Azure
Active Directory B2C para iniciar o processo de autenticação por meio de um fluxo de trabalho baseado na web.
Em ambos os casos, a experiência de autenticação é fornecida pelo locatário do Azure Active Directory B2C. No
aplicativo de exemplo, isso resulta na tela de logon mostrada nas capturas de tela seguir:

Entrar com provedores de identidade social, ou com uma conta local, são permitidos. Embora o Facebook, Google
e Microsoft são usados como provedores de identidade social, neste exemplo, outros provedores de identidade
também podem ser usados.

Configuração
Independentemente do fluxo de trabalho de autenticação usado, o processo inicial para a integração de um
locatário do Azure Active Directory B2C com uma instância de aplicativos móveis do Azure é o seguinte:
1. Crie uma instância de aplicativos móveis do Azure. Para obter mais informações, consulte consumir o aplicativo
móvel do Azure.
2. Habilite a autenticação na instância de aplicativos móveis do Azure e o aplicativo xamarin. Forms. Para obter
mais informações, consulte autenticando usuários com aplicativos móveis do Azure.
3. Crie um locatário do Azure Active Directory B2C. Para obter mais informações, consulte autenticando usuários
com o Azure Active Directory B2C.
Observe que a biblioteca de autenticação Microsoft (MSAL ) é necessária ao usar um fluxo de trabalho de
autenticação gerenciada pelo cliente. MSAL usa um navegador da web do dispositivo para realizar a autenticação.
Isso melhora a usabilidade de um aplicativo, como os usuários precisam apenas entrar depois por dispositivo,
melhorar as taxas de conversão de entrada e autorização fluxos no aplicativo. O navegador do dispositivo também
fornece segurança aprimorada. Depois que o usuário concluir o processo de autenticação, controle retornará para
o aplicativo da guia do navegador da web. Isso é feito registrando um esquema de URL personalizado para a URL
de redirecionamento que é retornada para o processo de autenticação e, em seguida, detectar e manipular a URL
personalizada quando ele é enviado. Para obter mais informações sobre como usar MSAL para se comunicar com
um locatário do Azure Active Directory B2C, consulte autenticando usuários com o Azure Active Directory B2C.
Autenticação gerenciada pelo cliente
Na autenticação gerenciada pelo cliente, um aplicativo móvel do xamarin. Forms entra em contato com um
locatário do Azure Active Directory B2C para iniciar um fluxo de autenticação. Após o logon bem-sucedido o B2C
do Azure Active Directory locatário retorna um token de identidade que é fornecido durante a entrada para a
instância de aplicativos móveis do Azure. Isso permite que o aplicativo xamarin. Forms executar ações na instância
de aplicativos móveis do Azure que requer permissões de usuário autenticado.
Configuração de locatário do Azure Active Directory B2C
Um fluxo de trabalho de autenticação gerenciada pelo cliente, o locatário B2C do Azure Active Directory deve ser
configurado da seguinte maneira:
Inclua um cliente nativo.
Defina o URI de redirecionamento personalizado a um esquema de URL que identifica exclusivamente o
aplicativo móvel, seguido por ://auth/ . Para obter mais informações sobre como escolher um esquema de
URL personalizado, consulte escolhendo um URI de redirecionamento do aplicativo nativo.
Captura de tela a seguir demonstra essa configuração:

A política usada no Azure Active Directory B2C locatário também deve ser configurado para que a URL de
resposta é definida como o mesmo esquema de URL personalizado, seguido por ://auth/ . Captura de tela a
seguir demonstra essa configuração:
Configuração de aplicativo móvel do Azure
Um fluxo de trabalho de autenticação gerenciada pelo cliente, a instância de aplicativos móveis do Azure deve ser
configurada da seguinte maneira:
Autenticação do serviço de aplicativo deve ser ativada.
A ação a ser tomada quando uma solicitação for autenticada não deve ser definida como faça logon com o
Azure Active Directory.
Captura de tela a seguir demonstra essa configuração:

A instância de aplicativos móveis do Azure também deve ser configurada para se comunicar com o locatário do
Azure Active Directory B2C. Isso pode ser feito habilitando Advanced modo para o provedor de autenticação do
Active Directory do Azure, com o ID do cliente sendo o ID do aplicativo do Azure Locatário do Active Directory
B2C e o Url do emissor sendo o ponto de extremidade de metadados para a política do Azure Active Directory
B2C. Captura de tela a seguir demonstra essa configuração:
Entrar
O exemplo de código a seguir mostra como iniciar um fluxo de trabalho de autenticação gerenciada pelo cliente:

public async Task<bool> LoginAsync(bool useSilent = false)


{
...
AuthenticationResult authenticationResult = await ADB2CClient.AcquireTokenAsync(
Constants.Scopes,
GetUserByPolicy(ADB2CClient.Users, Constants.PolicySignUpSignIn),
App.UiParent);

...
var payload = new JObject();
payload["access_token"] = authenticationResult.IdToken;

User = await TodoItemManager.DefaultManager.CurrentClient.LoginAsync(


MobileServiceAuthenticationProvider.WindowsAzureActiveDirectory,
payload);
...
}

A biblioteca de autenticação Microsoft (MSAL ) é usado para iniciar um fluxo de trabalho de autenticação com o
locatário do Azure Active Directory B2C. O AcquireTokenAsync método inicia o navegador da web do dispositivo e
exibe as opções de autenticação definidas na política do Azure Active Directory B2C é especificada pela política
referenciada por meio de Constants.Authority constante. Essa política define as experiências pelas quais os
consumidores passarão durante a inscrição e entrar e as declarações que o aplicativo receberá bem-sucedido
inscrever-se ou entrar.
O resultado do AcquireTokenAsync chamada de método é um AuthenticationResult instância. Se a autenticação
for bem-sucedida, o AuthenticationResult instância conterá um token de identidade, que será armazenado
localmente. Se a autenticação for bem-sucedida, o AuthenticationResult instância conterá os dados que indicam
por que a autenticação falhou. Para obter informações sobre como usar MSAL para se comunicar com um
locatário do Azure Active Directory B2C, consulte autenticando usuários com o Azure Active Directory B2C.
Quando o MobileServiceClient.LoginAsync método é invocado, a instância de aplicativos móveis do Azure recebe o
token de identidade encapsulado em um JObject . A presença de um meio de token válido que a instância de
aplicativos móveis do Azure não precisa iniciar seu próprio fluxo de autenticação OAuth 2.0. Em vez disso, o
MobileServiceClient.LoginAsync método retorna um MobileServiceUser que será armazenada na instância a
MobileServiceClient.CurrentUser propriedade. Esta propriedade fornece UserId e
MobileServiceAuthenticationToken propriedades. Elas representam o usuário autenticado e um token de
autenticação para o usuário, que pode ser usado até que ela expire. O token de autenticação será incluído em todas
as solicitações feitas para a instância de aplicativos móveis do Azure, permitindo que o aplicativo xamarin. Forms
executar ações na instância de aplicativos móveis do Azure que exigem permissões de usuário autenticado.
Sair
O exemplo de código a seguir mostra como o processo de saída gerenciada pelo cliente é invocado:

public async Task<bool> LogoutAsync()


{
...
await TodoItemManager.DefaultManager.CurrentClient.LogoutAsync();

foreach (var user in ADB2CClient.Users)


{
ADB2CClient.Remove(user);
}
...
}

O MobileServiceClient.LogoutAsync método desprovisionar autentica o usuário com a instância de aplicativos


móveis do Azure e, em seguida, todos os tokens de autenticação serão apagados do cache local criado pela MSAL.

Autenticação gerenciada pelo servidor


Na autenticação de servidor gerenciado, um aplicativo xamarin. Forms entra em contato com uma instância de
aplicativos móveis do Azure, que usa o locatário do Azure Active Directory B2C para gerenciar o fluxo de
autenticação OAuth 2.0 exibindo uma página de entrada, conforme definido na política do B2C. Após o logon
bem-sucedido, a instância de aplicativos móveis do Azure retorna um token que permite que o aplicativo xamarin.
Forms executar ações na instância de aplicativos móveis do Azure que exigem permissões de usuário autenticado.
Configuração de locatário do Azure Active Directory B2C
Um fluxo de trabalho de autenticação gerenciada pelo servidor, o locatário B2C do Azure Active Directory deve ser
configurado da seguinte maneira:
Incluir uma aplicativo de web/API web e permitir que o fluxo implícito.
Definir a URL de resposta para o endereço do aplicativo móvel do Azure, seguido por
/.auth/login/aad/callback .

Captura de tela a seguir demonstra essa configuração:


A política usada no Azure Active Directory B2C locatário também deve ser configurado para que a URL de
resposta é definida como o endereço do aplicativo móvel do Azure, seguido por /.auth/login/aad/callback .
Captura de tela a seguir demonstra essa configuração:

Configuração da instância de aplicativos móveis do Azure


Um fluxo de trabalho de autenticação gerenciada pelo servidor, a instância de aplicativos móveis do Azure deve ser
configurada da seguinte maneira:
Autenticação do serviço de aplicativo deve ser ativada.
A ação a ser tomada quando uma solicitação for autenticada não deve ser definida como faça logon com o
Azure Active Directory.
Captura de tela a seguir demonstra essa configuração:
A instância de aplicativos móveis do Azure também deve ser configurada para se comunicar com o locatário do
Azure Active Directory B2C. Isso pode ser feito habilitando Advanced modo para o provedor de autenticação do
Active Directory do Azure, com o ID do cliente sendo o ID do aplicativo do Azure Locatário do Active Directory
B2C e o Url do emissor sendo o ponto de extremidade de metadados para a política do Azure Active Directory
B2C. Captura de tela a seguir demonstra essa configuração:

Entrar
O exemplo de código a seguir mostra como iniciar um fluxo de trabalho de autenticação gerenciada pelo servidor:

public async Task<bool> AuthenticateAsync()


{
...
MobileServiceUser user = await TodoItemManager.DefaultManager.CurrentClient.LoginAsync(
UIApplication.SharedApplication.KeyWindow.RootViewController,
MobileServiceAuthenticationProvider.WindowsAzureActiveDirectory,
Constants.URLScheme);
...
}

Quando o MobileServiceClient.LoginAsync método é invocado, a instância de aplicativos móveis do Azure executa


a política do Azure Active Directory B2C vinculada, que inicia o fluxo de autenticação OAuth 2.0. Observe que cada
AuthenticateAsync método é específico da plataforma. No entanto, cada AuthenticateAsync usa o
MobileServiceClient.LoginAsync método e especifica que um locatário do Azure Active Directory será usado no
processo de autenticação. Para obter mais informações, consulte fazer logon de usuários.
O MobileServiceClient.LoginAsync método retorna um MobileServiceUser que será armazenada na instância a
MobileServiceClient.CurrentUser propriedade. Esta propriedade fornece UserId e
MobileServiceAuthenticationToken propriedades. Elas representam o usuário autenticado e um token de
autenticação para o usuário, que pode ser usado até que ela expire. O token de autenticação será incluído em todas
as solicitações feitas para a instância de aplicativos móveis do Azure, permitindo que o aplicativo xamarin. Forms
executar ações na instância de aplicativos móveis do Azure que exigem permissões de usuário autenticado.
Sair
O exemplo de código a seguir mostra como o processo de saída gerenciada por servidor é invocado:

public async Task<bool> LogoutAsync()


{
...
await TodoItemManager.DefaultManager.CurrentClient.LogoutAsync();
...
}

O MobileServiceClient.LogoutAsync método desprovisionar autentica o usuário com a instância de aplicativos


móveis do Azure. Para obter mais informações, consulte registro em log Out usuários.

Resumo
Este artigo demonstrou como usar o Azure Active Directory B2C para fornecer autenticação e autorização para
uma instância de aplicativos móveis do Azure com o xamarin. Forms. Azure Active Directory B2C do diretório é
uma solução de gerenciamento de identidade de nuvem para aplicativos móveis e web voltados ao consumidor.

Links relacionados
TodoAzureAuth ServerFlow (amostra)
TodoAzureAuth ClientFlow (amostra)
Consumir um aplicativo móvel do Azure
Autenticar usuários com aplicativos móveis do Azure
Autenticar usuários com o Azure Active Directory B2C
Biblioteca de autenticação da Microsoft
Sincronização de dados com serviços Web
12/04/2019 • 2 minutes to read

Sincronização offline permite que os usuários interagem com um aplicativo móvel, exibir, adicionar ou modificar
dados, mesmo que não tem uma conexão de rede. As alterações são armazenadas em um banco de dados local e,
depois que o dispositivo estiver online, as alterações podem ser sincronizadas com o serviço web.

Sincronização de dados Offline com aplicativos móveis do Azure


Este artigo explica como adicionar a funcionalidade de sincronização offline para um aplicativo xamarin. Forms.

Links relacionados
Introdução aos serviços Web
Visão geral do suporte assíncrono
Sincronizar dados Offline com aplicativos móveis do
Azure
12/04/2019 • 14 minutes to read

baixar o exemplo
Sincronização offline permite que os usuários interajam com um aplicativo móvel, exibindo, adicionando ou
modificando dados, mesmo que não tem uma conexão de rede. As alterações são armazenadas em um banco de
dados local e, depois que o dispositivo estiver online, as alterações podem ser sincronizadas com a instância de
aplicativos móveis do Azure. Este artigo explica como adicionar funcionalidade de sincronização offline para um
aplicativo xamarin. Forms.

Visão geral
O SDK do Azure Mobile Client fornece o IMobileServiceTable interface, que representa as operações que podem
ser executadas em tabelas armazenadas na instância de aplicativos móveis do Azure. Essas operações conectam
diretamente à instância de aplicativos móveis do Azure e falharão se o dispositivo móvel não tiver uma conexão de
rede.
Para dar suporte à sincronização offline, o SDK do Azure Mobile Client oferece suporte a tabelas de sincronização,
que são fornecidas pelo IMobileServiceSyncTable interface. Essa interface fornece o mesmo Create, Read, Update,
operações de exclusão (CRUD ) como o IMobileServiceTable interface, mas as operações de ler ou gravar em um
repositório local. O armazenamento local não é preenchido com novos dados da instância de aplicativos móveis do
Azure até que haja uma chamada para pull dados. Da mesma forma, os dados não serão enviados para a instância
de aplicativos móveis do Azure até que haja uma chamada para push alterações locais.
Sincronização offline também inclui suporte para detectar conflitos quando o mesmo registro é alterado no
repositório local e na instância de aplicativos móveis do Azure e a resolução de conflitos personalizado. Conflitos
podem ser manuseados no armazenamento local ou na instância de aplicativos móveis do Azure.
Para obter mais informações sobre a sincronização offline, consulte sincronização de dados Offline nos aplicativos
móveis do Azure e habilitar sincronização offline para seu aplicativo móvel do xamarin. Forms.

Configuração
O processo para a integração de sincronização offline entre um aplicativo xamarin. Forms e uma instância de
aplicativos móveis do Azure é da seguinte maneira:
1. Crie uma instância de aplicativos móveis do Azure. Para obter mais informações, consulte consumir o aplicativo
móvel do Azure.
2. Adicione a sqlitestore pacote do NuGet para todos os projetos na solução xamarin. Forms.
3. (Opcional) Habilite a autenticação na instância de aplicativos móveis do Azure e o aplicativo xamarin. Forms.
Para obter mais informações, consulte autenticando usuários com aplicativos móveis do Azure.
A seção a seguir fornece instruções de configuração adicionais para configurar projetos de plataforma Universal
do Windows (UWP ) para usar o pacote NuGet do sqlitestore. Nenhuma configuração adicional é necessária para
usar o pacote NuGet do sqlitestore no iOS e Android.
Plataforma Universal do Windows
Para usar o SQLite no Universal Windows Platform (UWP ), siga estas etapas:
1. Instalar o SQLite para plataforma Universal do Windows extensão do Visual Studio em seu ambiente de
desenvolvimento.
2. No projeto UWP no Visual Studio, clique com botão direito referências > Adicionar referência, navegue até
extensões e adicione o SQLite para plataforma Universal do Windows e Visual C++ 2015 Runtime para
aplicativos da plataforma Windows Universal extensões para o projeto UWP.

Inicializando o Store Local


O armazenamento local deve ser inicializado antes que qualquer operação de tabela de sincronização pode ser
executadas. Isso é feito no projeto de biblioteca de classe portátil (PCL ) da solução xamarin. Forms:

using Microsoft.WindowsAzure.MobileServices;
using Microsoft.WindowsAzure.MobileServices.SQLiteStore;
using Microsoft.WindowsAzure.MobileServices.Sync;

namespace TodoAzure
{
public partial class TodoItemManager
{
static TodoItemManager defaultInstance = new TodoItemManager();
IMobileServiceClient client;
IMobileServiceSyncTable<TodoItem> todoTable;

private TodoItemManager()
{
this.client = new MobileServiceClient(Constants.ApplicationURL);
var store = new MobileServiceSQLiteStore("localstore.db");
store.DefineTable<TodoItem>();
this.client.SyncContext.InitializeAsync(store);
this.todoTable = client.GetSyncTable<TodoItem>();
}
...
}
}

Novo banco de dados SQLite local é criado pelo MobileServiceSQLiteStore de classe, desde que ele ainda não
existir. Em seguida, o DefineTable<T> método cria uma tabela no repositório local que corresponde aos campos no
TodoItem de tipo, desde que ele ainda não existir.

Um contexto de sincronização está associado com um MobileServiceClient instância e rastreia as alterações são
feitas com tabelas de sincronização. O contexto de sincronização mantém uma fila que mantém uma lista
ordenada de operações criar, atualizar e excluir (CUD ) que será enviada para a instância de aplicativos móveis do
Azure mais tarde. O IMobileServiceSyncContext.InitializeAsync() método é usado para associar o repositório local
com o contexto de sincronização.
O todoTable campo é um IMobileServiceSyncTable , e, portanto, todas as operações de CRUD usam o
armazenamento local.

Execução da sincronização
O armazenamento local é sincronizado com o Azure Mobile Apps instância quando o SyncAsync método é
invocado:
public async Task SyncAsync()
{
ReadOnlyCollection<MobileServiceTableOperationError> syncErrors = null;

try
{
await this.client.SyncContext.PushAsync();

// The first parameter is a query name that is used internally by the client SDK to implement incremental
sync.
// Use a different query name for each unique query in your program.
await this.todoTable.PullAsync("allTodoItems", this.todoTable.CreateQuery());
}
catch (MobileServicePushFailedException exc)
{
if (exc.PushResult != null)
{
syncErrors = exc.PushResult.Errors;
}
}

// Simple error/conflict handling.


if (syncErrors != null)
{
foreach (var error in syncErrors)
{
if (error.OperationKind == MobileServiceTableOperationKind.Update && error.Result != null)
{
// Update failed, revert to server's copy
await error.CancelAndUpdateItemAsync(error.Result);
}
else
{
// Discard local change
await error.CancelAndDiscardItemAsync();
}

Debug.WriteLine(@"Error executing sync operation. Item: {0} ({1}). Operation discarded.",


error.TableName, error.Item["id"]);
}
}
}

O IMobileServiceSyncTable.PushAsync método opera no contexto de sincronização, em vez de uma tabela específica


e envia todas as alterações CUD desde o último envio por push.
Pull é executado pelo IMobileServiceSyncTable.PullAsync método em uma única tabela. O primeiro parâmetro
para o PullAsync método é um nome de consulta que é usado apenas no dispositivo móvel. Fornecendo uma
consulta não nulo os resultados de nome em que o SDK do Mobile Client do Azure que executa um sincronização
incremental, onde cada vez que uma operação de recepção retorna os resultados, a versão mais recente updatedAt
timestamp dos resultados é armazenado no local tabelas do sistema. Operações de pull subsequentes, em seguida,
recuperam somente registros após esse carimbo de hora. Como alternativa, sincronização completa pode ser feito
passando null como o nome da consulta, o que resulta em todos os registros que estão sendo recuperados em
cada operação de recepção. Após qualquer operação de sincronização, os dados recebidos são inseridos no
repositório local.

NOTE
Se um pull é executado em uma tabela que tenha atualizações locais pendentes, o pull primeiro executará um envio por push
no contexto de sincronização. Isso minimiza os conflitos entre as alterações que já estão na fila e novos dados da instância de
aplicativos móveis do Azure.
O SyncAsync método também inclui uma implementação básica para lidar com conflitos quando o mesmo
registro é alterado no repositório local e na instância de aplicativos móveis do Azure. Quando o conflito é que os
dados tiverem sido atualizados no repositório local e na instância de aplicativos móveis do Azure, o SyncAsync
método atualiza os dados no repositório local dos dados armazenados na instância de aplicativos móveis do Azure.
Quando ocorre qualquer conflito de outro, o SyncAsync método descarta a alteração local. Ele lida com o cenário
em que uma alteração local existe para os dados que foi excluídos da instância de aplicativos móveis do Azure.
Em um aplicativo de produção, os desenvolvedores devem escrever um personalizado IMobileServiceSyncHandler
implementação de manipulação de conflitos que é adequada ao seu caso de uso. Para obter mais informações,
consulte usar concorrência otimista para resolução de conflitos no portal do Azure, e aprofundando-se sobre o
suporte offline no SDK do cliente gerenciado em blogs do MSDN.

Limpando dados
Tabelas no armazenamento local podem ser apagadas de dados com o IMobileServiceSyncTable.PurgeAsync
método. Esse método dá suporte a cenários, como remover dados obsoletos que não exige um aplicativo. Por
exemplo, o aplicativo de exemplo exibe apenas TodoItem instâncias que não são concluídas. Portanto, itens
concluídos não precisam mais ser armazenados localmente. Limpar itens concluídos do repositório local pode ser
feito da seguinte maneira:

await todoTable.PurgeAsync(todoTable.Where(item => item.Done));

Uma chamada para PurgeAsync também dispara uma operação de push. Portanto, todos os itens que são
marcados como concluídos localmente serão enviados para a instância de aplicativos móveis do Azure antes de
serem removidos do repositório local. No entanto, se houver operações pendentes de sincronização com a
instância de aplicativos móveis do Azure, a limpeza lançará uma InvalidOperationException , a menos que o
force parâmetro for definido como true . Uma estratégia alternativa é examinar o
IMobileServiceSyncContext.PendingOperations propriedade, que retorna o número de operações que ainda não foi
enviado para a instância de aplicativos móveis do Azure e executar a limpeza apenas se a propriedade é zero
pendentes.

NOTE
Invocando PurgeAsync com o force parâmetro definido como true perderá todas as alterações pendentes.

Iniciando sincronização
No aplicativo de exemplo, o SyncAsync método é invocado por meio de TodoList.OnAppearing método:

protected override async void OnAppearing()


{
base.OnAppearing();

// Set syncItems to true to synchronize the data on startup when running in offline mode
await RefreshItems(true, syncItems: true);
}

Isso significa que o aplicativo tentará sincronizar com a instância de aplicativos móveis do Azure quando ele é
iniciado.
Além disso, sincronização poderá ser iniciada no iOS e Android usando o pull para atualizar a lista de dados e nas
plataformas Windows usando o sincronização botão na interface do usuário. Para obter mais informações,
consulte efetue Pull para atualizar.
Resumo
Este artigo explicou como adicionar funcionalidade de sincronização offline para um aplicativo xamarin. Forms.
Sincronização offline permite que os usuários interajam com um aplicativo móvel, exibindo, adicionando ou
modificando dados, mesmo que não tem uma conexão de rede. As alterações são armazenadas em um banco de
dados local e, depois que o dispositivo estiver online, as alterações podem ser sincronizadas com a instância de
aplicativos móveis do Azure.

Links relacionados
TodoAzureAuthOfflineSync (sample)
Consumir um aplicativo móvel do Azure
Autenticar usuários com aplicativos móveis do Azure
SDK de cliente móvel do Azure
MobileServiceClient
Enviar notificações por Push
12/04/2019 • 2 minutes to read

Uma notificação por push é usada para fornecer informações, como uma mensagem de um sistema de back-end a
um aplicativo em um dispositivo móvel para aumentar o uso e o compromisso do aplicativo. A notificação pode
ser enviada em qualquer momento, mesmo quando o usuário não está usando ativamente o aplicativo de destino.

Enviar notificações por Push de aplicativos móveis do Azure


Hubs de notificação do Azure oferecem uma infraestrutura de push escalonável para enviar notificações por push
de qualquer back-end para qualquer plataforma móvel, eliminando a complexidade de um back-end precisar se
comunicar com sistemas de notificação de plataforma diferente.
Enviar notificações por Push nos aplicativos móveis
do Azure
12/04/2019 • 25 minutes to read

baixar o exemplo
Os Hubs de notificação do Azure fornecem uma infraestrutura de envio por push escalonável para enviar
notificações por push de qualquer back-end para qualquer plataforma móvel, enquanto elimina a complexidade
de um back-end precisar se comunicar com sistemas de notificação de plataforma diferente. Este artigo explica
como usar os Hubs de notificação do Azure para enviar notificações por push de uma instância de aplicativos
móveis do Azure para um aplicativo xamarin. Forms.

Azure Push pelo Hub de notificação e o xamarin. Forms, Xamarin University


Uma notificação por push é usada para fornecer informações, como uma mensagem de um sistema de back-end a
um aplicativo em um dispositivo móvel para aumentar o uso e o contrato de aplicativo. A notificação pode ser
enviada em qualquer momento, mesmo quando o usuário não estiver usando ativamente o aplicativo de destino.
Sistemas de back-end enviam notificações por push para dispositivos móveis por meio de sistemas de notificação
de plataforma (PNS ), conforme mostrado no diagrama a seguir:

Para enviar uma notificação por push, o sistema de back-end contata o PNS específico da plataforma para enviar
uma notificação para uma instância do aplicativo cliente. Isso aumenta significativamente a complexidade de back-
end quando as notificações por push de plataforma cruzada forem necessárias, como o back-end deve usar cada
PNS API e um protocolo específico da plataforma.
Os Hubs de notificação do Azure eliminar essa complexidade, abstraindo os detalhes dos sistemas de notificação
de plataforma diferente, permitindo que uma notificação de plataforma cruzada ser enviada com uma única
chamada de API, conforme mostrado no diagrama a seguir:
Para enviar uma notificação por push, os back-end sistema apenas os contatos Azure Hub de notificação, que por
sua vez se comunica com os sistemas de notificação de plataforma diferente, portanto, diminuir a complexidade de
back-end que as notificações por push de envios de código.
Aplicativos móveis do Azure têm suporte interno para notificações por push usando hubs de notificação. O
processo para enviar uma notificação por push de uma instância de aplicativos móveis do Azure para um
aplicativo xamarin. Forms é da seguinte maneira:
1. Registra o aplicativo xamarin. Forms com o PNS, que retorna um identificador.
2. A instância de aplicativos móveis do Azure envia uma notificação ao seu Hub de notificação do Azure,
especificando o identificador do dispositivo para ser direcionado.
3. O Hub de notificação do Azure envia a notificação para o PNS apropriado para o dispositivo.
4. O PNS envia a notificação ao dispositivo especificado.
5. O aplicativo xamarin. Forms processa a notificação e o exibe.
O aplicativo de exemplo demonstra um aplicativo de lista de tarefas cujos dados são armazenados em uma
instância de aplicativos móveis do Azure. Sempre que um novo item é adicionado à instância de aplicativos móveis
do Azure, uma notificação por push seja enviada ao aplicativo xamarin. Forms. As capturas de tela a seguir
mostram a cada plataforma exibindo a notificação por push recebida:
Para obter mais informações sobre os Hubs de notificação do Azure, consulte os Hubs de notificação do Azure e
adicionar notificações de envio por push ao aplicativo xamarin. Forms.

Azure e a configuração do sistema de notificação de plataforma


O processo para a integração de um Hub de notificação do Azure em uma instância de aplicativos móveis do
Azure é da seguinte maneira:
1. Crie uma instância de aplicativos móveis do Azure. Para obter mais informações, consulte consumir o aplicativo
móvel do Azure.
2. Configure um hub de notificação. Para obter mais informações, consulte configurar um hub de notificação.
3. Atualize a instância de aplicativos móveis do Azure para enviar notificações por push. Para obter mais
informações, consulte atualizar o projeto de servidor para enviar notificações por push.
4. Registrar com cada PNS.
5. Configure o hub de notificação para se comunicar com cada PNS.
As seções a seguir fornecem instruções de configuração adicionais para cada plataforma.
iOS
As seguintes etapas adicionais devem ser executadas para usar o Apple APNS Push Notification Service () de um
Hub de notificação do Azure:
1. Gere um solicitação para o certificado de push com a ferramenta de acesso do conjunto de chaves de
assinatura de certificado. Para obter mais informações, consulte gere o arquivo de solicitação de assinatura de
certificado para o certificado push no Centro de documentação do Azure.
2. Registre o aplicativo xamarin. Forms para o suporte à notificação por push do Apple Developer Center. Para
obter mais informações, consulte registrar seu aplicativo para notificações por push no Centro de
documentação do Azure.
3. Crie um envio por push notificações habilitado perfil de provisionamento para o aplicativo xamarin. Forms no
Apple Developer Center. Para obter mais informações, consulte criar um perfil de provisionamento para o
aplicativo no Centro de documentação do Azure.
4. Configure o hub de notificação para se comunicar com o APNS. Para obter mais informações, consulte
configurar o hub de notificação para APNS.
5. Configure o aplicativo xamarin. Forms para usar a nova ID do aplicativo e o perfil de provisionamento. Para
obter mais informações, consulte Configurando o projeto iOS no Xamarin Studio ou Configurando o projeto
iOS no Visual Studio no Centro de documentação do Azure.
Android
As seguintes etapas adicionais devem ser executadas para usar o Firebase Cloud Messaging (FCM ) de um Hub de
notificação do Azure:
1. Registre-se para FCM. Uma chave de API de servidor e uma ID de cliente são automaticamente gerados e
empacotadas um google-services.json arquivo é baixado. Para obter mais informações, consulte habilitar o
Firebase Cloud Messaging (FCM ).
2. Configure o hub de notificação para se comunicar com o FCM. Para obter mais informações, consulte
configurar os aplicativos móveis volta de ponta a enviar solicitações por push usando FCM.
Plataforma Universal do Windows
As seguintes etapas adicionais devem ser executadas para usar o serviço de notificação do Windows (WNS ) de um
Hub de notificação do Azure:
1. Registre-se para o serviço de notificação do Windows (WNS ). Para obter mais informações, consulte registrar
seu aplicativo do Windows para notificações por push com WNS no Centro de documentação do Azure.
2. Configure o hub de notificação para se comunicar com o WNS. Para obter mais informações, consulte
configurar o hub de notificação para WNS no Centro de documentação do Azure.

Adicionando o suporte à notificação por Push ao aplicativo xamarin.


Forms
As seções a seguir discutem a implementação necessária em cada projeto específico da plataforma para dar
suporte a notificações por push.
iOS
O processo para implementar o suporte à notificação por push em um aplicativo iOS é da seguinte maneira:
1. Registre-se com o Apple APNS Push Notification Service () no AppDelegate.FinishedLaunching método. Para
obter mais informações, consulte Registrando com o sistema de notificação por Push da Apple.
2. Implementar o AppDelegate.RegisteredForRemoteNotifications método para manipular a resposta de registro.
Para obter mais informações, consulte manipulando a resposta de registro.
3. Implementar o AppDelegate.DidReceiveRemoteNotification método para processar as notificações por push
recebidas. Para obter mais informações, consulte processamento de notificações por Push recebidas.
Registrando com o Apple Push Notification Service
Antes de um aplicativo iOS pode receber notificações por push, deve ser registrado com o APNS Apple Push
Notification Service (), que vai gerar um token de dispositivo exclusivo e retorná-lo para o aplicativo. Registro é
invocado na FinishedLaunching substituir no AppDelegate classe:
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
...
var settings = UIUserNotificationSettings.GetSettingsForTypes(
UIUserNotificationType.Alert, new NSSet());

UIApplication.SharedApplication.RegisterUserNotificationSettings(settings);
UIApplication.SharedApplication.RegisterForRemoteNotifications();
...
}

Quando um aplicativo do iOS registra com o APNS, ele deve especificar os tipos de notificações por push que ele
gostaria de receber. O RegisterUserNotificationSettings método registra os tipos de notificações que o aplicativo
pode receber, com o RegisterForRemoteNotifications método registrar para receber notificações por push do
APNS.

NOTE
Falha ao chamar o RegisterUserNotificationSettings método resultará em notificações por push silenciosamente que
está sendo recebidas pelo aplicativo.

Manipulando a resposta de registro


A solicitação de registro APNS ocorre em segundo plano. Quando a resposta é recebida, o iOS chamará o
RegisteredForRemoteNotifications substituir no AppDelegate classe:

public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)


{
const string templateBodyAPNS = "{\"aps\":{\"alert\":\"$(messageParam)\"}}";

JObject templates = new JObject();


templates["genericMessage"] = new JObject
{
{"body", templateBodyAPNS}
};

// Register for push with the Azure mobile app


Push push = TodoItemManager.DefaultManager.CurrentClient.GetPush();
push.RegisterAsync(deviceToken, templates);
}

Esse método cria um modelo de mensagem de notificação simples como JSON e registra o dispositivo para
receber notificações de modelo do hub de notificação.

NOTE
O FailedToRegisterForRemoteNotifications substituição deve ser implementada para lidar com situações como
nenhuma conexão de rede. Isso é importante porque os usuários podem iniciar o aplicativo enquanto offline.

Processando notificações de envio por Push recebidas


O DidReceiveRemoteNotification substituir no AppDelegate classe é usada para processar as notificações por push
recebidas quando o aplicativo está em execução e é invocado quando uma notificação é recebida:
public override void DidReceiveRemoteNotification(
UIApplication application, NSDictionary userInfo, Action<UIBackgroundFetchResult> completionHandler)
{
NSDictionary aps = userInfo.ObjectForKey(new NSString("aps")) as NSDictionary;

string alert = string.Empty;


if (aps.ContainsKey(new NSString("alert")))
alert = (aps[new NSString("alert")] as NSString).ToString();

// Show alert
if (!string.IsNullOrEmpty(alert))
{
var notificationAlert = UIAlertController.Create("Notification", alert, UIAlertControllerStyle.Alert);
notificationAlert.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Cancel, null));
UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(notificationAlert,
true, null);
}
}

O userInfo dicionário contém o aps chave, cujo valor é o alert dicionário com os dados restantes de
notificação. Esse dicionário é recuperado, com o string que está sendo exibida em uma caixa de diálogo de
mensagem de notificação.

NOTE
Se um aplicativo não está em execução quando chega uma notificação por push, o aplicativo será iniciado, mas o
DidReceiveRemoteNotification método não processará a notificação. Em vez disso, obtenha a carga de notificação e
responder adequadamente a partir de WillFinishLaunching ou FinishedLaunching substitui.

Para obter mais informações sobre o APNS, consulte notificações por Push no iOS.
Android
O processo para implementar o suporte à notificação por push em um aplicativo Android é da seguinte maneira:
1. Adicione a firebase NuGet do pacote ao projeto do Android e defina a versão de destino do aplicativo para
Android 7.0 ou superior.
2. Adicione a google-services.json arquivo, baixado do console do Firebase, para a raiz do projeto do Android e
defina sua ação de compilação como GoogleServicesJson. Para obter mais informações, consulte adicionar o
arquivo de JSON de serviços do Google.
3. Registre-se com o Firebase Cloud Messaging (FCM ) declarando um receptor no manifesto do Android de
arquivo e por implementar a FirebaseRegistrationService.OnTokenRefresh método. Para obter mais
informações, consulte Registrando com o Firebase Cloud Messaging.
4. Registrar com o Hub de notificação do Azure na AzureNotificationHubService.RegisterAsync método. Para obter
mais informações, consulte Registrando com o Hub de notificação do Azure.
5. Implementar o FirebaseNotificationService.OnMessageReceived método para processar as notificações por push
recebidas. Para obter mais informações, consulte exibindo o conteúdo de uma notificação por Push.
Para obter mais informações sobre o Firebase Cloud Messaging, consulte Firebase Cloud Messaging e
notificações remotas com o Firebase Cloud Messaging.
Registrando com o Firebase Cloud Messaging
Antes de um aplicativo do Android pode receber notificações por push, deve ser registrado com o FCM, que vai
gerar um token de registro e retorná-lo para o aplicativo. Para obter mais informações sobre tokens do registro,
consulte registro com FCM.
Isso é feito:
Declarando um receptor no manifesto do Android. Para obter mais informações, consulte declarando o
receptor no manifesto do Android.
Implementando o serviço de ID de instância do Firebase. Para obter mais informações, consulte
Implementando o serviço de ID de instância do Firebase.
D e c l a r a n d o o r e c e p t o r n o m a n i fe st o d o A n d r o i d

Edite androidmanifest. XML e insira o seguinte <receiver> elementos no <application> elemento:

<receiver android:name="com.google.firebase.iid.FirebaseInstanceIdInternalReceiver" android:exported="false"


/>
<receiver android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver" android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="${applicationId}" />
</intent-filter>
</receiver>

Esse XML executa as seguintes operações:


Declara um interno FirebaseInstanceIdInternalReceiver implementação que é usada para iniciar os serviços
com segurança.
Declara um FirebaseInstanceIdReceiver implementação que fornece um identificador exclusivo para cada
instância do aplicativo. Esse receptor também autentica e autoriza ações.
O FirebaseInstanceIdReceiver recebe FirebaseInstanceId e FirebaseMessaging eventos e os entrega à classe que
é derivada de FirebasesInstanceIdService .
I m p l e m e n t a n d o o se r v i ç o d e I D d e i n st â n c i a d o F i r e b a se

Registrar o aplicativo com o FCM é feito derivando uma classe a partir de FirebaseInstanceIdService classe. Essa
classe é responsável por gerar tokens de segurança que autorizam o aplicativo cliente para acessar o FCM. No
aplicativo de exemplo o FirebaseRegistrationService classe deriva de FirebaseInstanceIdService classe e é
mostrado no exemplo de código a seguir:

[Service]
[IntentFilter(new[] { "com.google.firebase.INSTANCE_ID_EVENT" })]
public class FirebaseRegistrationService : FirebaseInstanceIdService
{
const string TAG = "FirebaseRegistrationService";

public override void OnTokenRefresh()


{
var refreshedToken = FirebaseInstanceId.Instance.Token;
Log.Debug(TAG, "Refreshed token: " + refreshedToken);
SendRegistrationTokenToAzureNotificationHub(refreshedToken);
}

void SendRegistrationTokenToAzureNotificationHub(string token)


{
// Update notification hub registration
Task.Run(async () =>
{
await
AzureNotificationHubService.RegisterAsync(TodoItemManager.DefaultManager.CurrentClient.GetPush(), token);
});
}
}

O OnTokenRefresh método é invocado quando o aplicativo recebe um token de registro do FCM. O método
recupera o token a partir de FirebaseInstanceId.Instance.Token propriedade, que é atualizada de forma assíncrona
pelo FCM. O OnTokenRefresh método é invocado com pouca frequência, porque o token é atualizado somente
quando o aplicativo é instalado ou desinstalado, quando o usuário exclui dados de aplicativos, quando o aplicativo
apaga a ID da instância, ou quando a segurança do token tiver sido comprometido. Além disso, o serviço de ID de
instância do FCM solicita que o aplicativo atualize seu token periodicamente, normalmente a cada 6 meses.
O OnTokenRefresh também invoca um método de SendRegistrationTokenToAzureNotificationHub método, que é
usado para associar o token de registro do usuário com o Hub de notificação do Azure.
Registrando com o Hub de notificação do Azure
O AzureNotificationHubService classe fornece o RegisterAsync método, que associa o token de registro do
usuário com o Hub de notificação do Azure. O seguinte exemplo de código mostra a RegisterAsync método, que é
invocado pelo FirebaseRegistrationService classe quando o token de registro do usuário é alterado:

public class AzureNotificationHubService


{
const string TAG = "AzureNotificationHubService";

public static async Task RegisterAsync(Push push, string token)


{
try
{
const string templateBody = "{\"data\":{\"message\":\"$(messageParam)\"}}";
JObject templates = new JObject();
templates["genericMessage"] = new JObject
{
{"body", templateBody}
};

await push.RegisterAsync(token, templates);


Log.Info("Push Installation Id: ", push.InstallationId.ToString());
}
catch (Exception ex)
{
Log.Error(TAG, "Could not register with Notification Hub: " + ex.Message);
}
}
}

Esse método cria um modelo de mensagem de notificação simples como JSON e se registra para receber
notificações de modelo do hub de notificação, usando o token de registro do Firebase. Isso garante que todas as
notificações enviadas do Hub de notificação do Azure serão o representado pelo token de registro de dispositivo
de destino.
Exibindo o conteúdo de uma notificação por Push
Exibir o conteúdo de uma notificação por push é obtido, derivando uma classe a partir de
FirebaseMessagingService classe. Essa classe inclui o substituível OnMessageReceived fornecido de método, que é
invocado quando o aplicativo recebe uma notificação do FCM, se o aplicativo está em execução em primeiro plano.
No aplicativo de exemplo do FirebaseNotificationService classe deriva o FirebaseMessagingService de classe e é
mostrado no exemplo de código a seguir:
[Service]
[IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
public class FirebaseNotificationService : FirebaseMessagingService
{
const string TAG = "FirebaseNotificationService";

public override void OnMessageReceived(RemoteMessage message)


{
Log.Debug(TAG, "From: " + message.From);

// Pull message body out of the template


var messageBody = message.Data["message"];
if (string.IsNullOrWhiteSpace(messageBody))
return;

Log.Debug(TAG, "Notification message body: " + messageBody);


SendNotification(messageBody);
}

void SendNotification(string messageBody)


{
var intent = new Intent(this, typeof(MainActivity));
intent.AddFlags(ActivityFlags.ClearTop);
var pendingIntent = PendingIntent.GetActivity(this, 0, intent, PendingIntentFlags.OneShot);

var notificationBuilder = new NotificationCompat.Builder(this)


.SetSmallIcon(Resource.Drawable.ic_stat_ic_notification)
.SetContentTitle("New Todo Item")
.SetContentText(messageBody)
.SetContentIntent(pendingIntent)
.SetSound(RingtoneManager.GetDefaultUri(RingtoneType.Notification))
.SetAutoCancel(true);

var notificationManager = NotificationManager.FromContext(this);


notificationManager.Notify(0, notificationBuilder.Build());
}
}

Quando o aplicativo recebe uma notificação do FCM, o OnMessageReceived método extrai o conteúdo da
mensagem e chama o SendNotification método. Este método converte o conteúdo da mensagem em uma
notificação de local que é iniciada enquanto o aplicativo é executado, com a notificação que aparece na área de
notificação.
M a n i p u l a ç ã o d e t e n t a t i v a s d e n o t i fi c a ç ã o

Quando um usuário toca uma notificação, todos os dados que acompanha a mensagem de notificação foi
disponibilizados no Intent extras. Esses dados podem ser extraídos com o código a seguir:

if (Intent.Extras != null)
{
foreach (var key in Intent.Extras.KeySet())
{
var value = Intent.Extras.GetString(key);
Log.Debug(TAG, "Key: {0} Value: {1}", key, value);
}
}

Iniciador do aplicativo Intent é acionado quando o usuário toca em sua mensagem de notificação, portanto, esse
código registrará em log todos os dados que acompanha este artigo no Intent à janela de saída.
Plataforma Universal do Windows
Antes de um Universal Windows Platform (UWP ) o aplicativo pode receber notificações por push que deve ser
registrado com o Windows serviço WNS (notificação), que retornará um canal de notificação. Registro é invocado
com o InitNotificationsAsync método no App classe:

private async Task InitNotificationsAsync()


{
var channel = await PushNotificationChannelManager
.CreatePushNotificationChannelForApplicationAsync();

const string templateBodyWNS =


"<toast><visual><binding template=\"ToastText01\"><text id=\"1\">$(messageParam)</text></binding>
</visual></toast>";

JObject headers = new JObject();


headers["X-WNS-Type"] = "wns/toast";

JObject templates = new JObject();


templates["genericMessage"] = new JObject
{
{"body", templateBodyWNS},
{"headers", headers} // Needed for WNS.
};

await TodoItemManager.DefaultManager.CurrentClient.GetPush()
.RegisterAsync(channel.Uri, templates);
}

Esse método obtém o canal de notificação por push, cria um modelo de mensagem de notificação como JSON e
registra o dispositivo para receber notificações de modelo do hub de notificação.
O InitNotificationsAsync método é chamado do OnLaunched substituir no App classe:

protected override async void OnLaunched(LaunchActivatedEventArgs e)


{
...
await InitNotificationsAsync();
}

Isso garante que o registro de notificação por push é criado ou atualizado sempre que o aplicativo é iniciado,
garantindo assim que o canal de push do WNS está sempre ativo.
Quando é recebida uma notificação por push ele será automaticamente exibido como uma toast – uma janela não
restrita que contém a mensagem.

Resumo
Este artigo demonstrou como usar os Hubs de notificação do Azure para enviar notificações por push de uma
instância de aplicativos móveis do Azure para um aplicativo xamarin. Forms. Os Hubs de notificação do Azure
fornecem uma infraestrutura de envio por push escalonável para enviar notificações por push de qualquer back-
end para qualquer plataforma móvel, enquanto elimina a complexidade de um back-end precisar se comunicar
com sistemas de notificação de plataforma diferente.

Links relacionados
Consumir um aplicativo móvel do Azure
Hubs de notificação do Azure
Adicionar notificações por push ao seu aplicativo xamarin. Forms
Notificações por push no iOS
Mensagens na nuvem do Firebase
TodoAzurePush (amostra)
SDK de cliente móvel do Azure
Armazenando arquivos na nuvem
12/04/2019 • 2 minutes to read

Armazenamento do Azure é uma solução de armazenamento de nuvem escalonáveis que pode ser usada para
armazenar dados estruturados e não estruturados.

Armazenando arquivos no armazenamento do Azure


Este artigo demonstra como usar o xamarin. Forms para armazenar texto e dados binários no armazenamento do
Azure e como acessar os dados.
Armazenar e acessar dados no armazenamento do
Azure
12/04/2019 • 18 minutes to read

baixar o exemplo
Armazenamento do Azure é uma solução de armazenamento de nuvem escalonável que pode ser usada para
armazenar dados não estruturados e estruturados. Este artigo demonstra como usar o xamarin. Forms para
armazenar texto e dados binários no armazenamento do Azure e como acessar os dados.
O armazenamento do Azure fornece quatro serviços de armazenamento:
Armazenamento de BLOBs. Um blob pode ser texto ou dados binários, como backups, máquinas virtuais,
arquivos de mídia ou documentos.
Armazenamento de tabela é um repositório de atributos de chave NoSQL.
Armazenamento de filas é um serviço de mensagens para processamento de fluxo de trabalho e comunicação
entre serviços de nuvem.
O armazenamento de arquivos oferece armazenamento compartilhado usando o protocolo SMB.
Há dois tipos de contas de armazenamento:
Contas de armazenamento de uso geral fornece acesso aos serviços de armazenamento do Azure de uma única
conta.
Uma conta de armazenamento de BLOBs é uma conta de armazenamento especializada para armazenamento
de blobs. Esse tipo de conta é recomendado quando você só precisa armazenar dados blob.
Neste artigo e que acompanha o aplicativo de exemplo demonstra a carregar arquivos de imagem e texto para o
armazenamento de blob e baixá-los. Além disso, ele também demonstra recuperando uma lista de arquivos do
armazenamento de BLOBs e excluir arquivos.
Para obter mais informações sobre o armazenamento do Azure, consulte Introdução ao armazenamento.

Introdução ao armazenamento de Blob


O armazenamento de BLOBs consiste em três componentes, que são mostrados no diagrama a seguir:
Todo o acesso ao armazenamento do Azure é por meio de uma conta de armazenamento. Uma conta de
armazenamento pode conter um número ilimitado de contêineres, e um contêiner pode armazenar um número
ilimitado de blobs, até o limite de capacidade da conta de armazenamento.
Um blob é um arquivo de qualquer tipo e tamanho. O armazenamento do Azure dá suporte a três tipos diferentes
de blob:
Blobs de blocos são otimizados para streaming e armazenamento de objetos de nuvem e são uma boa opção
para armazenar backups, arquivos de mídia, documentos etc. Blobs de bloco podem ser até 195Gb de tamanho.
Acrescentar blobs são semelhantes aos blobs de blocos, mas são otimizados para operações de acréscimo,
como registro em log. Acrescentar blobs podem ser de até 195Gb.
Blobs de página são otimizados para operações frequentes de leitura/gravação e normalmente são usados para
armazenar as máquinas virtuais e seus discos. Blobs de página podem ter até 1Tb de tamanho.

NOTE
Observe que as contas de armazenamento de BLOBs têm suporte para bloquear e acrescentar blobs, mas não os blobs de
página.

Um blob é carregado no armazenamento do Azure e baixado do armazenamento do Azure, como um fluxo de


bytes. Portanto, os arquivos devem ser convertidos em um fluxo de bytes antes de carregar e convertido de volta
para sua representação original após o download.
Cada objeto que é armazenado no armazenamento do Azure tem um endereço de URL exclusivo. O nome da
conta de armazenamento forma o subdomínio desse endereço e a combinação de formulários de nome de
domínio e subdomínio uma ponto de extremidade da conta de armazenamento. Por exemplo, se sua conta de
armazenamento é nomeada mystorageaccount, o ponto de extremidade de blob padrão para a conta de
armazenamento https://mystorageaccount.blob.core.windows.net .
A URL para acessar um objeto em uma conta de armazenamento é criada, acrescentando o local do objeto na
conta de armazenamento para o ponto de extremidade. Por exemplo, um endereço de blob terá o formato
https://mystorageaccount.blob.core.windows.net/mycontainer/myblob .

Configuração
O processo para integrar uma conta de armazenamento do Azure em um aplicativo xamarin. Forms é da seguinte
maneira:
1. Crie uma conta de armazenamento. Para obter mais informações, consulte criar uma conta de armazenamento.
2. Adicione a biblioteca de cliente de armazenamento do Azure ao aplicativo xamarin. Forms.
3. Configure a cadeia de caracteres de conexão de armazenamento. Para obter mais informações, consulte
conectar-se ao armazenamento do Azure.
4. Adicione using diretivas para o Microsoft.WindowsAzure.Storage e Microsoft.WindowsAzure.Storage.Blob
namespaces para classes que vai acessar o armazenamento do Azure.

Conectar-se ao armazenamento do Azure


Todas as solicitações feitas em relação aos recursos da conta de armazenamento devem ser autenticada. Embora
os blobs podem ser configurados para dar suporte à autenticação anônima, há duas abordagens principais para
que um aplicativo pode usar para autenticar com uma conta de armazenamento:
Chave compartilhada. Essa abordagem usa a chave de nome e da conta de armazenamento do Azure para
acessar os serviços de armazenamento. Uma conta de armazenamento recebe duas chaves privadas na criação
do que pode ser usado para autenticação de chave compartilhada.
Assinatura de acesso compartilhado. Esse é um token que pode ser anexado a uma URL que permite acesso
delegado a um recurso de armazenamento, com as permissões ele especifica, para o período de tempo em que
ele é válido.
Cadeias de caracteres de Conexão podem ser especificadas, que incluem as informações de autenticação
necessárias para acessar os recursos de armazenamento do Azure de um aplicativo. Além disso, uma cadeia de
caracteres de conexão pode ser configurada para se conectar ao emulador de armazenamento do Azure do Visual
Studio.

NOTE
O armazenamento do Azure dá suporte a HTTP e HTTPS em uma cadeia de conexão. No entanto, é recomendável usar
HTTPS.

Conectar-se ao emulador de armazenamento do Azure


O emulador de armazenamento do Azure fornece um ambiente local que emula os serviços de tabela para fins de
desenvolvimento, fila e BLOBs do Azure.
A seguinte cadeia de conexão deve ser usada para se conectar ao emulador de armazenamento do Azure:

UseDevelopmentStorage=true

Para obter mais informações sobre o emulador de armazenamento do Azure, consulte usar o emulador de
armazenamento do Azure para desenvolvimento e teste.
Conectar-se ao armazenamento do Azure usando uma chave compartilhada
O seguinte formato de cadeia de caracteres de conexão deve ser usado para se conectar ao armazenamento do
Azure com uma chave compartilhada:

DefaultEndpointsProtocol=[http|https];AccountName=myAccountName;AccountKey=myAccountKey

myAccountName deve ser substituído pelo nome da sua conta de armazenamento e myAccountKey deve ser
substituído por uma das suas duas chaves de acesso de conta.

NOTE
Ao usar compartilhada autenticação de chave, o nome da conta e chave de conta será distribuída para cada pessoa que usa
seu aplicativo, que fornece acesso completo de leitura/gravação à conta de armazenamento. Portanto, usar a autenticação de
chave compartilhada somente para testes e nunca distribuir chaves para outros usuários.

Conectar-se ao armazenamento do Azure usando uma assinatura de acesso compartilhado


O seguinte formato de cadeia de caracteres de conexão deve ser usado para se conectar ao armazenamento do
Azure com uma SAS:
BlobEndpoint=myBlobEndpoint;SharedAccessSignature=mySharedAccessSignature

myBlobEndpoint deve ser substituído pela URL do seu ponto de extremidade do blob e mySharedAccessSignature
deve ser substituído com a SAS. A SAS fornece o protocolo, o ponto de extremidade de serviço e as credenciais
para acessar o recurso.
NOTE
Autenticação de SAS é recomendada para aplicativos de produção. No entanto, em um aplicativo de produção as SAS devem
ser recuperadas de um back-end serviço sob demanda, em vez de ser agrupado com o aplicativo.

Para obter mais informações sobre assinaturas de acesso compartilhado, consulte usando acesso assinaturas
compartilhado (SAS ).

Criar um contêiner
O GetContainer método é usado para recuperar uma referência a um contêiner nomeado, o que, em seguida,
pode ser usado para recuperar os blobs do contêiner ou adicionar blobs no contêiner. O seguinte exemplo de
código mostra o GetContainer método:

static CloudBlobContainer GetContainer(ContainerType containerType)


{
var account = CloudStorageAccount.Parse(Constants.StorageConnection);
var client = account.CreateCloudBlobClient();
return client.GetContainerReference(containerType.ToString().ToLower());
}

O CloudStorageAccount.Parsemétodo analisa uma cadeia de caracteres de conexão e retorna um


CloudStorageAccount instância que representa a conta de armazenamento. Um CloudBlobClient instância, que é
usada para recuperar os contêineres e blobs, em seguida, é criada pelo CreateCloudBlobClient método. O
GetContainerReference método recupera o contêiner especificado como um CloudBlobContainer da instância, antes
de serem retornado para o método de chamada. Neste exemplo, o nome do contêiner é o ContainerType valor de
enumeração, convertido em uma cadeia de caracteres em minúsculas.

NOTE
Os nomes de contêiner devem estar em minúsculos e devem começar com uma letra ou número. Além disso, eles podem
conter apenas letras, números e o caractere de traço e devem ter entre 3 e 63 caracteres.

O GetContainer método é invocado da seguinte maneira:

var container = GetContainer(containerType);

O CloudBlobContainer instância, em seguida, pode ser usada para criar um contêiner se ele ainda não existir:

await container.CreateIfNotExistsAsync();

Por padrão, um contêiner recém-criado é privado. Isso significa que uma chave de acesso de armazenamento deve
ser especificada para recuperar os blobs do contêiner. Para obter informações sobre como fazer os blobs dentro de
um contêiner público, consulte criar um contêiner.

Carregar dados em um contêiner


O UploadFileAsync método é usado para carregar um fluxo de bytes de dados no armazenamento de BLOBs e é
mostrado no exemplo de código a seguir:
public static async Task<string> UploadFileAsync(ContainerType containerType, Stream stream)
{
var container = GetContainer(containerType);
await container.CreateIfNotExistsAsync();

var name = Guid.NewGuid().ToString();


var fileBlob = container.GetBlockBlobReference(name);
await fileBlob.UploadFromStreamAsync(stream);

return name;
}

Depois de recuperar uma referência de contêiner, o método cria o contêiner se ele ainda não existir.Uma nova
Guid , em seguida, é criado para atuar como um nome exclusivo de blob, e uma referência de blob de blocos é
recuperada como um CloudBlockBlob instância. O fluxo de dados é então carregado para o blob usando o
UploadFromStreamAsync método, que cria o blob se ele ainda não existe ou substitui, se ele existir.

Antes de um arquivo pode ser carregado usando esse método de armazenamento de BLOBs, primeiro ele deve ser
convertido para um fluxo de bytes. Isso é demonstrado no exemplo de código a seguir:

var byteData = Encoding.UTF8.GetBytes(text);


uploadedFilename = await AzureStorage.UploadFileAsync(ContainerType.Text, new MemoryStream(byteData));

O textdados são convertidos em uma matriz de bytes, que é empacotada como um fluxo que é passado para o
UploadFileAsync método.

Baixando dados de um contêiner


O GetFileAsync método é usado para baixar os dados de blob do armazenamento do Azure e é mostrado no
exemplo de código a seguir:

public static async Task<byte[]> GetFileAsync(ContainerType containerType, string name)


{
var container = GetContainer(containerType);

var blob = container.GetBlobReference(name);


if (await blob.ExistsAsync())
{
await blob.FetchAttributesAsync();
byte[] blobBytes = new byte[blob.Properties.Length];

await blob.DownloadToByteArrayAsync(blobBytes, 0);


return blobBytes;
}
return null;
}

Depois de recuperar uma referência de contêiner, o método recupera uma referência de blob para os dados
armazenados. Se o blob existir, suas propriedades são recuperadas pelo FetchAttributesAsync método. Uma
matriz de bytes do tamanho correto é criada e o blob é baixado como uma matriz de bytes que é retornada para o
método de chamada.
Depois de baixar os dados de bytes de blob, ele deve ser convertido em sua representação original. Isso é
demonstrado no exemplo de código a seguir:
var byteData = await AzureStorage.GetFileAsync(ContainerType.Text, uploadedFilename);
string text = Encoding.UTF8.GetString(byteData);

A matriz de bytes é recuperada do armazenamento do Azure ao GetFileAsync cadeia de caracteres codificada de


método, antes de ser convertido para um UTF8.

A listagem de dados em um contêiner


O GetFilesListAsync método é usado para recuperar uma lista de blobs armazenados em um contêiner e é
mostrado no exemplo de código a seguir:

public static async Task<IList<string>> GetFilesListAsync(ContainerType containerType)


{
var container = GetContainer(containerType);

var allBlobsList = new List<string>();


BlobContinuationToken token = null;

do
{
var result = await container.ListBlobsSegmentedAsync(token);
if (result.Results.Count() > 0)
{
var blobs = result.Results.Cast<CloudBlockBlob>().Select(b => b.Name);
allBlobsList.AddRange(blobs);
}
token = result.ContinuationToken;
} while (token != null);

return allBlobsList;
}

Depois de recuperar uma referência de contêiner, o método usa o contêiner ListBlobsSegmentedAsync método para
recuperar as referências para os blobs dentro do contêiner. Os resultados retornados pela ListBlobsSegmentedAsync
método são enumerados enquanto a BlobContinuationToken instância não é null . Cada blob é convertido de
retornado IListBlobItem para um CloudBlockBlob no acesso de ordem de Name propriedade do blob, antes que
seja o valor é adicionada ao allBlobsList coleção. Uma vez a BlobContinuationToken instância é null , o último
nome de blob retornou e execução sai do loop.

Excluir dados de um contêiner


O DeleteFileAsync método é usado para excluir um blob de um contêiner e é mostrado no exemplo de código a
seguir:

public static async Task<bool> DeleteFileAsync(ContainerType containerType, string name)


{
var container = GetContainer(containerType);
var blob = container.GetBlobReference(name);
return await blob.DeleteIfExistsAsync();
}

Depois de recuperar uma referência de contêiner, o método recupera uma referência de blob para o blob
especificado. O blob é excluído com o DeleteIfExistsAsync método.

Links relacionados
Armazenamento do Azure (exemplo)
Introdução ao armazenamento
Como usar o armazenamento de BLOBs do Xamarin
Usando assinaturas de acesso compartilhado (SAS )
Windows (NuGet) de armazenamento do Azure
Pesquisando dados na nuvem
12/04/2019 • 2 minutes to read

Pesquisa do Azure é um serviço de nuvem que fornece a indexação e consulta de recursos para os dados
carregados. Isso remove os requisitos de infraestrutura e as complexidades de algoritmo de pesquisa normalmente
associadas ao implementar a funcionalidade de pesquisa em um aplicativo.

Pesquisando dados com a pesquisa do Azure


Este artigo demonstra como usar a biblioteca de pesquisa do Microsoft Azure para integrar a pesquisa do Azure
em um aplicativo xamarin. Forms.
Pesquisa de dados com o Azure Search
12/04/2019 • 20 minutes to read

baixar o exemplo
O Azure Search é um serviço de nuvem que fornece a indexação e consulta recursos para os dados carregados.
Isso remove as complexidades do algoritmo de pesquisa tradicionalmente associadas ao implementar a
funcionalidade de pesquisa em um aplicativo e requisitos de infraestrutura. Este artigo demonstra como usar a
biblioteca do Microsoft Azure Search para integrar o Azure Search em um aplicativo xamarin. Forms.

Visão geral
Dados são armazenados no Azure Search, como índices e documentos. Uma índice é um repositório de dados que
podem ser pesquisados pelo serviço de Azure Search e é conceitualmente semelhante a uma tabela de banco de
dados. Um documento é uma única unidade de dados pesquisáveis em um índice e é conceitualmente semelhante
a uma linha do banco de dados. Quando carregar documentos e enviar consultas de pesquisa para o Azure Search,
as solicitações são feitas em um índice específico no serviço de pesquisa.
Cada solicitação feita ao Azure Search deve incluir o nome do serviço e uma chave de API. Há dois tipos de chave
de API:
Chaves de administração conceder direitos totais para todas as operações. Isso inclui o serviço de
gerenciamento, a criação e a exclusão de índices e fontes de dados.
Chaves de consulta conceder acesso somente leitura a índices e documentos e deve ser usado por aplicativos
que emitem solicitações de pesquisa.
A solicitação mais comum para o Azure Search é executar uma consulta. Há dois tipos de consulta que pode ser
enviado:
Um pesquisa consulta procura por um ou mais itens em todos os campos pesquisáveis em um índice.
Consultas de pesquisa são criadas usando a sintaxe simplificada, ou a sintaxe de consulta Lucene. Para obter
mais informações, consulte sintaxe de consulta simples no Azure Search, e sintaxe de consulta Lucene no Azure
Search.
Um filtro consulta avalia uma expressão booliana em todos os campos que podem ser filtrados em um índice.
Consultas de filtro são criadas usando um subconjunto da linguagem de filtro OData. Para obter mais
informações, consulte sintaxe de expressão do OData para o Azure Search.
Consultas de pesquisa e consultas de filtro podem ser usadas separadamente ou em conjunto. Quando usados
juntos, a consulta de filtro é aplicada primeiro ao índice inteiro e, em seguida, a consulta de pesquisa é realizada
nos resultados da consulta de filtro.
O Azure Search também dá suporte ao recuperar sugestões com base na entrada de pesquisa. Para obter mais
informações, consulte consultas de sugestão.

Configuração
O processo para a integração do Azure Search em um aplicativo xamarin. Forms é da seguinte maneira:
1. Crie um serviço Azure Search. Para obter mais informações, consulte criar um serviço de Azure Search usando
o Portal do Azure.
2. Remova o Silverlight como uma estrutura de destino da biblioteca de classe portátil (PCL ) da solução do
xamarin. Forms. Isso pode ser feito alterando o perfil PCL para qualquer perfil que dá suporte ao
desenvolvimento de plataforma cruzada, mas não oferece suporte a Silverlight, como perfil 151 ou 92.
3. Adicione a biblioteca do Microsoft Azure Search pacote NuGet ao projeto PCL na solução xamarin. Forms.
Depois de executar essas etapas, a API de biblioteca do Microsoft Search pode ser usada para gerenciar fontes de
dados e índices de pesquisa, carregar e gerenciar documentos e executar consultas.

Criar o índice de Azure Search


Um esquema de índice deve ser definido que é mapeado para a estrutura dos dados a ser pesquisado. Isso pode
ser realizado no Portal do Azure ou programaticamente usando o SearchServiceClient classe. Essa classe gerencia
conexões para o Azure Search e pode ser usado para criar um índice. O exemplo de código a seguir demonstra
como criar uma instância dessa classe:

var searchClient =
new SearchServiceClient(Constants.SearchServiceName, new SearchCredentials(Constants.AdminApiKey));

O sobrecarga de construtor aceita um nome de serviço de pesquisa e uma


SearchServiceClient
SearchCredentials como argumentos, o objeto com o SearchCredentials disposição do objeto a chave de
administração para o serviço de Azure Search. O chave de administração é necessária para criar um índice.

NOTE
Um único SearchServiceClient instância deve ser usada em um aplicativo para evitar abrir um número excessivo de
conexões para o Azure Search.

Um índice é definido pelo Index do objeto, conforme demonstrado no exemplo de código a seguir:

static void CreateSearchIndex()


{
var index = new Index()
{
Name = Constants.Index,
Fields = new[]
{
new Field("id", DataType.String) { IsKey = true, IsRetrievable = true },
new Field("name", DataType.String) { IsRetrievable = true, IsFilterable = true, IsSortable = true,
IsSearchable = true },
new Field("location", DataType.String) { IsRetrievable = true, IsFilterable = true, IsSortable = true,
IsSearchable = true },
new Field("details", DataType.String) { IsRetrievable = true, IsFilterable = true, IsSearchable = true
},
new Field("imageUrl", DataType.String) { IsRetrievable = true }
},
Suggesters = new[]
{
new Suggester("nameSuggester", SuggesterSearchMode.AnalyzingInfixMatching, new[] { "name" })
}
};

searchClient.Indexes.Create(index);
}

O Index.Name propriedade deve ser definida como o nome do índice e o Index.Fields propriedade deve ser
definida como uma matriz de Field objetos. Cada Field instância Especifica um nome, um tipo e quaisquer
propriedades que especificam como o campo é usado. Essas propriedades incluem:
IsKey – Indica se o campo é a chave do índice. Apenas um campo no índice, do tipo DataType.String , deve ser
designado como o campo de chave.
IsFacetable – Indica se é possível executar a navegação facetada nesse campo. O valor padrão é false .
IsFilterable – Indica se o campo pode ser usado em consultas de filtro. O valor padrão é false .
IsRetrievable – Indica se o campo pode ser recuperado nos resultados da pesquisa. O valor padrão é true .
IsSearchable – Indica se o campo está incluído em pesquisas de texto completo. O valor padrão é false .
IsSortable – Indica se o campo pode ser usado em OrderBy expressões. O valor padrão é false .

NOTE
Alterar um índice após sua implantação envolve a recriação e recarregar os dados.

Uma Index objeto pode especificar opcionalmente um Suggesters propriedade, que define os campos no índice a
ser usado para dar suporte a preenchimento automático ou consultas de sugestão de pesquisa. O Suggesters
propriedade deve ser definida como uma matriz de Suggester objetos que definem os campos que são usados
para criar resultados de sugestão de pesquisa.
Depois de criar o Index do objeto, o índice é criado chamando Indexes.Create sobre o SearchServiceClient
instância.

NOTE
Ao criar um índice de um aplicativo que deve ser mantido responsivo, use o Indexes.CreateAsync método.

Para obter mais informações, consulte criar um índice de Azure Search usando o SDK do .NET.

A exclusão do índice de Azure Search


Um índice pode ser excluído chamando Indexes.Delete sobre o SearchServiceClient instância:

searchClient.Indexes.Delete(Constants.Index);

Carregando dados para o índice de Azure Search


Depois de definir o índice, os dados podem ser carregados usando um destes dois modelos:
Modelo de pull – os dados são ingeridos periodicamente do Azure Cosmos DB, banco de dados SQL,
armazenamento de BLOBs do Azure ou SQL Server hospedado em uma máquina Virtual do Azure.
Modelo de push – dados por meio de programação são enviados para o índice. Esse é o modelo adotado
neste artigo.
Um SearchIndexClient instância deve ser criada para importar dados para o índice. Isso pode ser feito chamando
o SearchServiceClient.Indexes.GetClient método, conforme demonstrado no exemplo de código a seguir:
static void UploadDataToSearchIndex()
{
var indexClient = searchClient.Indexes.GetClient(Constants.Index);

var monkeyList = MonkeyData.Monkeys.Select(m => new


{
id = Guid.NewGuid().ToString(),
name = m.Name,
location = m.Location,
details = m.Details,
imageUrl = m.ImageUrl
});

var batch = IndexBatch.New(monkeyList.Select(IndexAction.Upload));


try
{
indexClient.Documents.Index(batch);
}
catch (IndexBatchException ex)
{
// Sometimes when the Search service is under load, indexing will fail for some
// documents in the batch. Compensating actions like delaying and retrying should be taken.
// Here, the failed document keys are logged.
Console.WriteLine("Failed to index some documents: {0}",
string.Join(", ", ex.IndexingResults.Where(r => !r.Succeeded).Select(r => r.Key)));
}
}

Dados a serem importados para o índice são empacotados como um IndexBatch objeto que encapsula uma
coleção de IndexAction objetos. Cada IndexAction instância contém um documento e uma propriedade que
informam ao Azure Search qual ação executar no documento. No exemplo de código acima, o IndexAction.Upload
ação for especificada, o que resulta no documento que está sendo inserida no índice, se for novo, ou substituída se
ele já existe. O IndexBatch objeto, em seguida, é enviado para o índice chamando o Documents.Index método o
SearchIndexClient objeto. Para obter informações sobre outras ações de indexação, consulte decidir qual ação de
indexação para usar.

NOTE
Apenas 1000 documentos podem ser incluídos em uma única solicitação de indexação.

Observe que no exemplo de código acima, o monkeyList coleção é criada como um objeto anônimo de uma
coleção de Monkey objetos. Isso cria os dados para o id campo e resolve o mapeamento de Pascal case Monkey
nomes de campo de índice de pesquisa de nomes de propriedade para concatenação com maiusculas. Como
alternativa, esse mapeamento também pode ser feito adicionando o [SerializePropertyNamesAsCamelCase] de
atributo para o Monkey classe.
Para obter mais informações, consulte carregar dados no Azure Search usando o SDK do .NET.

Consultar o índice de Azure Search


Um SearchIndexClient instância deve ser criada para consultar um índice. Quando um aplicativo executa
consultas, é recomendável seguir o princípio de privilégios mínimos e criar uma SearchIndexClient diretamente,
passando a chave de consulta como um argumento. Isso garante que os usuários tenham acesso somente leitura a
índices e documentos. Essa abordagem é demonstrada no exemplo de código a seguir:
SearchIndexClient indexClient =
new SearchIndexClient(Constants.SearchServiceName, Constants.Index, new
SearchCredentials(Constants.QueryApiKey));

O SearchIndexClientsobrecarga de construtor usa um nome de serviço de pesquisa, o nome do índice e um


SearchCredentials como argumentos, o objeto com o SearchCredentials disposição do objeto a chave de consulta
para o serviço de Azure Search.
Consultas de pesquisa
O índice pode ser consultado por meio da chamada a Documents.SearchAsync método no SearchIndexClient da
instância, conforme demonstrado no exemplo de código a seguir:

async Task AzureSearch(string text)


{
Monkeys.Clear();

var searchResults = await indexClient.Documents.SearchAsync<Monkey>(text);


foreach (SearchResult<Monkey> result in searchResults.Results)
{
Monkeys.Add(new Monkey
{
Name = result.Document.Name,
Location = result.Document.Location,
Details = result.Document.Details,
ImageUrl = result.Document.ImageUrl
});
}
}

O SearchAsync método usa um argumento de texto de pesquisa e um opcional SearchParameters objeto que pode
ser usado para refinar ainda mais a consulta. Uma consulta de pesquisa é especificada como o argumento de texto
de pesquisa, enquanto uma consulta de filtro pode ser especificada definindo a Filter propriedade do
SearchParameters argumento. O exemplo de código a seguir demonstra que os dois tipos de consulta:

var parameters = new SearchParameters


{
Filter = "location ne 'China' and location ne 'Vietnam'"
};
var searchResults = await indexClient.Documents.SearchAsync<Monkey>(text, parameters);

Essa consulta de filtro é aplicada a todo o índice e remove documentos nos resultados em que o location campo
não é igual a China e não é igual a Vietnã. Após a filtragem, a consulta de pesquisa é executada nos resultados da
consulta de filtro.

NOTE
Para filtrar sem pesquisar, passar * como o argumento de texto de pesquisa.

O SearchAsync método retorna um DocumentSearchResult objeto que contém os resultados da consulta. Esse
objeto é enumerado, com cada Document do objeto que está sendo criado como um Monkey do objeto e
adicionado à Monkeys ObservableCollection para exibição. Os seguir capturas de tela mostrar consulta resultados
da pesquisa retornados do Azure Search:
Para obter mais informações sobre pesquisa e filtragem, consulte consultar seu índice de Azure Search usando o
SDK do .NET.
Consultas de sugestão
O Azure Search permite sugestões para ser solicitado com base em uma consulta de pesquisa, chamando o
Documents.SuggestAsync método no SearchIndexClient instância. Isso é demonstrado no exemplo de código a
seguir:
async Task AzureSuggestions(string text)
{
Suggestions.Clear();

var parameters = new SuggestParameters()


{
UseFuzzyMatching = true,
HighlightPreTag = "[",
HighlightPostTag = "]",
MinimumCoverage = 100,
Top = 10
};

var suggestionResults =
await indexClient.Documents.SuggestAsync<Monkey>(text, "nameSuggester", parameters);

foreach (var result in suggestionResults.Results)


{
Suggestions.Add(new Monkey
{
Name = result.Text,
Location = result.Document.Location,
Details = result.Document.Details,
ImageUrl = result.Document.ImageUrl
});
}
}

O SuggestAsync método aceita um argumento de texto de pesquisa, o nome do sugestor usar (que é definido no
índice), e um opcional SuggestParameters objeto que pode ser usado para refinar ainda mais a consulta. O
SuggestParameters instância define as propriedades a seguir:

UseFuzzyMatching – Quando definido como true , Azure Search encontrará sugestões mesmo que haja um
caractere ausente ou substituído no texto de pesquisa.
HighlightPreTag – a marcação que é anexada à sugestão de ocorrências.
HighlightPostTag – a marcação que é acrescentada à sugestão de ocorrências.
MinimumCoverage – representa a porcentagem do índice que deve ser coberto por uma consulta de sugestão
para a consulta a ser relatado um sucesso. O padrão é 80.
Top – o número de sugestões a serem recuperadas. Ele deve ser um inteiro entre 1 e 100, com um valor
padrão de 5.
O efeito geral é que os 10 primeiros resultados do índice serão retornados com realce de ocorrências e os
resultados incluirão os documentos que incluem os termos de pesquisa a ortografia da mesma forma.
O SuggestAsync método retorna um DocumentSuggestResult objeto que contém os resultados da consulta. Esse
objeto é enumerado, com cada Document do objeto que está sendo criado como um Monkey do objeto e
adicionado à Monkeys ObservableCollection para exibição. As capturas de tela a seguir mostram os resultados de
sugestão retornados do Azure Search:
Observe que o aplicativo de exemplo, o SuggestAsync método é chamado somente quando o usuário termina de
inserir um termo de pesquisa. No entanto, ele também pode ser usado para dar suporte a consultas de pesquisa
de preenchimento automático executando em cada pressionamento de tecla.

Resumo
Este artigo demonstrou como usar a biblioteca do Microsoft Azure Search para integrar o Azure Search em um
aplicativo xamarin. Forms. O Azure Search é um serviço de nuvem que fornece a indexação e consulta recursos
para os dados carregados. Isso remove as complexidades do algoritmo de pesquisa tradicionalmente associadas
ao implementar a funcionalidade de pesquisa em um aplicativo e requisitos de infraestrutura.

Links relacionados
O Azure Search (amostra)
Documentação do Azure Search
Biblioteca do Microsoft Azure Search
Sem servidor de computação com o xamarin. Forms
12/04/2019 • 2 minutes to read

Compile aplicativos com a poderosa funcionalidade de back-end, sem a complexidade de configurar e gerenciar
um servidor.

Azure Functions
Comece criando seu primeiro Azure Function que interage com o xamarin. Forms.
Introdução ao Azure Functions
12/04/2019 • 2 minutes to read

[![Dbaixar exemplo](~/media/shared/download.png) Baixar a amostra]


(https://azure.microsoft.com/resources/samples/functions-xamarin-getting-started/ )
Comece a criar seu primeiro Azure Function que interage com o xamarin. Forms.
Visual Studio 2019
Visual Studio 2017
Visual Studio para Mac

Instruções passo a passo


Além de vídeo, você pode seguir estas instruções para compilar sua primeira função usando o Visual Studio.

Links relacionados
Documentos de funções do Azure
Implementando uma função do Azure simples com um cliente do xamarin. Forms (amostra)
Armazenamento de dados em um banco de dados
de documento
12/04/2019 • 2 minutes to read

Um banco de dados de documento de banco de dados do Azure Cosmos é um banco de dados NoSQL que
fornece acesso de baixa latência para documentos JSON, oferecendo um serviço de banco de dados rápida,
altamente disponível e dimensionável para aplicativos que necessitam de replicação global e escala contínua.

Consumo de um banco de dados de documento do Azure Cosmos DB


Este artigo explica como usar a biblioteca de cliente .NET padrão do Azure Cosmos DB para integrar um banco de
dados de documento de banco de dados do Azure Cosmos em um aplicativo xamarin. Forms.

Autenticar usuários com um banco de dados de documento do Azure


Cosmos DB
Este artigo explica como combinar o controle de acesso com coleções particionadas, para que um usuário pode
acessar somente seus próprios documentos em um aplicativo xamarin. Forms.
Consumo de um banco de dados de documentos do
Azure Cosmos DB
12/04/2019 • 15 minutes to read

baixar o exemplo
Um banco de dados de documentos do Azure Cosmos DB é um banco de dados NoSQL que fornece acesso de
baixa latência para documentos JSON, oferecendo um serviço de banco de dados rápida, altamente disponível e
escalonável para aplicativos que exigem dimensionamento perfeito e replicação global. Este artigo explica como
usar a biblioteca de cliente .NET Standard do Azure Cosmos DB para integrar um banco de dados de documentos
do Azure Cosmos DB em um aplicativo xamarin. Forms.

Microsoft Azure Cosmos DB, por Xamarin University


Uma conta de banco de dados de documento do Azure Cosmos DB pode ser provisionada usando uma assinatura
do Azure. Cada conta de banco de dados pode ter zero ou mais bancos de dados. Um banco de dados de
documentos no Azure Cosmos DB é um contêiner lógico para os usuários e coleções de documento.
Um banco de dados de documentos do Azure Cosmos DB pode conter zero ou mais coleções de documento. Cada
coleção de documentos pode ter um nível de desempenho diferentes, permitindo que mais taxa de transferência
deve ser especificado para coleções acessadas com frequência e menos produtividade para coleções acessadas
com pouca frequência.
Cada coleção de documento consiste em zero ou mais documentos JSON. Documentos em uma coleção são
esquemas e portanto, não precisará compartilhar a mesma estrutura ou campos. Como os documentos são
adicionados a uma coleção de documentos, o Cosmos DB indexa automaticamente-los e eles se tornam
disponíveis para serem consultados.
Para fins de desenvolvimento, um banco de dados de documentos também pode ser consumido por meio de um
emulador. Usando o emulador, aplicativos podem ser desenvolvidos e testados localmente, sem criar uma
assinatura do Azure ou incorrer em custos. Para obter mais informações sobre o emulador, consulte desenvolver
localmente com o emulador do Azure Cosmos DB.
Este artigo e que acompanha o aplicativo de exemplo demonstra um aplicativo de lista de tarefas em que as
tarefas são armazenadas em um banco de dados de documentos do Azure Cosmos DB. Para obter mais
informações sobre o aplicativo de exemplo, consulte Noções básicas da amostra.
Para obter mais informações sobre o Azure Cosmos DB, consulte a documentação do Azure Cosmos DB.

Configuração
O processo para a integração de um banco de dados de documentos do Azure Cosmos DB em um aplicativo
xamarin. Forms é da seguinte maneira:
1. Crie uma conta do Cosmos DB. Para obter mais informações, consulte criar uma conta do Azure Cosmos DB.
2. Adicione a biblioteca de cliente do .NET Standard do Azure Cosmos DB pacote do NuGet para os projetos de
plataforma da solução do xamarin. Forms.
3. Adicione using diretivas para o Microsoft.Azure.Documents , Microsoft.Azure.Documents.Client , e
Microsoft.Azure.Documents.Linq namespaces para classes que acessarão a conta do Cosmos DB.
Depois de executar essas etapas, a biblioteca de cliente .NET Standard do Azure Cosmos DB pode ser usada para
configurar e executar solicitações no banco de dados de documentos.

NOTE
A biblioteca de cliente .NET Standard do Azure Cosmos DB só pode ser instalada em projetos de plataforma e não em um
projeto de biblioteca de classe portátil (PCL). Portanto, o aplicativo de exemplo é um projeto de acesso compartilhado (SAP)
para evitar a duplicação de código. No entanto, o DependencyService classe pode ser usada em um projeto PCL para
invocar o código da biblioteca cliente .NET Standard do Azure Cosmos DB contido em projetos específicos da plataforma.

Consumo de conta do Azure Cosmos DB


O DocumentClient tipo encapsula o ponto de extremidade, credenciais e política de conexão usada para acessar a
conta do Azure Cosmos DB e é usado para configurar e executar solicitações em relação a conta. O exemplo de
código a seguir demonstra como criar uma instância dessa classe:

DocumentClient client = new DocumentClient(new Uri(Constants.EndpointUri), Constants.PrimaryKey);

O Uri do Cosmos DB e a chave primária devem ser fornecidas para o DocumentClient construtor. Eles podem ser
obtidos do Portal do Azure. Para obter mais informações, consulte conectar-se a uma conta do Azure Cosmos DB.
Criando um banco de dados
Um banco de dados do documento é um contêiner lógico para os usuários e coleções de documento e pode ser
criado no Portal do Azure ou programaticamente usando o DocumentClient.CreateDatabaseIfNotExistsAsync
método:

public async Task CreateDatabase(string databaseName)


{
...
await client.CreateDatabaseIfNotExistsAsync(new Database
{
Id = databaseName
});
...
}

O CreateDatabaseIfNotExistsAsync método Especifica um Database do objeto como um argumento, com o


Database objeto que especifica o nome do banco de dados como seu Id propriedade. O
CreateDatabaseIfNotExistsAsync método cria o banco de dados se ele não existir ou retorna o banco de dados se
ele já existe. No entanto, o aplicativo de exemplo ignora todos os dados retornados pelo
CreateDatabaseIfNotExistsAsync método.

NOTE
O CreateDatabaseIfNotExistsAsync método retorna um Task<ResourceResponse<Database>> objeto e o código de
status da resposta podem ser verificada para determinar se um banco de dados foi criado ou um banco de dados foi
retornado.

Criando uma coleção de documentos


Uma coleção de documentos é um contêiner para documentos JSON e pode ser criado no Portal do Azure ou
programaticamente usando o DocumentClient.CreateDocumentCollectionIfNotExistsAsync método:
public async Task CreateDocumentCollection(string databaseName, string collectionName)
{
...
// Create collection with 400 RU/s
await client.CreateDocumentCollectionIfNotExistsAsync(
UriFactory.CreateDatabaseUri(databaseName),
new DocumentCollection
{
Id = collectionName
},
new RequestOptions
{
OfferThroughput = 400
});
...
}

O CreateDocumentCollectionIfNotExistsAsync método requer dois argumentos compulsórios – um nome de banco


de dados especificado como uma Uri e um DocumentCollection objeto. O DocumentCollection objeto representa
uma coleção de documentos cujo nome é especificado com o Id propriedade. O
CreateDocumentCollectionIfNotExistsAsync método cria a coleção de documentos, se ele não existir ou retorna a
coleção de documentos, se ele já existe. No entanto, o aplicativo de exemplo ignora todos os dados retornados
pelo CreateDocumentCollectionIfNotExistsAsync método.

NOTE
O CreateDocumentCollectionIfNotExistsAsync método retorna um Task<ResourceResponse<DocumentCollection>>
objeto e o código de status da resposta podem ser verificada para determinar se uma coleção de documentos foi criada ou
uma coleção de documento existente foi retornada.

Opcionalmente, o CreateDocumentCollectionIfNotExistsAsync método também pode especificar um


RequestOptions objeto, que encapsula as opções que podem ser especificadas para solicitações emitidas para a
conta do Cosmos DB. O RequestOptions.OfferThroughput propriedade é usada para definir o nível de desempenho
da coleção de documentos e o exemplo de aplicativo, é definido como 400 unidades de solicitação por segundo.
Esse valor deve seja aumentado ou diminuído, dependendo se a coleção serão com frequência ou raramente
acessada.

IMPORTANT
Observe que o CreateDocumentCollectionIfNotExistsAsync método criará uma nova coleção com uma taxa de
transferência reservada, que tem implicações de preço.

Recuperando documentos da coleção do documento


O conteúdo de uma coleção de documentos pode ser recuperado criando e executando uma consulta de
documento. Uma consulta de documento é criada com o DocumentClient.CreateDocumentQuery método:
public async Task<List<TodoItem>> GetTodoItemsAsync()
{
...
var query = client.CreateDocumentQuery<TodoItem>(collectionLink)
.AsDocumentQuery();
while (query.HasMoreResults)
{
Items.AddRange(await query.ExecuteNextAsync<TodoItem>());
}
...
}

Essa consulta assíncrona recupera todos os documentos da coleção especificada e coloca os documentos em um
List<TodoItem> coleção para exibição.

O CreateDocumentQuery<T> método Especifica um Uri argumento que representa a coleção que deve ser
consultada para documentos. Neste exemplo, o collectionLink variável é um campo de nível de classe que
especifica o Uri que representa a coleção de documentos para recuperar os documentos a partir de:

Uri collectionLink = UriFactory.CreateDocumentCollectionUri(Constants.DatabaseName, Constants.CollectionName);

O CreateDocumentQuery<T> método cria uma consulta que é executada de forma síncrona e retorna um
IQueryable<T> objeto. No entanto, o AsDocumentQuery método converte os IQueryable<T> do objeto para um
IDocumentQuery<T> objeto que pode ser executado de forma assíncrona. A consulta assíncrona é executada com o
IDocumentQuery<T>.ExecuteNextAsync método, que recupera a próxima página de resultados de banco de dados de
documento, com o IDocumentQuery<T>.HasMoreResults propriedade que indica se há resultados adicionais a serem
retornados da consulta.
Os documentos podem ser filtradas do lado do servidor, incluindo um Where cláusula na consulta, que aplica um
predicado de filtragem à consulta na coleção de documentos:

var query = client.CreateDocumentQuery<TodoItem>(collectionLink)


.Where(f => f.Done != true)
.AsDocumentQuery();

Essa consulta recupera todos os documentos da coleção cuja Done propriedade é igual a false .
Inserindo um documento em uma coleção de documentos
Documentos são conteúdo JSON de definidas pelo usuário e podem ser inseridos em uma coleção de
documentos com o DocumentClient.CreateDocumentAsync método:

public async Task SaveTodoItemAsync(TodoItem item, bool isNewItem = false)


{
...
await client.CreateDocumentAsync(collectionLink, item);
...
}

O CreateDocumentAsync método Especifica um Uri argumento que representa a coleção em que o documento
deve ser inserido no, e um object argumento que representa o documento a ser inserido.
Substituição de um documento em uma coleção de documentos
Documentos podem ser substituídos em uma coleção de documentos com o DocumentClient.ReplaceDocumentAsync
método:
public async Task SaveTodoItemAsync(TodoItem item, bool isNewItem = false)
{
...
await client.ReplaceDocumentAsync(UriFactory.CreateDocumentUri(Constants.DatabaseName,
Constants.CollectionName, item.Id), item);
...
}

O ReplaceDocumentAsync método Especifica um Uri argumento que representa o documento na coleção que deve
ser substituído, e um object argumento que representa os dados de documento atualizado.
Excluir um documento de uma coleção de documentos
Um documento pode ser excluído de uma coleção de documentos com o DocumentClient.DeleteDocumentAsync
método:

public async Task DeleteTodoItemAsync(string id)


{
...
await client.DeleteDocumentAsync(UriFactory.CreateDocumentUri(Constants.DatabaseName,
Constants.CollectionName, id));
...
}

O DeleteDocumentAsync método Especifica um Uri argumento que representa o documento na coleção que deve
ser excluído.
Excluindo uma coleção de documentos
Uma coleção de documentos pode ser excluída do banco de dados com o
DocumentClient.DeleteDocumentCollectionAsync método:

await client.DeleteDocumentCollectionAsync(collectionLink);

O DeleteDocumentCollectionAsync método Especifica um Uri argumento que representa a coleção de documento


a ser excluído. Observe que a invocar esse método também excluirá os documentos armazenados na coleção.
Excluir um banco de dados
Um banco de dados pode ser excluído de uma conta de banco de dados do Cosmos DB com o
DocumentClient.DeleteDatabaesAsync método:

await client.DeleteDatabaseAsync(UriFactory.CreateDatabaseUri(Constants.DatabaseName));

O DeleteDatabaseAsync método Especifica um Uri argumento que representa o banco de dados a ser excluído.
Observe que invocar esse método também excluirá as coleções de documentos armazenadas no banco de dados e
os documentos armazenados nas coleções de documento.

Resumo
Este artigo explicou como usar a biblioteca de cliente .NET Standard do Azure Cosmos DB para integrar um banco
de dados de documentos do Azure Cosmos DB em um aplicativo xamarin. Forms. Um banco de dados de
documentos do Azure Cosmos DB é um banco de dados NoSQL que fornece acesso de baixa latência para
documentos JSON, oferecendo um serviço de banco de dados rápida, altamente disponível e escalonável para
aplicativos que exigem dimensionamento perfeito e replicação global.
Links relacionados
Todo Azure Cosmos DB (amostra)
Documentação do Azure Cosmos DB
Biblioteca de cliente do Azure Cosmos DB .NET Standard
API do Azure Cosmos DB
Autenticar usuários com um banco de dados de
documentos do Azure Cosmos DB
12/04/2019 • 22 minutes to read

baixar o exemplo
Bancos de dados de documento do Cosmos DB do Azure dão suporte a coleções particionadas, o que podem
abranger vários servidores e partições, e dar suporte a armazenamento ilimitado e taxa de transferência. Este
artigo explica como combinar o controle de acesso com coleções particionadas, para que um usuário só pode
acessar seus próprios documentos em um aplicativo xamarin. Forms.

Visão geral
Uma chave de partição deve ser especificada durante a criação de uma coleção particionada e documentos com a
mesma chave de partição serão armazenados na mesma partição. Portanto, especificando a identidade do usuário
como uma chave de partição resultará em uma coleção particionada que só irá armazenar documentos para que o
usuário. Isso também garante que o banco de dados de documentos do Azure Cosmos DB serão dimensionadas
conforme o número de usuários e aumentam de itens.
Acesso deve ser concedido a qualquer coleção e o modelo de controle de acesso de API do SQL define dois tipos
de construções de acesso:
Chaves mestras habilitam acesso administrativo total a todos os recursos dentro de uma conta do Cosmos DB
e são criadas quando uma conta do Cosmos DB é criada.
Tokens de recurso capturam a relação entre o usuário de um banco de dados e a permissão que o usuário tem
para um recurso específico do Cosmos DB, como uma coleção ou um documento.
Expor uma chave mestra é aberto em uma conta do Cosmos DB para a possibilidade de uso mal-intencionado ou
negligente. No entanto, os tokens de recurso do Azure Cosmos DB fornecem um mecanismo de seguro que
permita aos clientes ler, gravar e excluir recursos específicos em uma conta do Azure Cosmos DB de acordo com
as permissões concedidas.
Uma abordagem típica para solicitar, gerar e fornecer tokens de recurso para um aplicativo móvel é usar um
agente de token de recurso. O diagrama a seguir mostra uma visão geral de como o aplicativo de exemplo usa um
agente de token de recurso para gerenciar o acesso aos dados do banco de dados de documento:
O recurso Agente de token é um serviço de API da Web de camada intermediária, hospedado no serviço de
aplicativo do Azure, que tem a chave mestra da conta do Cosmos DB. O aplicativo de exemplo usa o agente de
token de recurso para gerenciar o acesso aos dados do banco de dados de documento da seguinte maneira:
1. Em logon, o aplicativo xamarin. Forms contata o serviço de aplicativo do Azure para iniciar um fluxo de
autenticação.
2. O serviço de aplicativo do Azure executa um fluxo de autenticação OAuth com o Facebook. Depois que o fluxo
de autenticação for concluída, o aplicativo xamarin. Forms recebe um token de acesso.
3. O aplicativo xamarin. Forms usa o token de acesso para solicitar um token de recurso do recurso Agente de
token.
4. O recurso Agente de token usa o token de acesso para solicitar a identidade do usuário do Facebook. A
identidade do usuário, em seguida, é usada para solicitar um token de recurso do Cosmos DB, que é usado para
conceder acesso de leitura/gravação para coleção particionada do usuário autenticado.
5. O aplicativo xamarin. Forms usa o token de recurso para acessar diretamente recursos do Cosmos DB com as
permissões definidas pelo token de recurso.

NOTE
Quando o token de recurso expira, solicitações de banco de dados de documento subsequente receberá uma exceção 401 de
não autorizado. Neste ponto, os aplicativos xamarin. Forms devem restabelecer a identidade e solicitar um novo token de
recurso.

Para obter mais informações sobre o particionamento do Cosmos DB, consulte como particionar e dimensionar
no Azure Cosmos DB. Para obter mais informações sobre o controle de acesso do Cosmos DB, consulte proteger o
acesso aos dados do Cosmos DB e controle de acesso no API do SQL.

Configuração
O processo para integrar o agente de token de recurso em um aplicativo xamarin. Forms é da seguinte maneira:
1. Crie uma conta do Cosmos DB que usará o controle de acesso. Para obter mais informações, consulte
configuração do BD Cosmos.
2. Crie um serviço de aplicativo do Azure para hospedar o agente de token de recurso. Para obter mais
informações, consulte configuração do serviço de aplicativo do Azure.
3. Crie um aplicativo do Facebook para realizar a autenticação. Para obter mais informações, consulte Facebook
App Configuration.
4. Configure o serviço de aplicativo do Azure para realizar a autenticação fácil com o Facebook. Para obter mais
informações, consulte configuração de autenticação de serviço de aplicativo do Azure.
5. Configure o aplicativo de exemplo do xamarin. Forms para se comunicar com o serviço de aplicativo do Azure e
o Cosmos DB. Para obter mais informações, consulte configuração do aplicativo xamarin. Forms.
Configuração do Azure Cosmos DB
O processo para criar uma conta do Cosmos DB que usará o controle de acesso é da seguinte maneira:
1. Crie uma conta do Cosmos DB. Para obter mais informações, consulte criar uma conta do Azure Cosmos DB.
2. Na conta do Cosmos DB, crie uma nova coleção chamada UserItems , especificando uma chave de partição de
/userid .

Configuração do serviço de aplicativo do Azure


O processo para hospedar o recurso Agente de token no serviço de aplicativo do Azure é da seguinte maneira:
1. No portal do Azure, crie um novo aplicativo de web do serviço de aplicativo. Para obter mais informações,
consulte criar um aplicativo web em um ambiente de serviço de aplicativo.
2. No portal do Azure, abra a folha de configurações do aplicativo para o aplicativo web e adicione as
seguintes configurações:
accountUrl – o valor deve ser a URL da conta do Cosmos DB na folha chaves de conta do Cosmos DB.
accountKey – o valor deve ser a chave mestra de Cosmos DB (primária ou secundária) na folha chaves
de conta do Cosmos DB.
databaseId – o valor deve ser o nome do banco de dados do Cosmos DB.
collectionId – o valor deve ser o nome da coleção do Cosmos DB (nesse caso, UserItems ).
hostUrl – o valor deve ser a URL do aplicativo web da folha de visão geral da conta de serviço de
aplicativo.
Captura de tela a seguir demonstra essa configuração:

3. Publica a solução de agente de token de recurso para o aplicativo de web do serviço de aplicativo do Azure.
Configuração de aplicativo do Facebook
O processo para criar um aplicativo do Facebook para realizar a autenticação é o seguinte:
1. Crie um aplicativo do Facebook. Para obter mais informações, consulte registrar e configurar um aplicativo no
Centro de desenvolvedores do Facebook.
2. Adicione o produto de logon do Facebook para o aplicativo. Para obter mais informações, consulte adicionar o
logon do Facebook ao seu aplicativo ou site no Centro de desenvolvedores do Facebook.
3. Configure o logon do Facebook da seguinte maneira:
Habilite o logon do cliente OAuth.
Habilite o logon do OAuth da Web.
Defina o URI para o URI do aplicativo web do serviço de aplicativo, de redirecionamento OAuth válidos com
/.auth/login/facebook/callback acrescentado.

Captura de tela a seguir demonstra essa configuração:


Para obter mais informações, consulte registrar seu aplicativo com o Facebook.
Configuração de autenticação do serviço de aplicativo do Azure
O processo para configurar a autenticação de serviço de aplicativo mais fácil é da seguinte maneira:
1. No Portal do Azure, navegue até o aplicativo do serviço de aplicativo web.
2. No Portal do Azure, abra a autenticação / folha de autorização e execute a seguinte configuração:
Autenticação do serviço de aplicativo deve ser ativada.
A ação a ser tomada quando uma solicitação for autenticada não deve ser definida como logon com o
Facebook.
Captura de tela a seguir demonstra essa configuração:

O serviço de aplicativo também deve ser configurado para se comunicar com o aplicativo do Facebook para
habilitar o fluxo de autenticação. Isso pode ser feito selecionando o provedor de identidade do Facebook e
inserindo os ID do aplicativo e segredo do aplicativo valores das configurações de aplicativo de Facebook no
Centro de desenvolvedores do Facebook. Para obter mais informações, consulte Facebook adicionar informações
ao seu aplicativo.
Configuração do aplicativo xamarin. Forms
O processo para configurar o aplicativo de exemplo do xamarin. Forms é da seguinte maneira:
1. Abra a solução do xamarin. Forms.
2. Abra Constants.cs e atualize os valores das constantes a seguir:

EndpointUri – o valor deve ser a URL da conta do Cosmos DB na folha chaves de conta do Cosmos DB.
DatabaseName – o valor deve ser o nome do banco de dados do documento.
CollectionName – o valor deve ser o nome da coleção de banco de dados de documentos (nesse caso,
UserItems ).
ResourceTokenBrokerUrl – o valor deve ser a URL do aplicativo web de agente de token de recurso da folha de
visão geral da conta de serviço de aplicativo.

Iniciando o logon
O aplicativo de exemplo inicia o processo de logon usando auth para redirecionar um navegador para uma URL
do provedor de identidade, conforme demonstrado no código de exemplo a seguir:

var auth = new Xamarin.Auth.WebRedirectAuthenticator(


new Uri(Constants.ResourceTokenBrokerUrl + "/.auth/login/facebook"),
new Uri(Constants.ResourceTokenBrokerUrl + "/.auth/login/done"));

Isso faz com que um fluxo de autenticação OAuth ser iniciada entre o serviço de aplicativo do Azure e o Facebook,
que exibe a página de logon do Facebook:

O logon pode ser cancelado, pressionando a cancele botão no iOS ou pressionando a volta botão no Android,
caso em que o usuário permanece não autenticado e a interface de usuário do provedor de identidade é removido
da tela.
Para obter mais informações sobre AUTH, consulte autenticando usuários com um provedor de identidade.

Como obter um Token de recurso


Após uma autenticação bem-sucedida, o WebRedirectAuthenticator.Completed evento é acionado. O exemplo de
código a seguir demonstra como manipular esse evento:

auth.Completed += async (sender, e) =>


{
if (e.IsAuthenticated && e.Account.Properties.ContainsKey("token"))
{
var easyAuthResponseJson = JsonConvert.DeserializeObject<JObject>(e.Account.Properties["token"]);
var easyAuthToken = easyAuthResponseJson.GetValue("authenticationToken").ToString();

// Call the ResourceBroker to get the resource token


using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Add("x-zumo-auth", easyAuthToken);
var response = await httpClient.GetAsync(Constants.ResourceTokenBrokerUrl + "/api/resourcetoken/");
var jsonString = await response.Content.ReadAsStringAsync();
var tokenJson = JsonConvert.DeserializeObject<JObject>(jsonString);
resourceToken = tokenJson.GetValue("token").ToString();
UserId = tokenJson.GetValue("userid").ToString();

if (!string.IsNullOrWhiteSpace(resourceToken))
{
client = new DocumentClient(new Uri(Constants.EndpointUri), resourceToken);
...
}
...
}
}
};

O resultado de uma autenticação bem-sucedida é um token de acesso, que está disponível


AuthenticatorCompletedEventArgs.Account propriedade. O token de acesso é extraído e usado em uma solicitação
GET para do recurso Agente de token resourcetoken API.
O resourcetoken API usa o token de acesso para solicitar a identidade do usuário do Facebook, que por sua vez é
usado para solicitar um token de recurso do Cosmos DB. Se já existe um documento de permissão válido para o
usuário no banco de dados de documento, ele é recuperado e um documento JSON que contém o token de
recurso é retornado ao aplicativo xamarin. Forms. Se um documento de permissão válido não existe para o
usuário, um usuário e a permissão é criada no banco de dados de documento e o token de recurso é extraído do
documento de permissão e retornado ao aplicativo xamarin. Forms em um documento JSON.

NOTE
Um usuário de banco de dados de documento é um recurso associado a um banco de dados de documento, e cada banco
de dados pode conter zero ou mais usuários. Uma permissão de banco de dados de documento é um recurso associado a
um usuário de banco de dados de documento, e cada usuário pode conter zero ou mais permissões. Um recurso de
permissão fornece acesso a um token de segurança que exige que o usuário durante a tentativa de acessar um recurso,
como um documento.

Se o resourcetoken API for concluída com êxito, ele enviará o código de status HTTP 200 (Okey) na resposta,
juntamente com um documento JSON que contém o token de recurso. Os dados JSON a seguir mostram uma
mensagem de resposta bem-sucedida típico:
{
"id": "John Smithpermission",
"token":
"type=resource&ver=1&sig=zx6k2zzxqktzvuzuku4b7y==;a74aukk99qtwk8v5rxfrfz7ay7zzqfkbfkremrwtaapvavw2mrvia4umbi/7
iiwkrrq+buqqrzkaq4pp15y6bki1u//zf7p9x/aefbvqvq3tjjqiffurfx+vexa1xarxkkv9rbua9ypfzr47xpp5vmxuvzbekkwq6txme0xxxb
jhzaxbkvzaji+iru3xqjp05amvq1r1q2k+qrarurhmjzah/ha0evixazkve2xk1zu9u/jpyf1xrwbkxqpzebvqwma+hyyaazemr6qx9uz9be==
;",
"expires": 4035948,
"userid": "John Smith"
}

O WebRedirectAuthenticator.Completed manipulador de eventos lê a resposta do resourcetoken API e extrai o


token de recurso e a id de usuário. O token de recurso, em seguida, é passado como um argumento para o
DocumentClient construtor, que encapsula o ponto de extremidade, credenciais e política de conexão usada para
acessar o Cosmos DB e é usado para configurar e executar solicitações no Cosmos DB. O token de recurso é
enviado com cada solicitação para acessar diretamente um recurso e indica que o acesso de leitura/gravação para
coleção particionada dos usuários autenticados é concedido.

Recuperar documentos
Recuperar documentos que só pertencem ao usuário autenticado pode ser obtido com a criação de uma consulta
de documento que inclui a id do usuário como uma chave de partição e, em seguida, é demonstrada no exemplo
de código a seguir:

var query = client.CreateDocumentQuery<TodoItem>(collectionLink,


new FeedOptions
{
MaxItemCount = -1,
PartitionKey = new PartitionKey(UserId)
})
.Where(item => !item.Id.Contains("permission"))
.AsDocumentQuery();
while (query.HasMoreResults)
{
Items.AddRange(await query.ExecuteNextAsync<TodoItem>());
}

A consulta de forma assíncrona recupera todos os documentos pertencentes ao usuário autenticado, da coleção
especificada e as colocará em um List<TodoItem> coleção para exibição.
O CreateDocumentQuery<T> método Especifica um Uri argumento que representa a coleção que deve ser
consultada para documentos, e um FeedOptions objeto. O FeedOptions objeto Especifica que um número
ilimitado de itens pode ser retornado pela consulta e a id do usuário como uma chave de partição. Isso garante
que apenas os documentos na coleção particionada do usuário são retornados no resultado.

NOTE
Observe que os documentos de permissão, que são criados pelo recurso Agente de token, são armazenados na coleção de
documentos como os documentos criados pelo aplicativo xamarin. Forms. Portanto, a consulta de documento contém um
Where cláusula que aplica um predicado de filtragem à consulta na coleção de documentos. Essa cláusula garante que os
documentos de permissão não são retornados da coleção de documentos.

Para obter mais informações sobre como recuperar os documentos de uma coleção de documentos, consulte
Recuperando documentos da coleção do documento.
Inserir documentos
Antes de inserir um documento em uma coleção de documentos, o TodoItem.UserId propriedade deve ser
atualizada com o valor que está sendo usado como a chave de partição, conforme demonstrado no exemplo de
código a seguir:

item.UserId = UserId;
await client.CreateDocumentAsync(collectionLink, item);

Isso garante que o documento será inserido na coleção particionada do usuário.


Para obter mais informações sobre como inserir um documento em uma coleção de documentos, consulte
inserindo um documento em uma coleção de documentos.

Exclusão de documentos
O valor de chave de partição deve ser especificado quando a exclusão de um documento de uma coleção
particionada, como demonstrado no exemplo de código a seguir:

await client.DeleteDocumentAsync(UriFactory.CreateDocumentUri(Constants.DatabaseName,
Constants.CollectionName, id),
new RequestOptions
{
PartitionKey = new PartitionKey(UserId)
});

Isso garante que o Cosmos DB sabe qual particionados coleção para excluir o documento da.
Para obter mais informações sobre como excluir um documento de uma coleção de documentos, consulte exclusão
de um documento de uma coleção de documentos.

Resumo
Este artigo explicou como combinar o controle de acesso com coleções particionadas, para que um usuário só
pode acessar seus próprios documentos do banco de dados de documento em um aplicativo xamarin. Forms.
Especificando a identidade do usuário como uma chave de partição garante que uma coleção particionada só pode
armazenar documentos para que o usuário.

Links relacionados
Todo o Azure Cosmos DB Auth (amostra)
Consumo de um banco de dados de documento do Azure Cosmos DB
Protegendo o acesso a dados do Azure Cosmos DB
Controle de acesso no API do SQL.
Como particionar e dimensionar no Azure Cosmos DB
Biblioteca de cliente do Azure Cosmos DB
API do Azure Cosmos DB
Adicionando inteligência com os serviços Cognitivos
12/04/2019 • 10 minutes to read

baixar o exemplo
Serviços Cognitivos da Microsoft são um conjunto de APIs, SDKs e serviços disponíveis para desenvolvedores para
tornar seus aplicativos mais inteligentes com a adição de recursos, como reconhecimento facial, reconhecimento
de fala e reconhecimento vocal. Este artigo fornece uma introdução ao aplicativo de exemplo que demonstra
como invocar algumas das APIs de serviços Cognitivos da Microsoft.

Visão geral
O exemplo que acompanha este artigo é um aplicativo de lista de tarefas que fornece funcionalidade para:
Exiba uma lista de tarefas.
Adicionar e editar tarefas por meio do teclado virtual, ou realizando o reconhecimento de fala com a API de fala
da Microsoft. Para obter mais informações sobre como executar o reconhecimento de fala, consulte
reconhecimento de fala usando a API de fala da Microsoft.
Usando a API de verificação de ortografia do Bing de tarefas de verificação de ortografia. Para obter mais
informações, consulte ortográfica usando a API de verificação de ortografia do Bing.
Converter tarefas do inglês para o alemão usando a API de tradução. Para obter mais informações, consulte
tradução de texto usando a API do Translator.
Exclua tarefas.
Defina o status da tarefa para 'concluído'.
Avalie o aplicativo com reconhecimento de emoções, usando a API de detecção facial. Para obter mais
informações, consulte reconhecimento de emoções usando a API de detecção facial.
Tarefas são armazenadas em um banco de dados SQLite local. Para obter mais informações sobre como usar um
banco de dados SQLite local, consulte trabalhando com um banco de dados Local.
O TodoListPage é exibida quando o aplicativo é iniciado. Esta página exibe uma lista de quaisquer tarefas
armazenados no banco de dados local e permite que o usuário para criar uma nova tarefa ou para avaliar o
aplicativo:
Novos itens podem ser criados, clicando na + botão, que navega para o TodoItemPage . Esta página também pode
ser navegada, selecionando uma tarefa:
O TodoItemPage permite que as tarefas a serem criados, editados, uma verificação ortográfica, traduzida, salva e
excluída. Reconhecimento de fala pode ser usado para criar ou editar uma tarefa. Isso é obtido pressionando o
botão de microfone para iniciar a gravação e pressionando o botão mesmo uma segunda vez para parar a
gravação, que envia a gravação para a API de reconhecimento de fala do Bing.
Clicar no botão smilies na TodoListPage navega para o RateAppPage , que é usado para realizar o reconhecimento
de emoções em uma imagem de uma expressão facial:

O RateAppPage permite que o usuário tirar uma foto do seu face, que é enviado à API de detecção facial com a
detecção de emoções retornada que está sendo exibida.

Noções básicas sobre a anatomia do aplicativo


O projeto de biblioteca de classe portátil (PCL ) para o aplicativo de exemplo consiste em cinco pastas principais:

PASTA FINALIDADE

Modelos Contém as classes de modelo de dados para o aplicativo. Isso


inclui o TodoItem classe, que modela um único item de
dados usados pelo aplicativo. A pasta também contém classes
usadas para modelar respostas JSON retornadas de diferentes
APIs serviços Cognitivos da Microsoft.

Repositórios Contém o ITodoItemRepositoryinterface e


TodoItemRepository classe que são usados para executar
operações de banco de dados.
PASTA FINALIDADE

Serviços Contém as interfaces e classes que são usadas para acessar


diferentes Microsoft APIs de serviços Cognitivos, juntamente
com as interfaces que são usadas pelo DependencyService
classe para localizar as classes que implementam as interfaces
em projetos de plataforma.

Utils Contém o Timerclasse, que é usado pelo


AuthenticationService classe para renovar um token de
acesso JWT cada 9 minutos.

Exibições Contém as páginas do aplicativo.

O projeto PCL também contém alguns arquivos importantes:

ARQUIVO FINALIDADE

Constants.cs O Constants classe, que especifica as chaves de API e os


pontos de extremidade para o Microsoft Cognitive APIs de
serviços que são invocados. As constantes de chave de API
exigem atualização para acessar as APIs de serviços Cognitivos
diferentes.

App.xaml.cs O App classe é responsável por instanciar os dois a primeira


página que será exibida pelo aplicativo em cada plataforma, e
o TodoManager classe que é usado para invocar operações de
banco de dados.

Pacotes NuGet
O aplicativo de exemplo usa os seguintes pacotes NuGet:
Newtonsoft.Json – Fornece uma estrutura JSON para .NET.
PCLStorage – Fornece um conjunto de arquivos local de plataforma cruzada APIs de e/s.
sqlite-net-pcl – Fornece armazenamento de banco de dados SQLite.
Xam.Plugin.Media – Fornece levando de foto de plataforma cruzada e APIs de separação.

Além disso, esses pacotes do NuGet também instalam suas próprias dependências.
Modelagem de dados
O aplicativo de exemplo usa o TodoItem classe para modelar os dados que são exibidos e armazenados no banco
de dados SQLite local. O exemplo de código a seguir mostra a classe TodoItem :

public class TodoItem


{
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
public string Name { get; set; }
public bool Done { get; set; }
}

O ID propriedade é usada para identificar exclusivamente cada TodoItem da instância e é decorado com atributos
de SQLite que tornam a propriedade de uma chave primária de incremento automático no banco de dados.
Chamando as operações de banco de dados
O TodoItemRepository classe implementa as operações de banco de dados e uma instância da classe pode ser
acessada por meio de App.TodoManager propriedade. O TodoItemRepository classe fornece os seguintes métodos
para chamar operações de banco de dados:
GetAllItemsAsync – recupera todos os itens do banco de dados SQLite local.
GetItemAsync – recupera um item especificado do banco de dados SQLite local.
SaveItemAsync – cria ou atualiza um item no banco de dados SQLite local.
DeleteItemAsync – exclui o item especificado do banco de dados SQLite local.
Implementações de projeto de plataforma
O Services pasta no projeto PCL contém o IFileHelper e IAudioRecorderService interfaces que são usadas pelo
DependencyService classe para localizar as classes que implementam as interfaces em projetos de plataforma.

O IFileHelper interface é implementada pelo FileHelper classe em cada projeto da plataforma. Essa classe
consiste em um único método, GetLocalFilePath , que retorna um caminho de arquivo local para armazenar o
banco de dados SQLite.
O IAudioRecorderService interface é implementada pelo AudioRecorderService classe em cada projeto da
plataforma. Essa classe consiste StartRecording , StopRecording e que dão suporte a métodos, que usam as APIs
da plataforma para gravar áudio do microfone do dispositivo e armazená-lo como um arquivo wav. No iOS, o
AudioRecorderService usa o AVFoundation API gravar áudio. No Android, o AudioRecordService usa o AudioRecord
API gravar áudio. Na Universal Windows Platform (UWP ), o AudioRecorderService usa o AudioGraph API gravar
áudio.
Invocando serviços Cognitivos
O aplicativo de exemplo invoca os seguintes serviços Cognitivos da Microsoft:
API de fala do Microsoft. Para obter mais informações, consulte reconhecimento de fala usando a API de fala da
Microsoft.
API de verificação de ortografia de Bing. Para obter mais informações, consulte ortográfica usando a API de
verificação de ortografia do Bing.
Converter API. Para obter mais informações, consulte tradução de texto usando a API do Translator.
API de detecção facial. Para obter mais informações, consulte reconhecimento de emoções usando a API de
detecção facial.

Links relacionados
Documentação dos serviços Cognitivos da Microsoft
Serviços Cognitivos de tarefas pendentes (amostra)
Reconhecimento de fala usando a API de fala da
Microsoft
12/04/2019 • 8 minutes to read

baixar o exemplo
A API de fala da Microsoft é uma API baseada em nuvem que fornece algoritmos para processar a linguagem
falada. Este artigo explica como usar a API de REST de reconhecimento de fala Microsoft para converter áudio
em texto em um aplicativo xamarin. Forms.

Visão geral
A API de fala da Microsoft tem dois componentes:
Um reconhecimento de fala API para a conversão de palavras faladas em texto. Reconhecimento de fala pode
ser executado por meio de uma API REST, a biblioteca de cliente ou a biblioteca de serviço.
Um texto em fala API para converter texto em palavras faladas. Conversão de texto em fala é realizada por
meio da API REST.
Este artigo se concentra em fazer o reconhecimento de fala por meio da API REST. Embora as bibliotecas de
cliente e serviço de suporte ao retorno de resultados parciais, a API REST só pode retornar um resultado de
reconhecimento única, sem quaisquer resultados parciais.
Uma chave de API deve ser obtida para usar a API de fala da Microsoft. Isso pode ser obtido do Azure portal.
Para obter mais informações, consulte criar uma conta de serviços Cognitivos no portal do Azure.
Para obter mais informações sobre a API de fala da Microsoft, consulte documentação de API de fala do
Microsoft.

Autenticação
Todas as solicitações feitas para a API de REST de fala da Microsoft exigem um token de acesso do JSON Web
Token (JWT), que pode ser obtido do serviço de token dos serviços cognitivos
https://api.cognitive.microsoft.com/sts/v1.0/issueToken . Um token pode ser obtido, fazendo uma solicitação
POST para o serviço de token, especificando um Ocp-Apim-Subscription-Key cabeçalho que contém a chave de
API como seu valor.
O exemplo de código a seguir mostra como solicitar um acesso de token do serviço de token:
public AuthenticationService(string apiKey)
{
subscriptionKey = apiKey;
httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", apiKey);
}
...
async Task<string> FetchTokenAsync(string fetchUri)
{
UriBuilder uriBuilder = new UriBuilder(fetchUri);
uriBuilder.Path += "/issueToken";
var result = await httpClient.PostAsync(uriBuilder.Uri.AbsoluteUri, null);
return await result.Content.ReadAsStringAsync();
}

O token de acesso retornado, o que é um texto Base64, tem uma hora de expiração de 10 minutos. Portanto, o
aplicativo de exemplo renova o token de acesso a cada 9 minutos.
O token de acesso deve ser especificado em cada API de REST de fala da Microsoft chamada como um
Authorization cabeçalho prefixado com a cadeia de caracteres Bearer , conforme mostrado no exemplo de
código a seguir:

httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken);

Falha ao passar um token de acesso válido para a API de REST de fala da Microsoft resultará em um erro de 403
resposta.

Fazer o reconhecimento de fala


Reconhecimento de fala é obtido por meio de uma solicitação POST para o recognition API em
https://speech.platform.bing.com/speech/recognition/ . Uma única solicitação não pode conter mais de 10
segundos de áudio e a duração da solicitação total não pode exceder 14 segundos.
Conteúdo de áudio deve ser colocado no corpo POST da solicitação no formato wav.
No aplicativo de exemplo, o RecognizeSpeechAsync método invoca o processo de reconhecimento de fala:

public async Task<SpeechResult> RecognizeSpeechAsync(string filename)


{
...

// Read audio file to a stream


var file = await PCLStorage.FileSystem.Current.LocalStorage.GetFileAsync(filename);
var fileStream = await file.OpenAsync(PCLStorage.FileAccess.Read);

// Send audio stream to Bing and deserialize the response


string requestUri = GenerateRequestUri(Constants.SpeechRecognitionEndpoint);
string accessToken = authenticationService.GetAccessToken();
var response = await SendRequestAsync(fileStream, requestUri, accessToken, Constants.AudioContentType);
var speechResult = JsonConvert.DeserializeObject<SpeechResult>(response);

fileStream.Dispose();
return speechResult;
}

Áudio é gravado em cada projeto específico da plataforma, como dados de wav do PCM e o
RecognizeSpeechAsync usa o PCLStorage pacote do NuGet para abrir o arquivo como um fluxo de áudio. A
solicitação de reconhecimento de fala URI é gerado e um token de acesso é recuperado do serviço de token. A
solicitação de reconhecimento de fala é postada para o recognition API, que retorna uma resposta JSON que
contém o resultado. A resposta JSON é desserializada, com o resultado retornado para o método de chamada
para exibição.
Configurando o reconhecimento de fala
O processo de reconhecimento de fala pode ser configurado especificando parâmetros de consulta HTTP:

string GenerateRequestUri(string speechEndpoint)


{
// To build a request URL, you should follow:
// https://docs.microsoft.com/azure/cognitive-services/speech/getstarted/getstartedrest
string requestUri = speechEndpoint;
requestUri += @"dictation/cognitiveservices/v1?";
requestUri += @"language=en-us";
requestUri += @"&format=simple";
System.Diagnostics.Debug.WriteLine(requestUri.ToString());
return requestUri;
}

A principal configuração executada pelo GenerateRequestUri método é definir a localidade do conteúdo de áudio.
Para obter uma lista de localidades com suporte, consulte idiomas com suporte .
Enviar a solicitação
O SendRequestAsync método faz a solicitação POST para a API de REST de fala da Microsoft e retorna a resposta:

async Task<string> SendRequestAsync(Stream fileStream, string url, string bearerToken, string contentType)
{
if (httpClient == null)
{
httpClient = new HttpClient();
}
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken);

var content = new StreamContent(fileStream);


content.Headers.TryAddWithoutValidation("Content-Type", contentType);
var response = await httpClient.PostAsync(url, content);
return await response.Content.ReadAsStringAsync();
}

Este método constrói a solicitação POST por:


Envolve o fluxo de áudio em um StreamContent instância, que fornece conteúdo HTTP com base em um fluxo.
Definindo o Content-Type cabeçalho da solicitação para audio/wav; codec="audio/pcm"; samplerate=16000 .
Adicionando o token de acesso para o Authorization cabeçalho, prefixado com a cadeia de caracteres Bearer .

A solicitação POST é enviada para recognition API. A resposta é, em seguida, ler e retornada para o método de
chamada.
O recognition API enviará o código de status HTTP 200 (Okey) em resposta, fornecida que a solicitação é válida,
que indica que a solicitação foi bem-sucedida e que as informações solicitadas estão na resposta. Para obter uma
lista de possíveis respostas de erro, consulte solução de problemas.
Processar a resposta
A resposta da API é retornada no formato JSON, com o texto reconhecido sendo contido no name marca. Os
dados JSON a seguir mostram uma mensagem de resposta bem-sucedida típico:
{
"RecognitionStatus":"Success",
"DisplayText":"Go shopping tomorrow.",
"Offset":16000000,
"Duration":17100000
}

No aplicativo de exemplo, a resposta JSON é desserializada em um SpeechResult instância, com o resultado


retornado para o método de chamada para exibição, conforme mostrado nas capturas de tela seguir:

Resumo
Este artigo explicou como usar a API de REST de fala da Microsoft para converter áudio em texto em um
aplicativo xamarin. Forms. Além de realizar o reconhecimento de fala, API de fala da Microsoft também pode
converter o texto em palavras faladas.

Links relacionados
Documentação da API de fala da Microsoft.
Consumir um serviço Web RESTful
Serviços Cognitivos de tarefas pendentes (amostra)
Verificação ortográfica usando a API de verificação
ortográfica do Bing
12/04/2019 • 9 minutes to read

baixar o exemplo
Verificação ortográfica do Bing executa ortográfica contextual para texto, fornecendo sugestões embutido para
palavras incorretas. Este artigo explica como usar a API de REST de verificação ortográfica de Bing para corrigir
erros de ortografia em um aplicativo xamarin. Forms.

Visão geral
A API de REST de verificação ortográfica de Bing tem dois modos de operação e um modo deve ser especificado
ao fazer uma solicitação para a API:
Spell corrige o texto curto (palavras até 9) sem quaisquer alterações de maiusculas e minúsculas.
Proof corrige o texto longo, fornece correções de maiusculas e minúsculas e pontuação básica e suprime
correções agressivas.
Uma chave de API deve ser obtida para usar a API de verificação de ortografia do Bing. Isso pode ser obtido no
Experimente os serviços Cognitivos
Para obter uma lista dos idiomas com suporte a API de verificação de ortografia do Bing, consulte idiomas com
suporte. Para obter mais informações sobre a API de verificação de ortografia do Bing, consulte documentação de
verificação ortográfica de Bing.

Autenticação
Todas as solicitações feitas para a API de verificação de ortografia do Bing requer uma chave de API que deve ser
especificada como o valor da Ocp-Apim-Subscription-Key cabeçalho. O exemplo de código a seguir mostra como
adicionar a chave de API para o Ocp-Apim-Subscription-Key cabeçalho de uma solicitação:

public BingSpellCheckService()
{
httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", Constants.BingSpellCheckApiKey);
}

Falha ao passar uma chave de API válida para a API de verificação de ortografia do Bing resultará em um erro de
401 resposta.

Executar a verificação ortográfica


Verificação ortográfica pode ser obtida por meio de uma solicitação GET ou POST para o SpellCheck API em
https://api.cognitive.microsoft.com/bing/v7.0/SpellCheck . Quando você faz uma solicitação GET, o texto a ser
ortografia verificada é enviado como um parâmetro de consulta. Quando você faz uma solicitação POST, o texto a
ser ortografia verificada é enviado no corpo da solicitação. As solicitações GET são limitadas a caracteres de 1500
devido à limitação de comprimento da cadeia de caracteres de parâmetro consulta de verificação ortográfica.
Portanto, as solicitações POST normalmente devem ser feitas, a menos que as cadeias de caracteres curtas estão
sendo ortografia verificada.
No aplicativo de exemplo, o SpellCheckTextAsync método invoca o processo de verificação ortográfica:

public async Task<SpellCheckResult> SpellCheckTextAsync(string text)


{
string requestUri = GenerateRequestUri(Constants.BingSpellCheckEndpoint, text, SpellCheckMode.Spell);
var response = await SendRequestAsync(requestUri);
var spellCheckResults = JsonConvert.DeserializeObject<SpellCheckResult>(response);
return spellCheckResults;
}

O SpellCheckTextAsync método gera um URI de solicitação e, em seguida, envia a solicitação para o SpellCheck
API, que retorna uma resposta JSON que contém o resultado. A resposta JSON é desserializada, com o resultado
retornado para o método de chamada para exibição.
Configurar a verificação ortográfica
O processo de verificação ortográfica pode ser configurado especificando parâmetros de consulta HTTP:

string GenerateRequestUri(string spellCheckEndpoint, string text, SpellCheckMode mode)


{
string requestUri = spellCheckEndpoint;
requestUri += string.Format("?text={0}", text); // text to spell check
requestUri += string.Format("&mode={0}", mode.ToString().ToLower()); // spellcheck mode - proof or spell
return requestUri;
}

Esse método define o texto a ser ortografia verificada e o modo de verificação ortográfica.
Para obter mais informações sobre a API de REST de verificação ortográfica de Bing, consulte referência do API
de verificação ortográfica v7.
Enviar a solicitação
O SendRequestAsync método faz a solicitação GET para a API de REST de verificação ortográfica de Bing e retorna
a resposta:

async Task<string> SendRequestAsync(string url)


{
var response = await httpClient.GetAsync(url);
return await response.Content.ReadAsStringAsync();
}

Esse método envia a solicitação GET para o SpellCheck API, com a URL da solicitação especifica o texto a ser
traduzido e o modo de verificação ortográfica. A resposta é, em seguida, ler e retornada para o método de
chamada.
O SpellCheck API enviará o código de status HTTP 200 (Okey) em resposta, fornecida que a solicitação é válida,
que indica que a solicitação foi bem-sucedida e que as informações solicitadas estão na resposta. Para obter uma
lista de objetos de resposta, consulte os objetos de resposta.
Processar a resposta
A resposta da API é retornada em formato JSON. Os dados JSON a seguir mostram a mensagem de resposta
para o texto digitado incorretamente Go shappin tommorow :
{
"_type":"SpellCheck",
"flaggedTokens":[
{
"offset":3,
"token":"shappin",
"type":"UnknownToken",
"suggestions":[
{
"suggestion":"shopping",
"score":1
}
]
},
{
"offset":11,
"token":"tommorow",
"type":"UnknownToken",
"suggestions":[
{
"suggestion":"tomorrow",
"score":1
}
]
}
],
"correctionType":"High"
}

O flaggedTokens matriz contém uma matriz de palavras no texto que foram marcados como não sendo escrito
corretamente ou são gramaticalmente incorreto. A matriz será vazia se nenhum ortografia ou erros gramaticais
forem encontrados. As marcas dentro da matriz são:
offset – um deslocamento de base zero desde o início da cadeia de caracteres de texto para a palavra que foi
marcado.
token – a palavra na cadeia de texto que não está escrita corretamente ou está gramaticalmente incorreto.
type – o tipo de erro que causou a palavra a ser sinalizado. Há dois valores possíveis – RepeatedToken e
UnknownToken .
suggestions – uma matriz de palavras que corrigirá o erro de ortografia ou gramática. A matriz é composta de
um suggestion e um score , que indica o nível de confiança de que a correção sugerida é correta.

No aplicativo de exemplo, a resposta JSON é desserializada em um SpellCheckResult instância, com o resultado


retornado para o método de chamada para exibição. O seguinte exemplo de código mostra como o
SpellCheckResult instância é processada para exibição:

var spellCheckResult = await bingSpellCheckService.SpellCheckTextAsync(TodoItem.Name);


foreach (var flaggedToken in spellCheckResult.FlaggedTokens)
{
TodoItem.Name = TodoItem.Name.Replace(flaggedToken.Token,
flaggedToken.Suggestions.FirstOrDefault().Suggestion);
}

Esse código itera por meio de FlaggedTokens coleta e substitui qualquer incorretas ou gramaticalmente incorretas
palavras no texto de origem com a primeira sugestão. As capturas de tela a seguir mostram antes e após a
verificação ortográfica:
NOTE
O exemplo acima usa Replace para manter a simplicidade, mas em uma grande quantidade de texto ele poderia substituir
o token errado. A API fornece a offset valor que deve ser usado em aplicativos de produção para identificar o local
correto no texto de origem para executar uma atualização.

Resumo
Este artigo explicou como usar a API de REST de verificação ortográfica de Bing para corrigir erros de ortografia
em um aplicativo xamarin. Forms. Verificação ortográfica do Bing executa ortográfica contextual para texto,
fornecendo sugestões embutido para palavras incorretas.

Links relacionados
Documentação de verificação ortográfica do Bing
Consumir um serviço Web RESTful
Serviços Cognitivos de tarefas pendentes (amostra)
Referência do API de verificação ortográfica do Bing v7
Tradução de texto usando a API do Translator
12/04/2019 • 8 minutes to read

baixar o exemplo
API do Microsoft Translator pode ser usado para converter fala e texto por meio de uma API REST. Este artigo
explica como usar a API de texto do Microsoft Translator para traduzir o texto de um idioma para outro em um
aplicativo xamarin. Forms.

Visão geral
A API de tradução tem dois componentes:
Uma tradução de texto da API REST para traduzir o texto de um idioma para o texto de outro idioma. A API
automaticamente detecta o idioma do texto que foi enviado antes de converter.
Uma tradução de fala a API REST para transcrição de fala de um idioma no texto de outro idioma. A API
também integra os recursos de texto em fala para falar o texto traduzido novamente.
Este artigo se concentra na tradução de texto de um idioma para outro usando a API de tradução de texto.
Uma chave de API deve ser obtida para usar a API de tradução de texto. Isso pode ser obtido no como se
inscrever para a API do Microsoft Translator texto.
Para obter mais informações sobre a API de texto do Microsoft Translator, consulte documentação da API do
Translator texto.

Autenticação
Todas as solicitações feitas para a API de tradução de texto requer um token de acesso do JSON Web Token
(JWT), que pode ser obtido do serviço de token dos serviços cognitivos
https://api.cognitive.microsoft.com/sts/v1.0/issueToken . Um token pode ser obtido, fazendo uma solicitação
POST para o serviço de token, especificando um Ocp-Apim-Subscription-Key cabeçalho que contém a chave de
API como seu valor.
O exemplo de código a seguir mostra como solicitar um acesso de token do serviço de token:

public AuthenticationService(string apiKey)


{
subscriptionKey = apiKey;
httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", apiKey);
}
...
async Task<string> FetchTokenAsync(string fetchUri)
{
UriBuilder uriBuilder = new UriBuilder(fetchUri);
uriBuilder.Path += "/issueToken";
var result = await httpClient.PostAsync(uriBuilder.Uri.AbsoluteUri, null);
return await result.Content.ReadAsStringAsync();
}

O token de acesso retornado, o que é um texto Base64, tem uma hora de expiração de 10 minutos. Portanto, o
aplicativo de exemplo renova o token de acesso a cada 9 minutos.
O token de acesso deve ser especificado em cada API de tradução de texto chamada como um Authorization
cabeçalho prefixado com a cadeia de caracteres Bearer , conforme mostrado no exemplo de código a seguir:

httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken);

Para obter mais informações sobre o serviço de token de serviços cognitivos, consulte API de Token de
autenticação.

Executar tradução de texto


Tradução de texto pode ser obtida por meio de uma solicitação GET para o translate API em
https://api.microsofttranslator.com/v2/http.svc/translate . No aplicativo de exemplo, o TranslateTextAsync
método invoca o processo de tradução de texto:

public async Task<string> TranslateTextAsync(string text)


{
...
string requestUri = GenerateRequestUri(Constants.TextTranslatorEndpoint, text, "en", "de");
string accessToken = authenticationService.GetAccessToken();
var response = await SendRequestAsync(requestUri, accessToken);
var xml = XDocument.Parse(response);
return xml.Root.Value;
}

O TranslateTextAsync método gera um URI de solicitação e recupera um token de acesso ao serviço de token. A
solicitação de tradução de texto é enviada para o translate API, que retorna uma resposta em XML que contém
o resultado. A resposta XML é analisada, e o resultado da conversão é retornado para o método de chamada para
exibição.
Para obter mais informações sobre as APIs de REST de tradução de texto, consulte API do Microsoft Translator
texto.
Configurando a tradução de texto
O processo de tradução de texto pode ser configurado especificando parâmetros de consulta HTTP:

string GenerateRequestUri(string endpoint, string text, string to)


{
string requestUri = endpoint;
requestUri += string.Format("?text={0}", Uri.EscapeUriString(text));
requestUri += string.Format("&to={0}", to);
return requestUri;
}

Esse método define o texto a ser convertido e o idioma para traduzir o texto a ser. Para obter uma lista dos
idiomas com suporte pelo Microsoft Translator, consulte idiomas com suporte na API do Microsoft Translator
texto.

NOTE
Se um aplicativo precisa saber qual idioma o texto é, o Detect API pode ser chamada para detectar o idioma da cadeia de
caracteres de texto.

Enviar a solicitação
O SendRequestAsync método faz a solicitação GET para a API de REST de tradução de texto e retorna a resposta:
async Task<string> SendRequestAsync(string url, string bearerToken)
{
if (httpClient == null)
{
httpClient = new HttpClient();
}
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken);

var response = await httpClient.GetAsync(url);


return await response.Content.ReadAsStringAsync();
}

Esse método cria a solicitação GET, adicionando o token de acesso para o Authorization cabeçalho, prefixado
com a cadeia de caracteres Bearer . A solicitação GET é enviada para o translate API, com a URL da solicitação
especifica o texto a ser traduzido e o idioma para traduzir o texto a ser. A resposta é, em seguida, ler e retornada
para o método de chamada.
O translate API enviará o código de status HTTP 200 (Okey) em resposta, fornecida que a solicitação é válida,
que indica que a solicitação foi bem-sucedida e que as informações solicitadas estão na resposta. Para obter uma
lista de possíveis respostas de erro, consulte as mensagens de resposta em obter traduzir.
Processar a resposta
A resposta da API é retornada em formato XML. Os dados XML a seguir mostram uma mensagem de resposta
bem-sucedida típico:

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">Morgen kaufen gehen ein</string>

No aplicativo de exemplo, a resposta XML é analisada em um XDocument instância, com o valor de raiz XML que
está sendo retornado para o método de chamada para exibição, conforme mostrado nas capturas de tela seguir:
Resumo
Este artigo explicou como usar a API de texto do Microsoft Translator para traduzir o texto de um idioma para o
texto de outro idioma em um aplicativo xamarin. Forms. Além de traduzir o texto, API do Microsoft Translator
pode transcrever também fala de um idioma no texto de outro idioma.

Links relacionados
Documentação de API de texto do tradutor.
Consumir um serviço Web RESTful
Serviços Cognitivos de tarefas pendentes (amostra)
API de texto do Microsoft Translator.
Reconhecimento de emoções usando a API de
detecção facial
12/04/2019 • 10 minutes to read

baixar o exemplo
API de detecção facial usa uma expressão facial em uma imagem como uma entrada e retorna dados que
incluem os níveis de confiança entre um conjunto de emoções para cada face na imagem. Este artigo explica
como usar a API de detecção facial para reconhecer emoções, a taxa de um aplicativo xamarin. Forms.

Visão geral
API de detecção facial pode executar a detecção de emoções para detectar raiva, desdém, aversão, medo,
felicidade, indiferença, tristeza e surpresa, em uma expressão facial. Essas emoções são universalmente e entre
culturas comunicadas por meio das mesmas expressões faciais básicas. Bem como retornar um resultado de
emoções para uma expressão facial, API de detecção facial pode também retorna uma caixa delimitadora para
faces detectadas. Observe que uma chave de API deve ser obtida para usar a API de detecção facial. Isso pode ser
obtido no Experimente os serviços Cognitivos.
Reconhecimento de emoções pode ser executado por meio de uma biblioteca de cliente e por meio da API REST.
Este artigo se concentra em fazer o reconhecimento de emoção por meio da API REST. Para obter mais
informações sobre a API REST, consulte API REST de detecção facial.
API de detecção facial também pode ser usada para reconhecer as expressões faciais das pessoas em vídeo e
pode retornar um resumo de suas emoções. Para obter mais informações, consulte como analisar vídeos em
tempo real.
Para obter mais informações sobre a API de detecção facial, consulte API de detecção facial.

Autenticação
Todas as solicitações feitas para a API de detecção facial requer uma chave de API que deve ser especificada como
o valor da Ocp-Apim-Subscription-Key cabeçalho. O exemplo de código a seguir mostra como adicionar a chave de
API para o Ocp-Apim-Subscription-Key cabeçalho de uma solicitação:

public FaceRecognitionService()
{
_client = new HttpClient();
_client.DefaultRequestHeaders.Add("ocp-apim-subscription-key", Constants.FaceApiKey);
}

Falha ao passar uma chave de API válida para a API de detecção facial resultará em um erro de 401 resposta.

Executar o reconhecimento de emoções


Reconhecimento de emoções é executado fazendo uma solicitação POST que contém uma imagem para o
detect API em https://[location].api.cognitive.microsoft.com/face/v1.0 , onde [location]] é a região que
você usou para obter sua chave de API. Os parâmetros de solicitação opcionais são:
returnFaceId – Se é necessário retornar faceIds as faces detectadas. O valor padrão é true .
returnFaceLandmarks – Se é necessário retornar marcos faciais as faces detectadas. O valor padrão é false .
returnFaceAttributes – Se deseja analisar e de retorno especificada de um ou mais atributos faciais. Atributos
faciais com suporte incluem age , gender , headPose , smile , facialHair , glasses , emotion , hair , makeup ,
occlusion , accessories , blur , exposure , e noise . Observe que a análise de atributo de face tem custo
computacional e de tempo adicional.
Conteúdo da imagem deve ser colocado no corpo da solicitação POST como uma URL ou dados binários.

NOTE
Formatos de arquivo de imagem com suporte são PNG, JPEG, GIF e BMP, e o tamanho de arquivo permitido é de 1KB a
4MB.

No aplicativo de exemplo, o processo de reconhecimento de emoções é invocado chamando o DetectAsync


método:

Face[] faces = await _faceRecognitionService.DetectAsync(photoStream, true, false, new FaceAttributeType[] {


FaceAttributeType.Emotion });

Esta chamada de método Especifica o fluxo que contém os dados da imagem, que devem ser retornadas faceIds,
que não devem ser retornados marcos faciais e que a emoção da imagem deve ser analisada. Ela também
especifica que os resultados serão retornados como uma matriz de Face objetos. Por sua vez, o DetectAsync
método invoca o detect API REST que executa o reconhecimento de emoções:

public async Task<Face[]> DetectAsync(Stream imageStream, bool returnFaceId, bool returnFaceLandmarks,


IEnumerable<FaceAttributeType> returnFaceAttributes)
{
var requestUrl =
$"{Constants.FaceEndpoint}/detect?returnFaceId={returnFaceId}" +
"&returnFaceLandmarks={returnFaceLandmarks}" +
"&returnFaceAttributes={GetAttributeString(returnFaceAttributes)}";
return await SendRequestAsync<Stream, Face[]>(HttpMethod.Post, requestUrl, imageStream);
}

Esse método gera um URI de solicitação e, em seguida, envia a solicitação para o detect API por meio de
SendRequestAsync método.

NOTE
Você deve usar a mesma região em suas chamadas de API de detecção facial que você usou para obter as chaves de
assinatura. Por exemplo, se você adquiriu suas chaves de assinatura do westus região, o ponto de extremidade de
detecção de face será https://westus.api.cognitive.microsoft.com/face/v1.0/detect .

Enviar a solicitação
O SendRequestAsync método faz a solicitação POST para a API de detecção facial e retorna o resultado como um
Face matriz:
async Task<TResponse> SendRequestAsync<TRequest, TResponse>(HttpMethod httpMethod, string requestUrl, TRequest
requestBody)
{
var request = new HttpRequestMessage(httpMethod, Constants.FaceEndpoint);
request.RequestUri = new Uri(requestUrl);
if (requestBody != null)
{
if (requestBody is Stream)
{
request.Content = new StreamContent(requestBody as Stream);
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
}
else
{
// If the image is supplied via a URL
request.Content = new StringContent(JsonConvert.SerializeObject(requestBody, s_settings), Encoding.UTF8,
"application/json");
}
}

HttpResponseMessage responseMessage = await _client.SendAsync(request);


if (responseMessage.IsSuccessStatusCode)
{
string responseContent = null;
if (responseMessage.Content != null)
{
responseContent = await responseMessage.Content.ReadAsStringAsync();
}
if (!string.IsNullOrWhiteSpace(responseContent))
{
return JsonConvert.DeserializeObject<TResponse>(responseContent, s_settings);
}
return default(TResponse);
}
else
{
...
}
return default(TResponse);
}

Se a imagem é fornecida por meio de um fluxo, o método compila a solicitação de POSTAGEM envolvendo o
fluxo de imagem em um StreamContent instância, que fornece conteúdo HTTP com base em um fluxo. Como
alternativa, se a imagem é fornecida por meio de uma URL, o método se baseia a solicitação de POSTAGEM
envolvendo a URL em um StringContent instância, que fornece conteúdo HTTP com base em uma cadeia de
caracteres.
A solicitação POST é enviada para detect API. A resposta é ler, desserializada e retornada para o método de
chamada.
O detect API enviará o código de status HTTP 200 (Okey) em resposta, fornecida que a solicitação é válida, que
indica que a solicitação foi bem-sucedida e que as informações solicitadas estão na resposta. Para obter uma lista
de possíveis respostas de erro, consulte API REST de detecção facial.
Processar a resposta
A resposta da API é retornada em formato JSON. Os dados JSON a seguir mostram uma mensagem de resposta
bem-sucedida típico que fornece os dados solicitados pelo aplicativo de exemplo:
[
{
"faceId":"8a1a80fe-1027-48cf-a7f0-e61c0f005051",
"faceRectangle":{
"top":192,
"left":164,
"width":339,
"height":339
},
"faceAttributes":{
"emotion":{
"anger":0.0,
"contempt":0.0,
"disgust":0.0,
"fear":0.0,
"happiness":1.0,
"neutral":0.0,
"sadness":0.0,
"surprise":0.0
}
}
}
]

Uma mensagem de resposta bem-sucedida consiste em uma matriz de entradas de face, classificados pelo
tamanho do retângulo facial em ordem decrescente, enquanto uma resposta vazia não indica que nenhuma face
detectada. Cada reconhecido face inclui uma série de atributos de face opcional, que são especificados pelo
returnFaceAttributes argumento para o DetectAsync método.

No aplicativo de exemplo, a resposta JSON é desserializada em uma matriz de Face objetos. Ao interpretar os
resultados da API de detecção facial, a emoção detectada deve ser interpretada como a emoção com a pontuação
mais alta, como as pontuações são normalizadas para soma a um. Portanto, o aplicativo de exemplo exibe a
emoção reconhecida com a pontuação mais alta para o rosto detectado maior na imagem. Isso é obtido com o
código a seguir:

emotionResultLabel.Text = faces.FirstOrDefault().FaceAttributes.Emotion.ToRankedList().FirstOrDefault().Key;

Captura de tela a seguir mostra o resultado do processo de reconhecimento de emoções no aplicativo de


exemplo:
Resumo
Este artigo explicou como usar a API de detecção facial para reconhecer emoções, a taxa de um aplicativo
xamarin. Forms. API de detecção facial usa uma expressão facial em uma imagem como uma entrada e retorna
dados que inclui a confiança entre um conjunto de emoções para cada face na imagem.

Links relacionados
API de detecção facial.
Serviços Cognitivos de tarefas pendentes (amostra)
REST API de detecção facial
Teste e implantação do Xamarin.Forms
12/04/2019 • 2 minutes to read • Edit Online

Como publicar aplicativos iOS


Os aplicativos iOS podem ser distribuídos por meio da App Store da Apple, internamente, e por meio de canais de
ad-hoc.

Como publicar aplicativos Android


Aplicativos Android podem ser distribuídos por canais como email, um servidor Web privado, Google Play ou pela
Amazon App Store para Android.

Publicando aplicativos da Plataforma Universal do Windows


Os aplicativos UWP podem ser distribuídos por meio da Microsoft Store, carregando paralelamente o pacote do
aplicativo diretamente a um dispositivo, ou por Instalação Web.

Como publicar aplicativos Mac


Os aplicativos do Mac podem ser distribuídos por meio da Mac App Store ou diretamente.

Desempenho
Há muitas técnicas para aumentar o desempenho de aplicativos Xamarin.Forms. Coletivamente, essas técnicas
podem reduzir de forma considerável a quantidade de trabalho que está sendo executado por uma CPU e a
quantidade de memória consumida por um aplicativo.

Testes automatizados no Visual Studio App Center


O App Center Test é um serviço de automação de teste para aplicativos móveis nativos e híbridos, também
conhecido como Test Cloud.
Visão geral da distribuição de aplicativos
Xamarin.iOS
12/04/2019 • 5 minutes to read • Edit Online

Este documento fornece uma visão geral das técnicas de distribuição disponíveis para aplicativos Xamarin.iOS e
funciona como um ponteiro para documentos mais detalhados sobre o tópico.
Depois que um aplicativo Xamarin.iOS for desenvolvido, a próxima etapa no ciclo de vida de desenvolvimento do
software é distribuir o aplicativo para os usuários, conforme mostrado na seção destacada do diagrama abaixo:

Apple fornece as seguintes maneiras de distribuir um aplicativo iOS, que tem suporte com Xamarin.iOS:
1. App Store
2. Interno (Enterprise)
3. Ad Hoc
Todos esses cenários exigem que os aplicativos sejam provisionados usando o perfil de provisionamento
apropriado. Perfis de provisionamento são arquivos que contêm informações de assinatura de código, bem como a
identidade do aplicativo e o mecanismo de distribuição desejado. Para a distribuição fora da App Store, também há
informações sobre em quais dispositivos o aplicativo pode ser implantado.

Distribuição da App Store


IMPORTANT
A Apple indicou que, a partir de julho de 2018, todos os aplicativos e atualizações enviados à App Store deverão ter sido
criados com o SDK do iOS 11 e ser compatíveis com à exibição do iPhone X.

Essa é a maneira principal que aplicativos iOS são distribuídos para consumidores em dispositivos iOS. Todos os
aplicativos enviados à App Store exigem aprovação da Apple.
Os aplicativos são enviados à App Store por meio de um portal chamado iTunes Connect. O guia Configurar seu
Aplicativo no iTunes Connect fornece mais informações sobre como configurar e usar este portal para preparar
um aplicativo Xamarin.iOS para publicação na App Store.
É importante observar que somente os desenvolvedores que pertencem ao Programa de Desenvolvedores da
Apple têm acesso ao iTunes Connect. Membros do Programa de Desenvolvedores Corporativos da Apple
não tem acesso.
Para obter mais informações, acesse o guia de Distribuição da App Store.

Distribuição Interna
Às vezes chamada de Distribuição Corporativa, a distribuição interna permite que membros do Programa de
Desenvolvedores Corporativos da Apple distribuam aplicativos internamente para outros membros da mesma
organização. A distribuição interna tem as vantagens de não exigir uma análise da App Store e não ter nenhum
limite de número de dispositivos nos quais um aplicativo pode ser instalado. No entanto, é importante observar
que membros do Programa de Desenvolvedor Corporativo da Apple não têm acesso ao iTunes Connect e,
portanto, o licenciado é responsável por distribuir o aplicativo.
Para obter mais informações sobre como configurar e distribuir um aplicativo internamente, consulte o guia de
Distribuição Interna.

Distribuição Ad Hoc
Aplicativos Xamarin.iOS podem ser testados pelo usuário por meio da distribuição ad-hoc, que está disponível no
Programa de Desenvolvedores da Apple e pelo Programa de Desenvolvedor Corporativo da Apple,
permitindo que até 100 dispositivos iOS sejam testados. O melhor caso de uso para a distribuição ad hoc é
distribuição dentro de uma empresa quando iTunes Connect não for uma opção.
Para obter mais informações sobre como configurar e distribuir um aplicativo internamente, consulte o Guia de
Distribuição Ad Hoc.

Resumo
Este artigo forneceu uma breve visão geral dos mecanismos de distribuição que estão disponíveis para aplicativos
Xamarin.iOS. Ele introduziu a iTunes App Store, implantação Ad Hoc e Interna, além de ter fornecido links para
obter informações mais detalhadas.

Links relacionados
Distribuição da App Store
Como configurar um aplicativo no iTunes Connect
Publicando na App Store
Distribuição interna
Distribuição Ad Hoc
O arquivo iTunesMetadata.plist
Suporte a IPA
Solução de problemas
Publicando um aplicativo
12/04/2019 • 6 minutes to read • Edit Online

Quando um bom aplicativo é criado, as pessoas querem usá-lo. Esta seção aborda as etapas envolvidas com a
distribuição pública de um aplicativo criado com o Xamarin.Android por meio de canais, como email, um servidor
Web particular, Google Play ou a Amazon App Store para Android.

Visão geral
A etapa final no desenvolvimento de um aplicativo Xamarin.Android é publicar o aplicativo. A publicação é o
processo de compilação de um aplicativo Xamarin.Android para que ele esteja pronto para que os usuários
instalem em seus dispositivos e envolve duas tarefas essenciais:
Preparação para publicação – Uma versão de lançamento do aplicativo é criada que pode ser implantada
em dispositivos Android (consulte Preparar um Aplicativo para a Lançamento para obter mais informações
sobre a preparação do lançamento).
Distribuição – A versão de um aplicativo é disponibilizada por meio de um ou mais dos vários canais de
distribuição.
O diagrama a seguir ilustra as etapas envolvidas na publicação de um aplicativo Xamarin.Android:

Como pode ser visto no diagrama acima, a preparação é a mesma, independentemente do método de distribuição
usado. Há várias maneiras que um aplicativo Android pode ser liberado para usuários:
Por meio de um site – Um aplicativo Xamarin.Android pode ser disponibilidade para download em um site,
do qual os usuários podem, em seguida, instalar o aplicativo ao clicar em um link.
Por email – É possível que os usuários instalem um aplicativo Xamarin.Android pelo email. O aplicativo será
instalado quando o anexo for aberto com um dispositivo Android.
Por meio de um mercado – Há vários mercados de aplicativos que existem para distribuição, como Google
Play ou Amazon App Store for Android.
Usar um marketplace estabelecido é a maneira mais comum para publicar um aplicativo, pois ele fornece um
alcance mais amplo do mercado e maior controle sobre a distribuição. No entanto, a publicação de um aplicativo
por meio de um marketplace requer esforço adicional.
Vários canais podem distribuir um aplicativo Xamarin.Android simultaneamente. Por exemplo, um aplicativo pode
ser publicado no Google Play, Amazon App Store para o Android e também ser baixado de um servidor Web.
Os outros dois métodos de distribuição (download ou email) são mais úteis para um subconjunto controlado de
usuários, como um ambiente corporativo ou um aplicativo destina-se apenas um conjunto bem específico ou
pequeno de usuários. Distribuição de email e de servidor também são modelos mais simples de publicação,
exigindo menos preparativos para publicar um aplicativo.
O Programa de Distribuição de Aplicativos Móveis da Amazon permite que desenvolvedores de aplicativos
móveis distribuam e vendam seus aplicativos no Amazon. Os usuários podem descobrir e comprar aplicativos em
seus dispositivos com Android ao usar o aplicativo Amazon App Store. Uma captura de tela do Amazon App Store
em execução em um dispositivo Android aparece abaixo:
O Google Play é indiscutivelmente o marketplace mais abrangente e popular para aplicativos Android. O Google
Play permite aos usuários descobrir, baixar, classificar e comprar aplicativos ao clicar em um único ícone no
dispositivo ou no computador. O Google Play também fornece ferramentas para auxiliar na análise de vendas e
tendências do mercado e para controlar quais dispositivos e usuários podem baixar um aplicativo. Uma captura de
tela do Google Play em execução em um dispositivo Android aparece abaixo:
Esta seção mostrou como carregar o aplicativo em lojas como o Google Play, junto com o material promocional
apropriado. Arquivos de expansão APK foram explicados, fornecendo uma visão geral conceitual sobre o que são e
como funcionam. Os serviços de licenciamento do Google também foram descritos. Finalmente, meios
alternativos de distribuição foram apresentados, incluindo o uso de um servidor Web HTTP, distribuição de email
simples e a Amazon App Store para Android.

Links relacionados
HelloWorldPublishing (amostra)
Processo de Compilação
Vinculação
Obter uma chave de API do Google Maps
Assinatura de aplicativos
Como publicar no Google Play
Licenciamento de aplicativos do Google
Android.Play.ExpansionLibrary
Portal de Distribuição de Aplicativo Móvel
Perguntas Frequentes da Distribuição de Aplicativo Móvel da Amazon
Publicando aplicativos Xamarin.Mac na Mac App
Store
12/04/2019 • 3 minutes to read • Edit Online

Visão geral
Os aplicativos Xamarin.Mac podem ser distribuídos de duas maneiras diferentes:
ID de Desenvolvedor – Os aplicativos assinados com uma de ID de Desenvolvedor podem ser distribuídos
fora da App Store, mas são reconhecidos pelo GateKeeper e têm instalação permitida.
Mac App Store – Os aplicativos devem ter um pacote de instalação e o aplicativo e o instalador devem ser
assinados, para o envio para a Mac App Store.
Este documento explica como usar o Visual Studio para Mac e o Xcode para configurar uma conta de
Desenvolvedor da Apple e configurar um projeto Xamarin.Mac para cada tipo de implantação.

Programa de Desenvolvedores do Mac


Ao ingressar no Programa de Desenvolvedores do Mac será oferecido ao desenvolvedor uma opção para
participar como uma Pessoa Física ou como uma Empresa, conforme mostrado na captura de tela abaixo:
Escolha o tipo de registro correto para a sua situação.

NOTE
As escolhas feitas aqui afetarão a forma como algumas telas aparecem ao configurar uma conta de desenvolvedor. As
descrições e capturas de tela neste documento são feitas da perspectiva de uma conta de desenvolvedor de Pessoa Física.
Em uma Empresa, algumas opções só estarão disponíveis para usuários Administradores de Equipe.

Certificados e Identificadores
Esse guia o orienta durante a criação dos Certificados e Identificadores que serão necessários para publicar um
aplicativo Xamarin.Mac.
Criar Perfil de Provisionamento
Esse guia o orienta na criação dos Perfis de Provisionamento que serão necessários para publicar um aplicativo
Xamarin.Mac.
Configuração do aplicativo Mac
Este guia explica como configurar um aplicativo Xamarin.Mac para publicação.
Entrar com a ID de desenvolvedor
Este guia explica como assinar um aplicativo Xamarin.Mac com a ID de Desenvolvedor para publicação.
Pacote para Mac App Store
Este guia ensina como agrupar um aplicativo Xamarin.Mac para publicação na Mac App Store.
Carregar na Mac App Store
Este guia ensina como fazer upload de aplicativos Xamarin.Mac para publicação na Mac App Store.

Links relacionados
Instalação
Amostra do Hello, Mac
ID de Desenvolvedor e GateKeeper
Desempenho do Xamarin.Forms
12/04/2019 • 19 minutes to read • Edit Online

Há muitas técnicas para aumentar o desempenho de aplicativos Xamarin.Forms. Coletivamente, essas técnicas
podem reduzir de forma considerável a quantidade de trabalho que está sendo executado por uma CPU e a
quantidade de memória consumida por um aplicativo. Esse artigo descreve e aborda essas técnicas.

Evolve 2016: Como otimizar o desempenho do aplicativo com o Xamarin.Forms

Visão geral
O baixo desempenho de aplicativo se apresenta de várias maneiras. Ele pode fazer com que o aplicativo pareça
não responder, deixar a rolagem lenta ou reduzir a vida útil da bateria. No entanto, a otimização do desempenho
engloba mais do que apenas a implementação de um código eficiente. A experiência do usuário quanto ao
desempenho do aplicativo também deve ser considerada. Por exemplo, garantir que as operações sejam
executadas sem impedir o usuário de realizar outras atividades pode ajudar a melhorar a experiência do usuário.
Há várias técnicas para aumentar o desempenho, bem como o desempenho percebido, de um aplicativo
Xamarin.Forms. Entre elas estão:
Habilitar o compilador de XAML
Escolher o layout correto
Habilitar a Compactação de Layout
Usar os Renderizadores Rápidos
Reduzir associações desnecessárias
Otimizar o desempenho do layout
Otimizar o desempenho da ListView
Otimizar os recursos de imagem
Reduzir o tamanho da árvore visual
Reduzir o tamanho do dicionário de recursos do aplicativo
Uso do padrão de renderizador personalizado

NOTE
Antes de ler esse artigo, você deve primeiro ler Desempenho de plataforma cruzada, que discute técnicas que não são
específicas a uma plataforma para melhorar o uso de memória e o desempenho de aplicativos criados usando a plataforma
Xamarin.

Habilitar o compilador de XAML


Opcionalmente, XAML pode ser compilado direto na IL (linguagem intermediária) com o compilador XAML
(XAMLC ). XAMLC oferece vários benefícios:
Executa verificação de tempo de compilação de XAML, notificando o usuário de quaisquer erros.
Elimina parte da carga e do tempo de instanciação para elementos XAML.
Ajuda a reduzir o tamanho do arquivo do assembly final não incluindo mais arquivos .XAML.
O XAMLC é desabilitado por padrão para garantir a compatibilidade com versões anteriores. No entanto, pode
ser habilitado nos níveis de classe e do assembly. Para saber mais, consulte Compilação de XAML.

Escolher o layout correto


Um layout que é capaz de exibir vários filhos, mas que tem apenas um único filho, é um desperdício. Por exemplo,
o seguinte exemplo de código mostra um StackLayout com um único filho:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DisplayImage.HomePage">
<ContentPage.Content>
<StackLayout>
<Image Source="waterfront.jpg" />
</StackLayout>
</ContentPage.Content>
</ContentPage>

Isso é um desperdício e o elemento StackLayout deve ser removido, conforme mostrado no exemplo de código a
seguir:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DisplayImage.HomePage">
<ContentPage.Content>
<Image Source="waterfront.jpg" />
</ContentPage.Content>
</ContentPage>

Além disso, não tente reproduzir a aparência de um layout específico usando combinações de outros layouts, pois
isso resulta na execução de cálculos de layout desnecessários. Por exemplo, não tente reproduzir um layout Grid
usando uma combinação de instâncias StackLayout . O código a seguir mostra um exemplo dessa má prática:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Details.HomePage"
Padding="0,20,0,0">
<ContentPage.Content>
<StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Name:" />
<Entry Placeholder="Enter your name" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Age:" />
<Entry Placeholder="Enter your age" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Occupation:" />
<Entry Placeholder="Enter your occupation" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Address:" />
<Entry Placeholder="Enter your address" />
</StackLayout>
</StackLayout>
</ContentPage.Content>
</ContentPage>

Isso é um desperdício porque cálculos de layout desnecessário são executados. Em vez disso, o layout desejado
pode ser melhor obtido usando um Grid , conforme mostra o exemplo de código a seguir:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Details.HomePage"
Padding="0,20,0,0">
<ContentPage.Content>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<Label Text="Name:" />
<Entry Grid.Column="1" Placeholder="Enter your name" />
<Label Grid.Row="1" Text="Age:" />
<Entry Grid.Row="1" Grid.Column="1" Placeholder="Enter your age" />
<Label Grid.Row="2" Text="Occupation:" />
<Entry Grid.Row="2" Grid.Column="1" Placeholder="Enter your occupation" />
<Label Grid.Row="3" Text="Address:" />
<Entry Grid.Row="3" Grid.Column="1" Placeholder="Enter your address" />
</Grid>
</ContentPage.Content>
</ContentPage>

Habilitar a Compactação de Layout


A compactação de layout remove os layouts especificados da árvore visual, em uma tentativa de melhorar o
desempenho de renderização da página. O benefício de desempenho que isso oferece varia dependendo da
complexidade de uma página, da versão do sistema operacional que está sendo usado e do dispositivo no qual o
aplicativo está sendo executado. No entanto, os maiores ganhos de desempenho serão observados em versões
mais antigas. Para obter mais informações, confira Layout de Compactação.

Usar os Renderizadores Rápidos


Os renderizadores rápidos reduzem os custos de renderização e inflação dos controles Xamarin.Forms no
Android nivelando a hierarquia resultante de controle nativo. Isso aprimora o desempenho criando menos
objetos, o que resulta em uma árvore visual menos complexa e em menos uso de memória. Para obter mais
informações, veja Renderizadores Rápidos.

Reduzir associações desnecessárias


Não use associações para conteúdo que pode ser facilmente definido estaticamente. Não há nenhuma vantagem
em associar dados que não precisam ser associados, pois associações não são econômicas. Por exemplo, a
configuração Button.Text = "Accept" tem menos sobrecarga do que a associação Button.Text para uma
propriedade ViewModel string com valor “Aceitar”.

Otimizar o desempenho do layout


O Xamarin.Forms 2 introduziu um mecanismo de layout otimizado que afeta as atualizações de layout. Para obter
o melhor desempenho possível do layout, siga estas diretrizes:
Reduzir a profundidade das hierarquias de layout especificando os valores de propriedade Margin , permitindo
a criação de layouts com menos exibições de encapsulamento. Para saber mais, consulte Margens e
preenchimento.
Ao usar um Grid , tente garantir que o menor número de linhas e colunas possível seja definido para o
tamanho Auto . Cada linha ou coluna dimensionada automaticamente fará o mecanismo de layout realizar
cálculos de layout adicionais. Em vez disso, use linhas e colunas de tamanho fixo, se possível. Como alternativa,
defina linhas e colunas para ocupar uma quantidade proporcional de espaço com o valor de enumeração
GridUnitType.Star , desde que a árvore pai siga essas diretrizes de layout.
Não defina as propriedades VerticalOptions e HorizontalOptions de um layout, a menos que necessário. Os
valores padrão de LayoutOptions.Fill e LayoutOptions.FillAndExpand permitem a melhor otimização de
layout. Alterar essas propriedades tem um custo e consome memória, mesmo ao configurá-las como os
valores padrão.
Evite usar um RelativeLayout sempre que possível. Isso resultará em a CPU precisar realizar
significativamente mais trabalho.
Ao usar um AbsoluteLayout , evite usar a propriedade AbsoluteLayout.AutoSize sempre que possível.
Ao usar um StackLayout , garanta que apenas um filho seja definido como LayoutOptions.Expands . Essa
propriedade garante que o filho especificado ocupe o maior espaço que o StackLayout pode dar a ele e é um
desperdício executar esses cálculos mais de uma vez.
Não chame nenhum dos métodos da classe Layout , uma vez que eles resultam na execução de cálculos de
layout de alto custo. Em vez disso, é provável que o comportamento de layout desejado possa ser obtido
configurando as propriedades TranslationX e TranslationY . Como alternativa, subclasse da classe
Layout<View> para obter o comportamento de layout desejado.
Não atualize nenhuma instância Label com mais frequência do que o necessário, pois a alteração do tamanho
do rótulo pode resultar no recálculo de todo o layout de tela.
Não defina a propriedade Label.VerticalTextAlignment , a menos que necessário.
Defina o LineBreakMode de quaisquer instâncias Label como NoWrap sempre que possível.

Otimizar o desempenho da ListView


Ao usar um controle ListView , há várias experiências de usuário que devem ser otimizadas:
Inicialização – o intervalo de tempo que começa quando o controle é criado e termina quando itens são
mostrados na tela.
Rolagem – a capacidade de rolar pela lista e garantir que a interface do usuário não fique atrasada com
relação a gestos de toque.
Interação para adicionar, excluir e selecionar itens.
O controle ListView requer um aplicativo para fornecer dados e modelos de célula. Como isso é feito terá um
grande impacto sobre o desempenho do controle. Para obter mais informações, consulte Desempenho da
ListView.

Otimizar os recursos de imagem


Exibir recursos de imagem pode aumentar significativamente o volume de memória do aplicativo. Portanto, eles
só devem ser criados quando necessário e devem ser liberados assim que o aplicativo não exigi-los mais. Por
exemplo, se um aplicativo estiver exibindo uma imagem lendo seus dados de um fluxo, certifique-se de que esse
fluxo seja criado somente quando necessário e liberado quando não for mais necessário. Isso pode ser feito
criando o fluxo quando a página é criada ou quando o evento Page.Appearing é acionado e, em seguida,
descartando o fluxo quando o evento Page.Disappearing é acionado.
Ao fazer o download de uma imagem para exibição com o método ImageSource.FromUri , armazene em cache a
imagem baixada garantindo que a propriedade UriImageSource.CachingEnabled esteja definida como true . Para
saber mais, consulte Trabalhando com imagens.
Para saber mais, consulte Otimizar recursos de imagem.
Reduzir o tamanho da árvore visual
Reduzir o número de elementos em uma página tornará a renderização da página mais rápida. Há duas técnicas
principais para realizar essa tarefa. A primeira é ocultar elementos que não estão visíveis. A propriedade
IsVisible de cada elemento determina se o elemento deve fazer parte da árvore visual ou não. Portanto, se um
elemento não estiver visível porque está oculto atrás de outros elementos, remova o elemento ou defina sua
propriedade IsVisible como false .
A segunda técnica é remover elementos desnecessários. Por exemplo, o código a seguir mostra um layout da
página que exibe uma série de elementos Label :

<ContentPage.Content>
<StackLayout>
<StackLayout Padding="20,20,0,0">
<Label Text="Hello" />
</StackLayout>
<StackLayout Padding="20,20,0,0">
<Label Text="Welcome to the App!" />
</StackLayout>
<StackLayout Padding="20,20,0,0">
<Label Text="Downloading Data..." />
</StackLayout>
</StackLayout>
</ContentPage.Content>

O mesmo layout da página poderá ser mantido com uma contagem de elementos reduzida, conforme mostrado
no exemplo de código a seguir:

<ContentPage.Content>
<StackLayout Padding="20,20,0,0" Spacing="25">
<Label Text="Hello" />
<Label Text="Welcome to the App!" />
<Label Text="Downloading Data..." />
</StackLayout>
</ContentPage.Content>

Reduzir o tamanho do dicionário de recursos do aplicativo


Todos os recursos usados em todo o aplicativo devem ser armazenados no dicionário de recursos do aplicativo
para evitar duplicação. Isso ajudará a reduzir a quantidade de XAML que precisa ser analisada em todo o
aplicativo. O seguinte exemplo de código mostra o recurso HeadingLabelStyle , que é usado em todo o aplicativo e
então é definido no dicionário de recursos do aplicativo:

<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Resources.App">
<Application.Resources>
<ResourceDictionary>
<Style x:Key="HeadingLabelStyle" TargetType="Label">
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="FontSize" Value="Large" />
<Setter Property="TextColor" Value="Red" />
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>

No entanto, XAML específico de uma página não deve ser incluído no dicionário de recursos do aplicativo, uma
vez que os recursos então serão analisados na inicialização do aplicativo, em vez de quando exigido por uma
página. Se um recurso for usado por uma página que não seja a página de inicialização, ele deverá ser colocado
no dicionário de recursos para essa página, ajudando, assim, a reduzir o XAML analisado quando o aplicativo é
iniciado. O seguinte exemplo de código mostra o recurso HeadingLabelStyle , que está em apenas uma única
página e então é definido no dicionário de recursos da página:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Test.HomePage"
Padding="0,20,0,0">
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="HeadingLabelStyle" TargetType="Label">
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="FontSize" Value="Large" />
<Setter Property="TextColor" Value="Red" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
...
</ContentPage.Content>
</ContentPage>

Para saber mais sobre os recursos de aplicativo, consulte Working with Styles .

Uso do padrão de renderizador personalizado


A maioria das classes de renderizador expõe o método OnElementChanged , que é chamado quando um controle
personalizado do Xamarin.Forms é criado para renderizar o controle nativo correspondente. Então, classes de
renderizador personalizadas em cada classe de renderizador específica da plataforma substituem esse método
para instanciar e personalizar o controle nativo. O método SetNativeControl é usado para instanciar o controle
nativo e esse método também atribuirá a referência de controle à propriedade Control .
No entanto, em algumas circunstâncias, o método OnElementChanged pode ser chamado várias vezes. Portanto,
para evitar perdas de memória, que podem ter um impacto no desempenho, é necessário ter cuidado ao instanciar
um novo controle nativo. A abordagem a ser usada ao instanciar um novo controle nativo em um renderizador
personalizado é mostrada no exemplo de código a seguir:

protected override void OnElementChanged (ElementChangedEventArgs<NativeListView> e)


{
base.OnElementChanged (e);

if (Control == null) {
// Instantiate the native control
}

if (e.OldElement != null) {
// Unsubscribe from event handlers and cleanup any resources
}

if (e.NewElement != null) {
// Configure the control and subscribe to event handlers
}
}

Um novo controle nativo deve ser instanciado apenas uma vez, quando a propriedade Control é null . O
controle deve ser configurado e os manipuladores de eventos devem ser inscritos apenas quando o renderizador
personalizado for anexado a um novo elemento Xamarin.Forms. Da mesma forma, a inscrição de quaisquer
manipuladores de evento inscritos só deverá ser cancelada quando o elemento ao qual o renderizador está
anexado for alterado. Adotar essa abordagem ajudará a criar um renderizador personalizado de desempenho
eficiente que não sofra perdas de memória.
Para obter mais informações sobre renderizadores personalizados, consulte Como personalizar controles em cada
plataforma.

Resumo
Esse artigo descreveu e discutiu técnicas para aumentar o desempenho dos aplicativos criados Xamarin.Forms.
Coletivamente, essas técnicas podem reduzir de forma considerável a quantidade de trabalho que está sendo
executado por uma CPU e a quantidade de memória consumida por um aplicativo.

Links relacionados
Desempenho de plataforma cruzada
Desempenho de ListView
Renderizadores Rápidos
Compactação de Layout
XamlCompilation
XamlCompilationOptions
Conceitos avançados e recursos internos
12/04/2019 • 2 minutes to read • Edit Online

Resolução de dependência
Este artigo explica como injetar um método de resolução de dependência em xamarin. Forms para que o contêiner
de injeção de dependência do aplicativo tem controle sobre a criação e o tempo de vida de renderizadores
personalizados, efeitos, e DependencyService implementações.

Renderizadores Rápidos
Este artigo apresenta os renderizadores rápidos, o que reduz os custos de renderização de um controle xamarin.
Forms no Android e inflação nivelando a hierarquia de controle nativo resultante.

.NET Standard
Este artigo explica como converter um aplicativo xamarin. Forms para usar o .NET Standard 2.0.
Resolução de dependência no xamarin. Forms
12/04/2019 • 18 minutes to read • Edit Online

baixar o exemplo
Este artigo explica como injetar um método de resolução de dependência no xamarin. Forms para que o
contêiner de injeção de dependência do aplicativo tem controle sobre a criação e o tempo de vida de
renderizadores personalizados, efeitos e implementações de DependencyService. Os exemplos de código neste
artigo são tirados o resolução de dependência usando contêineres exemplo.
No contexto de um aplicativo xamarin. Forms que usa o padrão Model-View -ViewModel (MVVM ), um contêiner
de injeção de dependência pode ser usado para registrar e resolver os modelos de exibição e para registrar os
serviços e injetando-as nos modelos de exibição. Durante a criação do modelo de exibição, o contêiner injeta
quaisquer dependências que são necessárias. Se essas dependências não tem sido criadas, o contêiner cria e
resolve as dependências primeiro. Para obter mais informações sobre injeção de dependência, incluindo exemplos
de injetar dependências nos modelos de exibição, consulte injeção de dependência.
Controle sobre a criação e o tempo de vida dos tipos de projetos de plataforma é feito tradicionalmente por
xamarin. Forms, que usa o Activator.CreateInstance método para criar instâncias de renderizadores
personalizados, efeitos, e DependencyService implementações. Infelizmente, isso limita o controle do
desenvolvedor sobre a criação e o tempo de vida desses tipos, e a capacidade de injetar dependências neles. Esse
comportamento pode ser alterado por injetando um método de resolução de dependência no xamarin. Forms que
controla como tipos serão criados – pelo contêiner de injeção de dependência do aplicativo, ou xamarin. Forms.
No entanto, observe que não há nenhum requisito para injetar um método de resolução de dependência no
xamarin. Forms. Xamarin. Forms continuarão criar e gerenciar o tempo de vida dos tipos de projetos de
plataforma, se um método de resolução de dependência não é inserido.

NOTE
Embora este artigo se concentra em injetando um método de resolução de dependência no xamarin. Forms que resolve
tipos registrados usando um contêiner de injeção de dependência, também é possível inserir um método de resolução de
dependência que usa métodos de fábrica para resolver tipos registrados. Para obter mais informações, consulte o resolução
de dependência usando métodos de fábrica exemplo.

Injetando um método de resolução de dependência


O DependencyResolver classe fornece a capacidade de injetar um método de resolução de dependência no
xamarin. Forms, usando o ResolveUsing método. Em seguida, quando o xamarin. Forms precisa de uma instância
de um tipo específico, o método de resolução de dependência tem a oportunidade de fornecer a instância. Se o
método de resolução de dependência retornar null para um tipo solicitado, xamarin. Forms voltará à tentativa de
criar o tipo de instância usando o Activator.CreateInstance método.
O exemplo a seguir mostra como definir o método de resolução de dependência com o ResolveUsing método:
using Autofac;
using Xamarin.Forms.Internals;
...

public partial class App : Application


{
// IContainer and ContainerBuilder are provided by Autofac
static IContainer container;
static readonly ContainerBuilder builder = new ContainerBuilder();

public App()
{
...
DependencyResolver.ResolveUsing(type => container.IsRegistered(type) ? container.Resolve(type) :
null);
...
}
...
}

Neste exemplo, o método de resolução de dependência é definido como uma expressão lambda que usa o
contêiner de injeção de dependência do Autofac para resolver quaisquer tipos que foram registrados com o
contêiner. Caso contrário, null será retornado, que resultará na tentativa de resolver o tipo de xamarin. Forms.

NOTE
A API usada por um contêiner de injeção de dependência é específica para o contêiner. Os exemplos de código neste artigo
usam o Autofac como um contêiner de injeção de dependência, que fornece o IContainer e ContainerBuilder tipos.
Contêineres de injeção de dependência alternativo igualmente poderia ser usados, mas usam APIs diferentes que são
apresentados aqui.

Observe que não há nenhum requisito para definir o método de resolução de dependência durante a inicialização
do aplicativo. Ele pode ser definido a qualquer momento. A única restrição é que o xamarin. Forms precisa saber
sobre o método de resolução de dependência no momento em que o aplicativo tentar consumir tipos
armazenados no contêiner de injeção de dependência. Portanto, se houver serviços no contêiner de injeção de
dependência que o aplicativo exigirá durante a inicialização, o método de resolução de dependência precisará ser
definido no início do ciclo de vida do aplicativo. Da mesma forma, se o contêiner de injeção de dependência
gerencia a criação e o tempo de vida de um determinado Effect , xamarin. Forms precisará saber sobre o
método de resolução de dependência, antes de tentar criar uma exibição que usa que Effect .

WARNING
Registrar e resolver os tipos com um contêiner de injeção de dependência tem um custo devido ao uso do contêiner de
reflexão para a criação de cada tipo, especialmente se as dependências estão sendo reconstruídas para cada navegação de
página no aplicativo de desempenho. Se houver muitos ou profundas dependências, o custo de criação pode aumentar
significativamente.

Registrando tipos
Tipos devem ser registrados com o contêiner de injeção de dependência, antes que ele possa resolvê-los por meio
do método de resolução de dependência. O exemplo de código a seguir mostra os métodos de registro que o
aplicativo de exemplo expõe no App classe, para o contêiner Autofac:
using Autofac;
using Autofac.Core;
...

public partial class App : Application


{
static IContainer container;
static readonly ContainerBuilder builder = new ContainerBuilder();
...

public static void RegisterType<T>() where T : class


{
builder.RegisterType<T>();
}

public static void RegisterType<TInterface, T>() where TInterface : class where T : class, TInterface
{
builder.RegisterType<T>().As<TInterface>();
}

public static void RegisterTypeWithParameters<T>(Type param1Type, object param1Value, Type param2Type,


string param2Name) where T : class
{
builder.RegisterType<T>()
.WithParameters(new List<Parameter>()
{
new TypedParameter(param1Type, param1Value),
new ResolvedParameter(
(pi, ctx) => pi.ParameterType == param2Type && pi.Name == param2Name,
(pi, ctx) => ctx.Resolve(param2Type))
});
}

public static void RegisterTypeWithParameters<TInterface, T>(Type param1Type, object param1Value, Type


param2Type, string param2Name) where TInterface : class where T : class, TInterface
{
builder.RegisterType<T>()
.WithParameters(new List<Parameter>()
{
new TypedParameter(param1Type, param1Value),
new ResolvedParameter(
(pi, ctx) => pi.ParameterType == param2Type && pi.Name == param2Name,
(pi, ctx) => ctx.Resolve(param2Type))
}).As<TInterface>();
}

public static void BuildContainer()


{
container = builder.Build();
}
...
}

Quando um aplicativo usa um método de resolução de dependência para resolver os tipos de um contêiner, os
registros do tipo normalmente são executados de projetos de plataforma. Isso permite que projetos de plataforma
ao registrar tipos de renderizadores personalizados, efeitos, e DependencyService implementações.
Após o registro de tipo de um projeto de plataforma, o IContainer objeto deve ser criado, o que é realizado
chamando o BuildContainer método. Este método invoca do Autofac Build método no ContainerBuilder
instância, que cria um novo contêiner de injeção de dependência que contém os registros que foram feitos.
Nas seções a seguirem, uma Logger classe que implementa o ILogger interface é injetado em construtores de
classe. O Logger classe implementa o log simples funcionalidade usando o Debug.WriteLine método e é usado
para demonstrar como os serviços possam ser injetados em renderizadores personalizados, efeitos, e
DependencyService implementações.
Registrando renderizadores personalizados
O aplicativo de exemplo inclui uma página que desempenha vídeos da web, cujo código-fonte XAML é mostrado
no exemplo a seguir:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:video="clr-namespace:FormsVideoLibrary"
...>
<video:VideoPlayer Source="https://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4" />
</ContentPage>

O VideoPlayer exibição é implementada em cada plataforma por um VideoPlayerRenderer classe, que fornece a
funcionalidade para reproduzir o vídeo. Para obter mais informações sobre essas classes de renderizador
personalizado, consulte implementando um player de vídeo.
No iOS e Universal Windows Platform (UWP ), o VideoPlayerRenderer classes têm o seguinte construtor, que
exige um ILogger argumento:

public VideoPlayerRenderer(ILogger logger)


{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}

Em todas as plataformas, o tipo de registro com o contêiner de injeção de dependência é executado pela
RegisterTypes método, que é invocado antes da plataforma de carregar o aplicativo com o
LoadApplication(new App()) método. A exemplo a seguir mostra o RegisterTypes método na plataforma iOS:

void RegisterTypes()
{
App.RegisterType<ILogger, Logger>();
App.RegisterType<FormsVideoLibrary.iOS.VideoPlayerRenderer>();
App.BuildContainer();
}

Neste exemplo, o Logger tipo concreto é registrado por meio de um mapeamento em relação a seu tipo de
interface e o VideoPlayerRenderer tipo é registrado diretamente sem um mapeamento de interface. Quando o
usuário navega até a página que contém o VideoPlayer modo de exibição, o método de resolução de dependência
será invocado para resolver o VideoPlayerRenderer tipo de contêiner de injeção de dependência, que também
resolver e injetar o Logger digitar em o VideoPlayerRenderer construtor.
O VideoPlayerRenderer construtor na plataforma Android é um pouco mais complicado, pois exige uma Context
argumento além de ILogger argumento:

public VideoPlayerRenderer(Context context, ILogger logger) : base(context)


{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}

A exemplo a seguir mostra o RegisterTypes método na plataforma Android:


void RegisterTypes()
{
App.RegisterType<ILogger, Logger>();
App.RegisterTypeWithParameters<FormsVideoLibrary.Droid.VideoPlayerRenderer>
(typeof(Android.Content.Context), this, typeof(ILogger), "logger");
App.BuildContainer();
}

Neste exemplo, o App.RegisterTypeWithParameters método registra o VideoPlayerRenderer com o contêiner de


injeção de dependência. O método de registro garante que o MainActivity instância será injetada como o
Context argumento e que o Logger tipo será injetado como o ILogger argumento.

Registrando efeitos
O aplicativo de exemplo inclui uma página que usa um efeito de controle de toque para arrastar BoxView
instâncias em torno da página. O Effect é adicionado para o BoxView usando o seguinte código:

var boxView = new BoxView { ... };


var touchEffect = new TouchEffect();
boxView.Effects.Add(touchEffect);

O TouchEffect classe é um RoutingEffect que é implementada em cada plataforma por um TouchEffect classe
que tem um PlatformEffect . A plataforma TouchEffect classe fornece a funcionalidade de arrastar o BoxView em
torno da página. Para obter mais informações sobre essas classes de efeito, consulte invocação de eventos de
efeitos.
Em todas as plataformas, o TouchEffect classe tem o seguinte construtor, que exige um ILogger argumento:

public TouchEffect(ILogger logger)


{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}

Em todas as plataformas, o tipo de registro com o contêiner de injeção de dependência é executado pela
RegisterTypes método, que é invocado antes da plataforma de carregar o aplicativo com o
LoadApplication(new App()) método. A exemplo a seguir mostra o RegisterTypes método na plataforma Android:

void RegisterTypes()
{
App.RegisterType<ILogger, Logger>();
App.RegisterType<TouchTracking.Droid.TouchEffect>();
App.BuildContainer();
}

Neste exemplo, o Logger tipo concreto é registrado por meio de um mapeamento em relação a seu tipo de
interface e o TouchEffect tipo é registrado diretamente sem um mapeamento de interface. Quando o usuário
navega até a página que contém um BoxView instância que tem o TouchEffect anexado a ele, o método de
resolução de dependência será invocado para resolver a plataforma TouchEffect tipo de dependência contêiner
de injeção, que também resolver e injetar o Logger digitar no TouchEffect construtor.
Registrando as implementações do DependencyService
O aplicativo de exemplo inclui uma página que usa DependencyService implementações em cada plataforma para
permitir que o usuário escolha uma foto da biblioteca de imagens do dispositivo. O IPhotoPicker interface define
a funcionalidade que é implementada pelo DependencyService implementações e é mostrado no exemplo a seguir:
public interface IPhotoPicker
{
Task<Stream> GetImageStreamAsync();
}

Em cada projeto de plataforma, o PhotoPicker classe implementa o IPhotoPicker interface usando as APIs da
plataforma. Para obter mais informações sobre esses serviços de dependência, consulte escolhendo uma foto na
biblioteca de imagens.
No iOS e UWP, o PhotoPicker classes têm o seguinte construtor, que exige um ILogger argumento:

public PhotoPicker(ILogger logger)


{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}

Em todas as plataformas, o tipo de registro com o contêiner de injeção de dependência é executado pela
RegisterTypes método, que é invocado antes da plataforma de carregar o aplicativo com o
LoadApplication(new App()) método. A exemplo a seguir mostra o RegisterTypes método na UWP:

void RegisterTypes()
{
DIContainerDemo.App.RegisterType<ILogger, Logger>();
DIContainerDemo.App.RegisterType<IPhotoPicker, Services.UWP.PhotoPicker>();
DIContainerDemo.App.BuildContainer();
}

Neste exemplo, o Logger tipo concreto é registrado por meio de um mapeamento em relação a seu tipo de
interface e o PhotoPicker tipo também é registrado por meio de um mapeamento de interface.
O PhotoPicker construtor na plataforma Android é um pouco mais complicado, pois exige uma Context
argumento além de ILogger argumento:

public PhotoPicker(Context context, ILogger logger)


{
_context = context ?? throw new ArgumentNullException(nameof(context));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}

A exemplo a seguir mostra o RegisterTypes método na plataforma Android:

void RegisterTypes()
{
App.RegisterType<ILogger, Logger>();
App.RegisterTypeWithParameters<IPhotoPicker, Services.Droid.PhotoPicker>(typeof(Android.Content.Context),
this, typeof(ILogger), "logger");
App.BuildContainer();
}

Neste exemplo, o App.RegisterTypeWithParameters método registra o PhotoPicker com o contêiner de injeção de


dependência. O método de registro garante que o MainActivity instância será injetada como o Context
argumento e que o Logger tipo será injetado como o ILogger argumento.
Quando o usuário navega para a página de separação de fotos e optar por selecionar uma foto, o
OnSelectPhotoButtonClicked manipulador é executado:
async void OnSelectPhotoButtonClicked(object sender, EventArgs e)
{
...
var photoPickerService = DependencyService.Resolve<IPhotoPicker>();
var stream = await photoPickerService.GetImageStreamAsync();
if (stream != null)
{
image.Source = ImageSource.FromStream(() => stream);
}
...
}

Quando o DependencyService.Resolve<T> método é invocado, o método de resolução de dependência será


invocado para resolver o PhotoPicker tipo de contêiner de injeção de dependência, que também resolver e injetar
o Logger tipo para o PhotoPicker construtor.

NOTE
O Resolve<T> método deve ser usado durante a resolução de um tipo de contêiner de injeção de dependência do
aplicativo por meio de DependencyService .

Links relacionados
Resolução de dependência usando contêineres (amostra)
Injeção de dependência
Implementar um player de vídeo
Invocação de eventos de efeitos
Escolhendo uma foto na biblioteca de imagens
Renderizadores de xamarin. Forms Fast
12/04/2019 • 3 minutes to read • Edit Online

Este artigo apresenta os renderizadores rápidos (adicionados no xamarin. Forms 2.4 ), que reduz os custos de
renderização de um controle xamarin. Forms no Android e inflação nivelando a hierarquia de controle nativo
resultante.
Tradicionalmente, a maioria dos renderizadores de controle original no Android é compostas de dois modos de
exibição:
Controlar um nativo, como uma Button ou TextView .
Um contêiner ViewGroup que lida com algumas das outras tarefas, tratamento de gesto e o trabalho de layout.

No entanto, essa abordagem tem uma implicação de desempenho que dois modos de exibição são criados para
cada controle lógico, o que resulta em uma árvore visual mais complexa que exige mais memória e mais
processamento para renderizar na tela.
Os renderizadores rápidos reduzem os custos de renderização de um controle xamarin. Forms e inflação em uma
única exibição. Portanto, em vez de criar dois modos de exibição e adicioná-los à árvore de exibição, somente um
é criado. Isso melhora o desempenho criando menos objetos, que por sua vez, significa que uma árvore de
exibição menos complexa, e menos uso de memória (que também resulta em menos pausas na coleta de lixo).
Os renderizadores rápidos estão disponíveis para os seguintes controles no xamarin. Forms 2.4 no Android:
Button
Image
Label
Frame

Funcionalmente, esses renderizadores rápidos não são diferentes para os renderizadores originais. No entanto,
eles atualmente são experimentais e só pode ser usados, adicionando a seguinte linha de código para seus
MainActivity classe antes de chamar Forms.Init :

Forms.SetFlags("FastRenderers_Experimental");

NOTE
Os renderizadores rápidos só são aplicáveis para o aplicativo compat Android back-end, portanto, essa configuração será
ignorada em atividades de compatibilidade de aplicativo pré.

Melhorias de desempenho irá variar para cada aplicativo, dependendo da complexidade do layout. Por exemplo,
melhorias de desempenho de x2 são possíveis ao rolar por um ListView que contém milhares de linhas de
dados, em que as células em cada linha são compostas de controles que usam os renderizadores rápidos, o que
resulta em visivelmente rolagem mais suave.
Links relacionados
Renderizadores personalizados
2.0 suporte ao .NET standard no xamarin. Forms
12/04/2019 • 2 minutes to read • Edit Online

Este artigo explica como converter um aplicativo xamarin. Forms para usar o .NET Standard 2.0.
.NET standard é uma especificação de APIs .NET que devem estar disponíveis em todas as implementações do
.NET. Ele torna mais fácil de compartilhar código entre aplicativos da área de trabalho, aplicativos móveis e jogos e
serviços de nuvem, reunindo APIs idêntico para as plataformas diferentes. Para obter informações sobre as
plataformas com suporte pelo .NET Standard, consulte suporte à implementação do .NET.
Bibliotecas do .NET standard são a substituição para Portable Class Libraries (PCL ). No entanto, uma biblioteca
direcionada ao .NET Standard ainda é uma PCL e é conhecida como uma PCL baseada no .NET Standard.
Determinados perfis de PCL são mapeados para versões do .NET Standard e para os perfis que têm um
mapeamento, os tipos de dois biblioteca poderão fazer referência uns aos outros. Para obter mais informações,
consulte compatibilidade com PCL.
2.4 de xamarin. Forms permite que os aplicativos xamarin. Forms destino .NET Standard 2.0, substituindo o PCL
com uma biblioteca .NET Standard 2.0. Isso pode ser feito da seguinte maneira:
Certifique-se .NET Core 2.0 está instalado.
Atualize a solução do xamarin. Forms para usar o xamarin. Forms 2.4 ou superior.
Adicione uma biblioteca .NET Standard à solução, que tem como alvo o .NET Standard 2.0.
Exclua a classe que é adicionada à biblioteca do .NET Standard.
Adicione o pacote do NuGet xamarin. Forms 2,4 (ou superior) para a biblioteca .NET Standard.
Em projetos da plataforma, adicione uma referência à biblioteca do .NET Standard e remova a referência ao
projeto da PCL que contém a lógica de interface de usuário do xamarin. Forms.
Copie os arquivos do projeto PCL para a biblioteca .NET Standard.
Remova o projeto PCL que contém a lógica de interface de usuário do xamarin. Forms.

Links relacionados
.NET Standard
Opções de compartilhamento de código
Solução de problemas
12/04/2019 • 3 minutes to read

Condições de erro comuns e como resolvê-los

Erro: "não é possível localizar uma versão do xamarin. Forms compatível


com..."
Os erros a seguir podem aparecer no pacote Console janela ao atualizar todos os pacotes do Nuget em uma
solução xamarin. Forms ou em um projeto de aplicativo xamarin. Forms Android:

Attempting to resolve dependency 'Xamarin.Android.Support.v7.AppCompat (= 23.3.0.0)'.


Attempting to resolve dependency 'Xamarin.Android.Support.v4 (= 23.3.0.0)'.
Looking for updates for 'Xamarin.Android.Support.v7.MediaRouter'...
Updating 'Xamarin.Android.Support.v7.MediaRouter' from version '23.3.0.0' to '23.3.1.0' in project
'Todo.Droid'.
Updating 'Xamarin.Android.Support.v7.MediaRouter 23.3.0.0' to 'Xamarin.Android.Support.v7.MediaRouter 23.3.1.0'
failed.
Unable to find a version of 'Xamarin.Forms' that is compatible with 'Xamarin.Android.Support.v7.MediaRouter
23.3.0.0'.

O que causa esse erro?


O Visual Studio para Mac (ou o Visual Studio) pode indicar que atualizações estejam disponíveis para o xamarin.
Forms Nuget packge e todas as suas dependências. Do Xamarin Studio, a solução pacotes nó pode ter esta
aparência (os números de versão podem ser diferentes):

Esse erro pode ocorrer se você tentar atualizar todos os os pacotes.


Isso é porque com Android projetos definidos para uma versão de compilação/destino do Android 6.0 (API 23) ou
abaixo, xamarin. Forms tem uma dependência de disco rígida em específico versões do Android que suportam a
pacotes. Embora as versões atualizadas desses pacotes podem estar disponíveis, xamarin. Forms não é
necessariamente compatível com eles.
Nesse caso, você deve atualizar somente o xamarin. Forms pois isso assegurará que as dependências
permanecem em versões compatíveis do pacote. Outros pacotes que você adicionou ao seu projeto também
podem ser atualizados individualmente, contanto que eles não fazem com que os pacotes de suporte do Android
atualizar.
NOTE
Se você estiver usando o xamarin. Forms 2.3.4 ou posterior e versão de destino/compilação do seu projeto Android é
definido para o Android 7.0 (API 24) ou superior, em seguida, as dependências de disco rígidas mencionadas acima não se
aplicam e você pode atualizar o suporte pacotes independentemente do pacote xamarin. Forms.

Correção: Remover todos os pacotes e adicionar novamente o xamarin. Forms


Se o Xamarin.Android.Support pacotes foram atualizados para versões incompatíveis, a correção mais simples
é:
1. Exclua manualmente todos os pacotes do Nuget no projeto do Android, em seguida
2. Adicionar novamente o xamarin. Forms pacote.
Isso fará o download automaticamente o correto versões dos outros pacotes.
Para ver um vídeo desse processo, consulte a post fóruns.
Perguntas frequentes sobre o xamarin. Forms
12/04/2019 • 2 minutes to read

Posso atualizar o modelo padrão Xamarin.Forms para um pacote NuGet


mais recente?
Este guia usa o modelo de biblioteca xamarin. Forms .NET Standard como um exemplo, mas o mesmo método
geral também funcionarão para o modelo de projeto compartilhado do xamarin. Forms.

Por que o designer XAML do Visual Studio não funciona para arquivos
XAML do Xamarin.Forms?
Xamarin. Forms atualmente não dá suporte a designers visuais para arquivos XAML.

Erro de build do Android: The "LinkAssemblies" task failed


unexpectedly
Você poderá ver uma mensagem de erro The "LinkAssemblies" task failed unexpectedly quando a criação de um
projeto xamarin. Android que usa formulários. Isso acontece quando o vinculador está ativo (normalmente em um
versão build para reduzir o tamanho do pacote do aplicativo); e isso ocorre porque os destinos Android não são
atualizados para o framework mais recente.

"Por que meu projeto Xamarin.Forms.Maps Android falha com


COMPILETODALVIK: ERRO NÍVEL SUPERIOR INESPERADO?"
Esse erro pode ser visto no painel de erro do Visual Studio para Mac ou na janela de saída do Build do Visual
Studio; em projetos do Android usando Xamarin.Forms.Maps. Ele geralmente é resolvido aumentando o tamanho
do Heap de Java para o seu projeto xamarin. Android.
Pode atualizar o modelo padrão do xamarin. Forms
para um pacote do NuGet mais recente?
12/04/2019 • 2 minutes to read

Este guia usa o modelo de biblioteca xamarin. Forms .NET Standard como um exemplo, mas o mesmo método
geral também funcionarão para o modelo de projeto compartilhado do xamarin. Forms. Este guia foi escrito com o
exemplo de atualização do xamarin. Forms 1.5.1.6471 para 2.1.0.6529, mas as mesmas etapas são possíveis definir
outras versões como o padrão em vez disso.
1. Copie o modelo original .zip de:

C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\Extensions\Xamarin\Xamarin\[Xamarin


Version]\T\PT\Cross-Platform\Xamarin.Forms.PCL.zip

2. Descompacte o .zip para um local temporário.


3. Altere todas as ocorrências da versão antiga do pacote de formulários para a nova versão que você deseja
usar.
FormsTemplate\FormsTemplate.vstemplate
FormsTemplate.Android\FormsTemplate.Android.vstemplate
FormsTemplate.iOS\FormsTemplate.iOS.vstemplate

Exemplo: <package id="Xamarin.Forms" version="1.5.1.6471" /> ->


<package id="Xamarin.Forms" version="2.1.0.6529" />

4. Altere o elemento "nome" da janela principal arquivo de modelo multiprojeto (


Xamarin.Forms.PCL.vstemplate ) para torná-lo exclusivo. Por exemplo:

Aplicativo em branco (xamarin. Forms portátil) - 2.1.0.6529

5. Novamente, compacte a pasta de modelo inteiro. Certifique-se de corresponder à estrutura do arquivo


original do .zip arquivo. O Xamarin.Forms.PCL.vstemplate arquivo deve estar na parte superior do .zip
arquivo, não em todas as pastas.
6. Crie um subdiretório de "Aplicativos móveis" na sua pasta de modelos do Visual Studio por usuário:

%USERPROFILE%\Documents\Visual Studio 2013\Templates\ProjectTemplates\Visual C#\Mobile Apps

7. Copie a nova pasta zipada modelo para o novo diretório de "Aplicativos móveis".
8. Baixe o pacote do NuGet que corresponde à versão da etapa 3. Por exemplo,
http://nuget.org/api/v2/package/Xamarin.Forms/2.1.0.6529 (Consulte também
https://stackoverflow.com/questions/8597375/how -to-get-the-url-of-a-nupkg-file ) e copie-o para a
subpasta apropriada da pasta de extensões do Xamarin para Visual Studio:
C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\Extensions\Xamarin\Xamarin\[Xamarin
Version]\Packages
Por que o designer XAML do Visual Studio não
funciona para arquivos XAML xamarin. Forms?
12/04/2019 • 2 minutes to read

Xamarin. Forms atualmente não dá suporte a designers visuais para arquivos XAML. Por isso, ao tentar abrir um
arquivo XAML de formulários no Visual Studio Designer de interface do usuário XAML ou Designer de interface
do usuário XAML com codificação, a seguinte mensagem de erro é gerada:

"Não é possível abrir o arquivo com o editor selecionado. Escolha outro editor."

Essa limitação é descrita no visão geral seção o xamarin. Forms Noções básicas de XAML guia:

"Não há ainda um designer visual para gerar o XAML em aplicativos xamarin. Forms, XAML para que todos os
deve ser manual".

No entanto, o Visualizador de XAML xamarin. Forms pode ser exibido selecionando a exibição > outras janelas
> Visualizador xamarin. Forms opção de menu.
Erro de build do Android – tarefa o LinkAssemblies
falhou inesperadamente
12/04/2019 • 2 minutes to read

Você poderá ver uma mensagem de erro The "LinkAssemblies" task failed unexpectedly quando a criação de um
projeto xamarin. Android que usa formulários. Isso acontece quando o vinculador está ativo (normalmente em um
versão build para reduzir o tamanho do pacote do aplicativo); e isso ocorre porque os destinos Android não são
atualizados para o framework mais recente. (Mais informações: Xamarin. Forms para Android requisitos)
A resolução para esse problema é certificar-se de ter as versões do SDK do Android mais recente com suporte e
defina as estrutura de destino para a plataforma mais recente instalada. Também é recomendável que você
defina as versão destino Android para a plataforma instalada mais recente e o versão mínima do Android
para API 19 ou superior. Isso é considerado a configuração com suporte.

Configuração no Visual Studio para Mac


1. Clique com o botão direito no projeto do Android e selecione opções no menu.
2. No opções de projeto caixa de diálogo, vá para Build > geral.
3. Defina o compilar usando a versão do Android: (Estrutura de destino) para a plataforma mais recente
instalada.
4. No opções de projeto caixa de diálogo, vá para compilar > aplicativo Android.
5. Defina a versão mínima do Android à API nível 19 ou superior e o versão destino Android a mais recente
instalada plataforma escolhida (3).

Configuração no Visual Studio


1. Clique com o botão direito no projeto do Android e selecione dimensões no menu.
2. Nas propriedades do projeto, vá para aplicativo.
3. Defina o compilar usando a versão do Android: (Estrutura de destino) para a plataforma mais recente
instalada.
4. Nas propriedades do projeto, vá para manifesto do Android.
5. Defina a versão mínima do Android à API nível 19 ou superior e o versão destino Android a mais recente
instalada plataforma escolhida (3).
Depois de atualizar essas configurações,. Limpe e recompile o projeto para garantir que as alterações são
escolhidas.
Por que meu projeto Xamarin.Forms.Maps Android
falha com erro INESPERADO de nível superior
COMPILETODALVIK?
12/04/2019 • 2 minutes to read

Esse erro pode ser visto no painel de erro do Visual Studio para Mac ou na janela de saída de compilação do
Visual Studio; em projetos Android usando Xamarin.Forms.Maps.
Isso geralmente é resolvido, aumentando o tamanho do Heap do Java para o seu projeto xamarin. Siga estas
etapas para aumentar o tamanho do heap:

Visual Studio
1. Clique com botão direito do Android & Abrir as opções de projeto.
2. Vá para Android opções -> Avançado
3. Na caixa de texto de tamanho do heap de Java insira 1G.
4. Recompile o projeto.

Visual Studio para Mac


1. Clique com botão direito do Android & Abrir as opções de projeto.
2. Vá para Build -> compilação Android -> Avançado
3. Na caixa de texto de tamanho do heap de Java insira 1G.
4. Recompile o projeto.
Criando aplicativos móveis com xamarin. Forms
book
12/04/2019 • 10 minutes to read

baixar o exemplo
O livro criação de aplicativos móveis com xamarin. Forms , de Charles Petzold, é um guia
para aprender a escrever aplicativos xamarin. Forms. O único pré-requisito é conhecimento
sobre o C# linguagem de programação. O livro oferece uma exploração extensiva na interface
do usuário do xamarin. Forms e também aborda a animação, MVVM, gatilhos,
comportamentos, layouts personalizados, renderizadores personalizados e muito mais.
O livro foi publicado na primavera de 2016 e não tiver sido atualizado desde então. Há muito
o no livro valioso que permanece, mas alguns dos material está desatualizado, e alguns tópicos não são
totalmente correto ou foi concluído.

Baixe o livro eletrônico gratuito


Baixe o seu formato de livro eletrônico preferencial da Microsoft Virtual Academy:
PDF (56Mb)
ePub (151Mb)
Kindle edition (325Mb)
Você também pode Baixe capítulos individuais como arquivos PDF.

Exemplos
Os exemplos estão disponível no githube incluem projetos para iOS, Android e Universal Windows Platform
(UWP ). (Xamarin. Forms não é compatível com Windows 10 Mobile, mas os aplicativos xamarin. Forms serão
executado na área de trabalho do Windows 10.)

Resumos de capítulo
Resumos de capítulo estão disponíveis na tabela de capítulo mostrados abaixo. Esses resumos descrevem o
conteúdo de cada capítulo e incluem vários tipos de links:
Links para os reais capítulos do livro (na parte inferior da página) e artigos relacionados
Links para todos os exemplos de xamarin-forms-samples livro repositório do GitHub
Links para a documentação da API para obter descrições mais detalhadas de classes xamarin. Forms,
estruturas, propriedades, enumerações e assim por diante
Esses resumos também indicam quando pode ser o material no capítulo um pouco desatualizada.

Baixe capítulos e resumos


CAPÍTULO TEX TO COMPLETO RESUMO

Capítulo 1. Como o ajuste do xamarin. Baixar PDF Resumo


Forms?

Capítulo 2. Anatomia de um aplicativo Baixar PDF Resumo

Capítulo 3. Aprofundamento no texto Baixar PDF Resumo

Capítulo 4. Rolagem da pilha Baixar PDF Resumo

Capítulo 5. Lidando com tamanhos Baixar PDF Resumo

Capítulo 6. Cliques de botão Baixar PDF Resumo

Capítulo 7. XAML vs. Código Baixar PDF Resumo

Capítulo 8. Código e XAML em Baixar PDF Resumo


harmonia

Capítulo 9. Chamadas à API específicas Baixar PDF Resumo


da plataforma

Capítulo 10. Extensões de marcação Baixar PDF Resumo


XAML

Capítulo 11. A infraestrutura associável Baixar PDF Resumo

Capítulo 12. Estilos Baixar PDF Resumo

Capítulo 13. Bitmaps Baixar PDF Resumo

Capítulo 14. Layout absoluto Baixar PDF Resumo

Capítulo 15. A Interface interativa Baixar PDF Resumo

Capítulo 16. Associação de dados Baixar PDF Resumo

Capítulo 17. Domínio da grade Baixar PDF Resumo

Capítulo 18. MVVM Baixar PDF Resumo

Capítulo 19. Exibições de coleção Baixar PDF Resumo

Capítulo 20. E/s assíncrona e de Baixar PDF Resumo


arquivo

Capítulo 21. Transformações Baixar PDF Resumo

Capítulo 22. Animação Baixar PDF Resumo

Capítulo 23. Gatilhos e Baixar PDF Resumo


comportamentos
CAPÍTULO TEX TO COMPLETO RESUMO

Capítulo 24. Navegação de página Baixar PDF Resumo

Capítulo 25. Variedades de página Baixar PDF Resumo

Capítulo 26. Layouts personalizados Baixar PDF Resumo

Capítulo 27. Renderizadores Baixar PDF Resumo


personalizados

Capítulo 28. Localização e mapas Baixar PDF Resumo

Maneiras em que o livro está desatualizado


Desde a publicação da criação de aplicativos móveis com xamarin. Forms, vários recursos novos foram
adicionados ao xamarin. Forms. Esses novos recursos são descritos nos artigos individuais a xamarin. Forms
documentação.
Outras alterações fizeram parte do conteúdo do livro fiquem desatualizados:
Bibliotecas do .NET standard 2.0 substituíram as bibliotecas de classes portáteis
Em geral, um aplicativo xamarin. Forms usa uma biblioteca para compartilhar código entre diferentes
plataformas. Originalmente, essa foi uma biblioteca de classe portátil (PCL ). Há muitas referências a PCLs em
todo o catálogo e os resumos de capítulo.
Biblioteca de classes portátil foi substituída por uma biblioteca .NET Standard 2.0, conforme descrito no artigo
suporte no xamarin. Forms do .NET Standard 2.0. Todos os código de exemplo do livro foi atualizado para usar
bibliotecas .NET Standard 2.0.
A maioria das informações no livro sobre a função de biblioteca de classes portátil permanece o mesmo para
uma biblioteca .NET Standard 2.0. Uma diferença é que apenas uma PCL tem um numérico "perfil". Além disso,
há algumas vantagens em bibliotecas do .NET Standard 2.0. Por exemplo, o capítulo 20 Async e/s de arquivo
descreve como usar as plataformas subjacentes para executar e/s de arquivo. Isso não é mais necessário. A
biblioteca do .NET Standard 2.0 oferece suporte a familiar System.IO classes para todas as plataformas do
xamarin. Forms.
A biblioteca .NET Standard 2.0 também permite que os aplicativos xamarin. Forms usar HttpClient para
acessar os arquivos pela Internet em vez de WebRequest ou outras classes.
A função do XAML foi promovida
Criando aplicativos móveis com xamarin. Forms começa descrevendo como escrever aplicativos xamarin. Forms
usando a linguagem c#. O de Extensible Application Markup Language (XAML ) não é introduzido até capítulo 7.
XAML vs. Código.
Agora, a XAML tem um papel muito maior no xamarin. Forms. Os modelos de solução do xamarin. Forms
distribuídos com o Visual Studio criam arquivos de página baseados em XAML. Um desenvolvedor usando o
xamarin. Forms deve se familiarizar com o XAML mais cedo possível. O linguagem de marcação de aplicativo
extensível (XAML ) seção da documentação do xamarin. Forms contém vários artigos sobre XAML para você
começar.
Plataformas com suporte
Xamarin. Forms não oferece mais suporte do Windows 8.1 e Windows Phone 8.1.
O livro, às vezes, faz referência à tempo de execução do Windows. Esse é um termo que abrange a API do
Windows usada em várias versões do Windows e Windows Phone. As versões mais recentes do xamarin. Forms
restringe-se para dar suporte a plataforma Universal do Windows, que é a API para o Windows 10 e Windows
10 Mobile.
Uma biblioteca .NET Standard 2.0 não oferece suporte a qualquer versão do Windows 10 Mobile. Portanto, um
aplicativo xamarin. Forms usando uma biblioteca .NET Standard não será executado em um dispositivo
Windows 10 Mobile. Aplicativos de xamarin. Forms continuarão sendo executados no Windows 10 desktop,
versões 10.0.16299.0 e acima.
Xamarin. Forms tem suporte de visualização para o Mac, WPF, GTK #, e Tizen plataformas.
Resumos de capítulo
Os resumos de capítulo incluem as informações relacionadas a alterações no xamarin. Forms, pois o livro foi
escrito. Eles costumam ser na forma de anotações:

NOTE
Observações sobre cada página indicam onde o xamarin. Forms foi bifurcado do material apresentado no livro.

Exemplos
No xamarin-forms-samples livro repositório do GitHub, o código original do livro branch contém
exemplos de programa consistentes com o catálogo. O mestre branch contém projetos que foram atualizados
para remover APIs preteridas e refletir APIs aprimoradas. Além disso, o Android projetos na mestre branch
foram atualizados para o Android Design de Material via AppCompat e geralmente exibirá texto preto em um
plano de fundo branco.

Links relacionados
Blog do MS Press
Código de exemplo do livro
Padrões de aplicativo empresarial usando o livro
eletrônico do xamarin. Forms
12/04/2019 • 9 minutes to read

Diretrizes de arquitetura para o desenvolvimento de aplicativos empresariais de xamarin. Forms testáveis


adaptáveis e sustentáveis

Este livro eletrônico fornece orientação sobre como implementar o padrão Model-View -ViewModel (MVVM ), a
injeção de dependência, a navegação, a validação e o gerenciamento de configuração, mantendo um acoplamento
flexível. Além disso, há também orientações sobre como executar autenticação e autorização com IdentityServer,
acessando dados através de microsserviços em contêineres e testes de unidade.

Prefácio
Este capítulo explica a finalidade e o escopo do guia e que ele é destinado.

Introdução
Os desenvolvedores de aplicativos empresariais enfrentam vários desafios que podem alterar a arquitetura do
aplicativo durante o desenvolvimento. Portanto, é importante compilar um aplicativo para que possa ser
modificado ou estendido ao longo do tempo. A criação de tal adaptabilidade pode ser difícil, mas geralmente
envolve o particionamento de um aplicativo em componentes discretos e flexíveis que podem ser facilmente
integrados juntos em um aplicativo.

MVVM
O padrão Model-View -ViewModel (MVVM ) ajuda a separar a lógica de negócios e apresentação de um aplicativo
de sua interface do usuário (UI) de forma precisa. Mantendo uma separação clara entre a lógica do aplicativo e a
interface do usuário ajuda a resolver vários problemas de desenvolvimento e pode tornar mais fácil de testar um
aplicativo, manter e evoluem. Ele pode também melhoram muito a oportunidades de reutilização de código e
permite que os desenvolvedores e designers de interface do usuário mais facilmente colaboram durante o
desenvolvimento de suas respectivas partes de um aplicativo.

Injeção de dependência
Injeção de dependência permite desassociação de tipos concretos do código que depende desses tipos.
Normalmente, ele usa um contêiner que mantém uma lista de registros e mapeamentos entre as interfaces e tipos
abstratos e os tipos concretos que implementam ou estendem a esses tipos.
Contêineres de injeção de dependência reduzem o acoplamento entre objetos fornecendo um recurso para
instanciar instâncias de classe e gerenciar seu tempo de vida com base na configuração do contêiner. Durante a
criação de objetos, o contêiner injeta quaisquer dependências que exige que o objeto nele. Se essas dependências
ainda não tem sido criadas, o contêiner cria e resolve as dependências entre primeiro.

Comunicação entre componentes flexíveis


O xamarin. Forms MessagingCenter classe implementa a publicar-padrão, permitindo a comunicação baseada em
mensagens entre os componentes são inconvenientes para vincular as referências de objeto e o tipo de assinatura.
Esse mecanismo permite que os publicadores e assinantes para se comunicar sem a necessidade de uma referência
entre si, ajudando a reduzir as dependências entre componentes, enquanto também permite que componentes de
forma independente seja desenvolvido e testado.

Navegação
Xamarin. Forms inclui suporte para navegação de página, que geralmente resulta da interação do usuário com a
interface do usuário ou do aplicativo em si, como resultado das alterações de estado interno controlado por lógica.
No entanto, a navegação pode ser complexa para implementar em aplicativos que usam o padrão MVVM.
Este capítulo apresenta um NavigationService classe, que é usado para executar a navegação de model first de
modo de exibição de modelos de exibição. Colocar a lógica de navegação no modo de exibição classes de modelo
significa que a lógica pode ser exercida por meio de testes automatizados. Além disso, o modelo de exibição, em
seguida, pode implementar a lógica para controlar a navegação para assegurar que determinadas regras de
negócio são aplicadas.

Validação
Qualquer aplicativo que aceita entrada de usuários deve garantir que a entrada é válida. Sem validação, um usuário
pode fornecer dados que faz com que o aplicativo falhe. Validação impõe regras de negócio e impede que um
invasor injetando dados mal-intencionados.
No contexto do Model-View -ViewModel (MVVM ) padrão, um modelo de exibição ou modelo geralmente
precisará executar a validação de dados e sinalizar erros de validação para o modo de exibição para que o usuário
possa corrigi-los.

Gerenciamento de configurações
As configurações permitem a separação dos dados que configura o comportamento de um aplicativo do código,
permitindo que o comportamento a ser alterado sem recompilar o aplicativo. Configurações do aplicativo são
dados que um aplicativo cria e gerencia e configurações de usuário são as configurações personalizáveis de um
aplicativo que afetam o comportamento do aplicativo e não exigem o ajuste re frequente.

Microservices em contêineres
Os Microsserviços oferecem uma abordagem ao desenvolvimento de aplicativos e implantação que é adequada
para os requisitos de agilidade, escala e confiabilidade de aplicativos de nuvem modernos. Uma das principais
vantagens de microsserviços é que eles podem ser escalados horizontalmente de forma independente, o que
significa que uma área funcional específica pode ser dimensionada que que requer mais processamento de rede ou
energia largura de banda para dar suporte à demanda, sem dimensionamento desnecessariamente áreas do o
aplicativo que não estejam enfrentando o aumento na demanda.

Autenticação e autorização
Há muitas abordagens para integrar a autenticação e autorização em um aplicativo xamarin. Forms que se
comunica com um aplicativo web ASP.NET MVC. Aqui, autenticação e autorização são executadas com um
microsserviço de identidade em contêineres que usa 4 IdentityServer. IdentityServer é uma estrutura de OAuth 2.0
e OpenID Connect do código-fonte aberto para o ASP.NET Core se integra ao ASP.NET Core Identity para realizar
a autenticação de token de portador.

Acesso a dados remotos


Muitas soluções modernas baseado na web fazer uso dos serviços da web, hospedados por servidores web, para
fornecer funcionalidade para o cliente remoto a aplicativos. As operações que um serviço web expõe constituem
uma API da web e aplicativos de cliente devem ser capazes de utilizar a API da web sem saber como os dados ou
operações que expõe a API são implementadas.

Testes de Unidade
Teste de modelos e modelos de exibição de aplicativos MVVM é idêntico ao teste de outras classes e as mesmas
ferramentas e técnicas podem ser usadas. No entanto, há alguns padrões que são comuns ao modelo e classes de
modelo de exibição, que podem se beneficiar das técnicas de teste de unidade específica.

Comentários
Este projeto tem um site da comunidade, no qual você pode postar perguntas e fornecer comentários. O site da
comunidade está localizado em GitHub. Como alternativa, comentários sobre o livro eletrônico podem ser
enviados por email para dotnet-architecture-ebooks-feedback@service.microsoft.com .

Links relacionados
Baixe o livro eletrônico (PDF de 2Mb)
eShopOnContainers (GitHub) (amostra)
Elementos gráficos de SkiaSharp em Xamarin.Forms
12/04/2019 • 5 minutes to read

baixar o exemplo
Usar SkiaSharp para gráficos 2D em seus aplicativos xamarin. Forms
SkiaSharp é um sistema de gráficos em 2D para .NET e c# com o engine gráficos Skia de código-fonte aberto
que é amplamente usado em produtos do Google. Você pode usar SkiaSharp em seus aplicativos xamarin.
Forms para desenhar o texto, bitmaps e gráficos vetoriais 2D. Consulte a desenho 2D guia para obter mais
informações gerais sobre a biblioteca de SkiaSharp e alguns outros tutoriais.
Este guia pressupõe que você esteja familiarizado com a programação do xamarin. Forms.

Webinar: SkiaSharp para xamarin. Forms

Etapas preliminares de SkiaSharp


SkiaSharp para xamarin. Forms é empacotado como um pacote do NuGet. Depois de criar uma solução
xamarin. Forms no Visual Studio ou Visual Studio para Mac, você pode usar o Gerenciador de pacotes do NuGet
para pesquisar o SkiaSharp.Views.Forms empacotar e adicioná-lo à sua solução. Se você marcar a
referências seção de cada projeto após a adição de SkiaSharp, você pode ver que várias SkiaSharp bibliotecas
foram adicionadas para cada um dos projetos na solução.
Se seu aplicativo xamarin. Forms tem como alvo iOS, use a página de propriedades do projeto para alterar o
destino de implantação mínimo para o iOS 8.0.
Em qualquer página do c# que usa SkiaSharp você desejará incluir uma using diretriz para a SkiaSharp
namespace, que abrange todos os de SkiaSharp classes, estruturas e enumerações que você usará em seus
elementos gráficos a programação. Você também pode uma using diretriz para a SkiaSharp.Views.Forms
namespace para as classes específicas para xamarin. Forms. Isso é um quantidade menor espaço para nome,
com a classe mais importantes sendo SKCanvasView . Essa classe deriva o xamarin. Forms View de classe e
hospeda sua saída de gráficos de SkiaSharp.

IMPORTANT
O SkiaSharp.Views.Forms namespace também contém um SKGLView classe que deriva de View mas utiliza o
OpenGL para renderização de gráficos. Para fins de simplicidade, este guia restringe-se ao SKCanvasView , mas o uso
SKGLView em vez disso, é bastante semelhante.

Noções básicas de desenho do SkiaSharp


Algumas das estimativas de gráficos mais simples, que você pode desenhar com SkiaSharp são retângulos,
elipses e círculos. Exibir esses números, você aprenderá sobre as coordenadas de SkiaSharp, tamanhos e cores.
A exibição de texto e bitmaps é mais complexa, mas esses artigos também introduzem essas técnicas.

Caminhos e linhas de SkiaSharp


Um caminho gráfico é uma série de linhas retas conectadas e curvas. Caminhos podem tracejados, preenchidos,
ou ambos. Este artigo abrange muitos aspectos do desenho de linha, incluindo o traço extremidades e uniões e
tracejada e as linhas pontilhadas, mas parar com pouca geometrias de curva.

Transformações de SkiaSharp
As transformações permitem que os objetos gráficos ser uniformemente traduzido, dimensionado, girados ou
inclinados. Este artigo também mostra como você pode usar uma matriz de transformação de 3 por 3 padrão
para criar transformações não afins e aplicar transformações aos caminhos.

Curvas e caminhos de SkiaSharp


A exploração dos caminhos continua com adicionando curvas a um objeto de caminho e explorar outros
recursos avançados de caminho. Você verá como você pode especificar um caminho inteiro em uma cadeia de
caracteres de texto conciso, como usar efeitos de caminho e como se aprofundar em elementos internos do
caminho.

Bitmaps do SkiaSharp
Os bitmaps são matrizes retangulares de bits que correspondem aos pixels de um dispositivo de vídeo. Esta
série de artigos mostra como carregar, salvar, exibir, criar, desenhar em, animar e acessar os bits de SkiaSharp
bitmaps.

Efeitos de SkiaSharp
Os efeitos são propriedades que alteram a exibição normal de elementos gráficos, incluindo gradientes linear e
circulares, lado a lado de bitmap, misturar modos de desfoque e outras pessoas.

Links relacionados
APIs de SkiaSharp
SkiaSharpFormsDemos (amostra)
SkiaSharp com xamarin. Forms Webinar (vídeo)

Você também pode gostar