Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Xamarin.Forms
Primeros pasos
Requisitos
Instalación
Compilación de la primera aplicación
Inicio rápido de una sola página
Inicio rápido de varias páginas
Inicio rápido para bases de datos locales
Inicio rápido para estilos
Profundización
XAML
Controles de XAML
XAML Basics
Parte 1. Introducción a XAML
Parte 2. Sintaxis XAML esencial
Parte 3. Extensiones de marcado XAML
Parte 4. Conceptos básicos del enlace de datos
Parte 5. De enlaces de datos a MVVM
Compilación de XAML
Cuadro de herramientas de XAML
Controlador de vista previa de XAML
Datos en tiempo de diseño
Controles personalizados
Espacios de nombres XAML
Esquemas de espacio de nombres personalizado XAML
Prefijos recomendados de espacio de nombres de XAML
Extensiones de marcado XAML
Consumo de extensiones de marcado XAML
Creación de extensiones de marcado XAML
Modificadores de campo
Paso de argumentos
Propiedades enlazables
Propiedades asociadas
Diccionarios de recursos
XAML estándar (versión preliminar)
Controles
Carga de XAML en tiempo de ejecución
Principios de la aplicación
Accesibilidad
Propiedades de automatización
Accesibilidad de teclado
Clase de aplicación
Ciclo de vida de la aplicación
Indexación de la aplicación y vinculación en profundidad
Comportamientos
Introducción
Comportamientos asociados
Comportamientos de Xamarin.Forms
Comportamientos reutilizables
EffectBehavior
EventToCommandBehavior
Representadores personalizados
Introducción
Clases base y controles nativos del representador
Personalización de una entrada
Personalización de una página de contenido
Personalización de un mapa
Personalización de un anclado de mapa
Resaltado de un área circular en un mapa
Resaltado de una región en un mapa
Resaltado de una ruta en un mapa
Personalización de la clase ListView
Personalización de la clase ViewCell
Implementación de una vista
Implementación de una clase HybridWebView
Implementación de un reproductor de vídeo
Creación de reproductores de vídeo de la plataforma
Reproducción de un vídeo de web
Enlace de orígenes de vídeo con el reproductor
Carga de vídeos de recursos de aplicación
Acceso a la biblioteca de vídeos del dispositivo
Controles de transporte de vídeo personalizados
Posicionamiento de vídeo personalizado
Enlace de datos
Enlaces básicos
Modo de enlace
Formato de cadena
Enlace de ruta de acceso
Enlace de convertidores de valores
Conmutación por recuperación de enlaces
Interfaz de comandos
Enlaces compilados
DependencyService
Introducción
Registro y resolución
Selección de biblioteca de fotos
Efectos
Introducción
Creación de efectos
Pasar parámetros
Parámetros como propiedades CLR
Parámetros como propiedades asociadas
Invocación de eventos
Gestos
Pulsar
Reducir
Movimiento panorámico
Deslizar rápidamente
Localización
Localización de cadenas e imágenes
Localización de derecha a izquierda
MessagingCenter
Navegación
Navegación jerárquica
TabbedPage
CarouselPage
MasterDetailPage
Páginas modales
Shell
Introducción
Creación de una aplicación Shell
Control flotante
Pestañas
Configuración de la página
Navegación
Búsqueda
Representadores personalizados
Templates
Plantillas de control
Introducción
Creación de plantilla de control
Enlaces a plantilla
Plantillas de datos
Introducción
Creación de plantilla de datos
Selección de plantilla de datos
Desencadenadores
Interfaz de usuario
Indicador de actividad
Animación
Animaciones simples
Funciones de aceleración
Animaciones personalizadas
BoxView
Button
CheckBox
CollectionView
Introducción
Data
Diseño
Selección
EmptyView
Desplazarse
Colores
Referencia de controles
Páginas
Diseños
Vistas
Celdas
DataPages
Primeros pasos
Controls Reference
DatePicker
Mostrar elementos emergentes
Gráficos con SkiaSharp
Imágenes
ImageButton
Diseños
StackLayout
AbsoluteLayout
RelativeLayout
Grid
FlexLayout
ScrollView
LayoutOptions
Margen y relleno
Orientación del dispositivo
Tableta y escritorio
Diseños enlazables
Creación de un diseño personalizado
Compresión de diseño
ListView
Orígenes de datos
Apariencia de etiqueta
Apariencia de línea
Interactividad
Rendimiento
Mapas
Selector
Configuración de la propiedad ItemsSource de un selector
Adición de datos a la colección de elementos de un selector
Barra de progreso
Slider
Control de incremento
Estilos
Aplicación de estilos para aplicaciones Xamarin.Forms con estilos XAML
Introducción
Estilos explícitos
Estilos implícitos
Estilos globales
Herencia de estilo
Estilos dinámicos
Estilos de dispositivo
Clases de estilo
Aplicación de estilos para aplicaciones Xamarin.Forms con hojas de estilo (CSS)
Switch
TableView
Texto
Label
Entrada
Editor
Fuentes
Estilos
Temas
Tema claro
Tema oscuro
Creación de un tema personalizado
TimePicker
Visual
Objeto visual de material
Creación de un representador visual
Administrador de estado visual
WebView
Características de la plataforma
Android
AppCompat y Material Design
Relleno y sombras de los botones
Opciones de entrada del Editor de métodos de entrada
Sombras paralelas ImageButton
Desplazamiento rápido ListView
Altura de la barra NavigationPage
Eventos del ciclo de vida de la página
Modo de entrada de teclado en pantalla
Deslizamiento de página TabbedPage
Animaciones de transición de página TabbedPage
Color y colocación de la barra de herramientas TabbedPage
Elevación VisualElement
Modo de color heredado VisualElement
Contenido mixto WebView
Zoom de WebView
Clase de dispositivo
iOS
Accessibility Scaling for Named Font Sizes
Color de fondo de celda
Color del cursor de entrada
Tamaño de la fuente de entrada
Formato
Estilo de presentación de la página modal de iPad
Títulos de página grandes
Estilo de encabezado de grupo de ListView
Animaciones de la fila de ListView
Estilo del separador ListView
Actualizaciones de control del subproceso principal
Separador de barra NavigationPage
Modo de color del texto de barra NavigationPage
Translucidez de barra NavigationPage
Visibilidad del indicador de página principal
Visibilidad de barra de estado de página
Selección de elementos de selector
Guía de diseño de área segura
Toques de contenido ScrollView
Reconocimiento de gestos simultáneos de desplazamiento lateral
Control deslizante con el uso de toques
Desenfoque VisualElement
Sombras paralelas VisualElement
Modo de color heredado VisualElement
Formularios nativos
Vistas nativas
Vistas nativas en XAML
Vistas nativas en C#
Otras plataformas
GTK#
Mac
Tizen
WPF
Funcionalidad específica de plataforma
Windows
Orden de lectura InputView
Modo de selección ListView
Barra de navegación MasterDetailPage
Colocación de la barra de herramientas de página
Configuración de la plataforma
Spell Check SearchBar
Iconos TabbedPage
Claves de acceso VisualElement
Modo de color heredado VisualElement
Alertas de JavaScript en WebView
Xamarin.Essentials
Primeros pasos
Compatibilidad de plataforma y características
Acelerómetro
Información de la aplicación
Barómetro
Batería
Portapapeles
Convertidores de colores
Brújula
Conectividad
Detección de vibraciones
Información de pantalla del dispositivo
Información del dispositivo
Correo electrónico
Asistentes del sistema de archivos
Linterna
Codificación geográfica
Geolocalización
Giroscopio
Selector
Magnetómetro
Subproceso principal
Mapas
Apertura del explorador
Sensor de orientación
Marcador telefónico
Extensiones de plataforma (Size, Rect, Point)
Preferencias
Almacenamiento seguro
Compartir
SMS
Texto a voz
Convertidores de unidades
Seguimiento de versiones
Vibración
Solución de problemas
Datos y Azure Cloud Services
Información general
Almacenamiento de datos local
Información general
Control de archivos
Bases de datos locales
Servicios de Azure
Introducción a servicios de Azure
Base de datos de documentos de Azure Cosmos DB
Centros de notificaciones de Azure
Almacenamiento de Azure
Azure Search
Funciones de Azure
Servicio Azure SignalR
Azure Cognitive Services
Información general de Cognitive Services
Introducción
Reconocimiento de voz
Corrector ortográfico
Traducción de texto
Reconocimiento de emociones
Servicios Web
Información general de servicios web
Introducción
ASMX
WCF
REST
Autenticación
Información general sobre la autenticación
REST
OAuth
Azure Active Directory B2C
Autenticación en Azure Cosmos DB
Implementación y pruebas
Publicación de aplicaciones de iOS
Publicación de aplicaciones de Android
Publicación de aplicaciones de UWP
Publicación de aplicaciones de Mac
Rendimiento
Pruebas automatizadas con Visual Studio App Center
Conceptos avanzados y funcionamiento interno
Resolución de dependencias
Representadores rápidos
.NET Standard
Solución de problemas
Preguntas más frecuentes
¿Se puede actualizar la plantilla predeterminada de Xamarin.Forms en un paquete
NuGet más reciente?
¿Por qué no funciona el diseñador XAML de Visual Studio para los archivos XAML
de Xamarin.Forms?
Error de compilación de Android: error inesperado en la tarea "LinkAssemblies"
¿Por qué se realiza mi proyecto de Xamarin.Forms.Maps para Android produce el
siguiente error: COMPILETODALVIK : UNEXPECTED TOP-LEVEL ERROR?
Notas de la versión
Muestras
Libro Creating Mobile Apps with Xamarin.Forms
Libro electrónico sobre patrones de aplicación empresarial
Gráficos de SkiaSharp en Xamarin.Forms
Requisitos de Xamarin.Forms
11/07/2019 • 3 minutes to read • Edit Online
Plataformas de destino
Las aplicaciones de Xamarin.Forms pueden escribirse para los siguientes sistemas operativos:
iOS 8 o versiones posteriores
Android 5.0 (API 21) o superior (más detalles)
Plataforma universal de Windows de Windows 10 (más detalles)
Se supone que los desarrolladores están familiarizados con .NET Standard.
Compatibilidad con plataforma adicional
El estado de estas plataformas está disponible en el GitHub de Xamarin.Forms:
Samsung Tizen
macOS
GTK#
WPF
Android
Debe tener instalada la plataforma más reciente de Android SDK Tools y de la API de Android. Puede actualizar a
las versiones más recientes con Android SDK Manager.
Además, la versión de compilación o de destino de los proyectos de Android debe establecerse en Usar la última
plataforma instalada, aunque la versión mínima se puede establecer en API 19 para que pueda seguir admitiendo
dispositivos que usen Android 4.4 y versiones más recientes. Estos valores se establecen en Opciones del
proyecto:
Visual Studio
Visual Studio para Mac
Opciones de proyecto > Aplicación > Propiedades de la aplicación
NOTE
Las aplicaciones de Windows no se pueden desarrollar en macOS.
En plataformas obsoletas
No se admiten estas plataformas cuando se usa Xamarin.Forms 3.0 o posterior:
Windows 8.1 / Windows Phone 8.1 WinRT
Windows Phone 8 Silverlight
Instalación de Xamarin
11/07/2019 • 4 minutes to read • Edit Online
Cómo configurar Visual Studio y Xamarin para comenzar a crear aplicaciones móviles con .NET.
4. Cuando esté listo para comenzar la instalación de Visual Studio de 2019, haga clic en el instalar botón en
la esquina inferior derecha:
5. Cuando esté listo para comenzar la instalación de Visual Studio 2017, haga clic en el botón Instalar
situado en la esquina inferior derecha:
En función de la edición de Visual Studio 2017 que vaya a instalar, el proceso de instalación puede tardar
bastante tiempo. Puede usar las barras de progreso para supervisar la instalación:
6. Cuando haya finalizado la instalación de Visual Studio 2017, haga clic en el botón Iniciar para iniciar
Visual Studio:
Vínculos relacionados
Desinstalación de Xamarin
Instrucciones de configuración del firewall de Xamarin
Creación de una primera aplicación de
Xamarin.Forms
11/07/2019 • 5 minutes to read • Edit Online
Vea este vídeo y siga el tutorial para crear una primera aplicación móvil con Xamarin.Forms.
2. Busque "Xamarin" o elija Mobile desde el tipo de proyecto menú. Seleccione el aplicación móvil
(Xamarin.Forms) tipo de proyecto:
3. Elija un nombre de proyecto – en el ejemplo se usa "AwesomeApp":
5. Espere hasta que se restauren los paquetes de NuGet (aparecerá un mensaje de "Restauración completada"
en la barra de estado).
6. Inicie Android Emulator presionando el botón de depuración (o el elemento de menú Depurar > Iniciar
depuración).
7. Edite MainPage.xaml, agregando este XAML antes del final de </StackLayout> :
<Button Text="Click Me" Clicked="Button_Clicked" />
int count = 0;
void Button_Clicked(object sender, System.EventArgs e)
{
count++;
((Button)sender).Text = $"You clicked {count} times.";
}
TIP
Es posible crear y depurar la aplicación de iOS desde Visual Studio con un equipo Mac en red. Consulte las
instrucciones de configuración para obtener más información.
2. Asegúrese de que Android y iOS están seleccionados, con uso compartido del código .NET Standard:
3. Espere hasta que se restauren los paquetes de NuGet (aparecerá un mensaje de "Restauración completada"
en la barra de estado).
4. Inicie Android Emulator presionando el botón de depuración (o el elemento de menú Depurar > Iniciar
depuración).
5. Edite MainPage.xaml, agregando este XAML antes del final de </StackLayout> :
int count = 0;
void Button_Clicked(object sender, System.EventArgs e)
{
count++;
((Button)sender).Text = $"You clicked {count} times.";
}
2. Asegúrese de que Android y iOS están seleccionados, con uso compartido del código .NET Standard:
3. Restaurar paquetes de NuGet, haciendo clic en el botón derecho en la solución:
4. Inicie Android Emulator presionando el botón de depuración (o Ejecutar > Iniciar depuración).
5. Edite MainPage.xaml, agregando este XAML antes del final de </StackLayout> :
int count = 0;
void Handle_Clicked(object sender, System.EventArgs e)
{
count++;
((Button)sender).Text = $"You clicked {count} times.";
}
Pasos siguientes
Único Page Quickstart – compilar una aplicación más funcional.
Ejemplos de Xamarin.Forms: Descarga y ejecución de ejemplos de código y aplicaciones de muestra.
Libro electrónico Creating Mobile Apps (Creación de Mobile Apps): Capítulos detallados que enseñan el
desarrollo de Xamarin.Forms, disponible como archivo PDF y que incluye cientos de ejemplos adicionales.
Crear una aplicación de Xamarin.Forms de página
única
12/07/2019 • 24 minutes to read • Edit Online
Descargar el ejemplo
En este tutorial, obtendrá información sobre cómo:
Crear una aplicación de Xamarin.Forms multiplataforma.
Definir la interfaz de usuario para una página con el lenguaje de marcado de aplicaciones eXtensible (XAML ).
Interactuar con elementos de interfaz de usuario XAML desde el código.
El tutorial le guía a través de la creación de una aplicación de Xamarin.Forms multiplataforma, lo que permite
escribir una nota y enviarlo al almacenamiento del dispositivo. A continuación se muestra la aplicación final:
Requisitos previos
Visual Studio 2019 (versión más reciente), con el desarrollo móvil con .NET carga de trabajo instalada.
Conocimiento de C#.
(opcional) Un equipo Mac emparejado para compilar la aplicación en iOS.
Para obtener más información sobre estos requisitos previos, consulte instalar Xamarin. Para obtener información
sobre cómo conectar Visual Studio 2019 a un host de compilación de Mac, consulte Emparejar con Mac para el
desarrollo de Xamarin.iOS.
3. En el configurar el nuevo proyecto ventana, establezca el nombre del proyecto a notas, elija una
ubicación adecuada para el proyecto y haga clic en el crear botón:
IMPORTANT
Los fragmentos de XAML y C# en este inicio rápido requieren que la solución se denomine Notes. El uso de otro
nombre dará como resultado errores de compilación al copiar el código de este inicio rápido en la solución.
4. En el nueva aplicación multiplataforma cuadro de diálogo, haga clic en aplicación vacíay haga clic en
el Aceptar botón:
Para obtener más información sobre la biblioteca de .NET Standard creada, vea Anatomía de una aplicación
de Xamarin.Forms en Análisis detallado de inicio rápido de Xamarin.Forms.
5. En el Explorador de soluciones, en el proyecto Notes, haga doble clic en MainPage.xaml para abrirlo:
6. En MainPage.xaml, quite todo el código de plantilla y sustitúyalo por el siguiente código:
Este código define mediante declaración la interfaz de usuario para la página, que consta de un Label para
mostrar texto, un Editor para entrada de texto y dos Button instancias que dirigir la aplicación para
guardar o eliminar un archivo. Las dos instancias de Button se disponen horizontalmente en Grid ,
mientras que Label , Editor y Grid se disponen verticalmente en StackLayout . Para obtener más
información sobre la creación de la interfaz de usuario, consulte interfaz de usuario en el análisis detallado
de inicio rápido de Xamarin.Forms.
Guarde los cambios en MainPage.xaml presionando CTRL+S y cierre el archivo.
7. En el Explorador de soluciones, en el proyecto Notes, expanda MainPage.xaml y haga doble clic en
MainPage.xaml.cs para abrirlo:
8. En MainPage.xaml.cs, quite todo el código de plantilla y sustitúyalo por el siguiente código:
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);
}
}
Si hay errores, repita los pasos anteriores y corrija los errores hasta que la solución se compile
correctamente.
2. En la barra de herramientas de Visual Studio, pulse el botón Iniciar (el botón triangular que parece un
botón de reproducción) para iniciar la aplicación en la instancia elegida de Android Emulator:
NOTE
Los pasos siguientes solo deben realizarse si se tiene un equipo Mac emparejado que cumpla los requisitos del
sistema para el desarrollo de Xamarin.Forms.
3. En la barra de herramientas de Visual Studio, haga clic con el botón derecho en el proyecto Notes.iOS y
seleccione Establecer como proyecto de inicio.
4. En la barra de herramientas de Visual Studio, pulse el botón Iniciar (el botón triangular que parece un
botón de reproducción) para iniciar la aplicación en la instancia elegida de iOS Simulator:
Para obtener más información sobre estos requisitos previos, consulte instalar Xamarin. Para obtener información
sobre cómo conectar Visual Studio 2019 a un host de compilación de Mac, consulte Emparejar con Mac para el
desarrollo de Xamarin.iOS.
IMPORTANT
Los fragmentos de XAML y C# en este inicio rápido requieren que la solución se denomine Notes. El uso de otro
nombre dará como resultado errores de compilación al copiar el código de este inicio rápido en la solución.
3. En el cuadro de diálogo New Cross Platform App (Nueva aplicación multiplataforma), haga clic en
Aplicación en blanco, seleccione .NET Standard como estrategia de código de uso compartido y haga
clic en el botón Aceptar:
Para obtener más información sobre la biblioteca de .NET Standard creada, vea Anatomía de una aplicación
de Xamarin.Forms en Análisis detallado de inicio rápido de Xamarin.Forms.
4. En el Explorador de soluciones, en el proyecto Notes, haga doble clic en MainPage.xaml para abrirlo:
Este código define mediante declaración la interfaz de usuario para la página, que consta de un Label para
mostrar texto, un Editor para entrada de texto y dos Button instancias que dirigir la aplicación para
guardar o eliminar un archivo. Las dos instancias de Button se disponen horizontalmente en Grid ,
mientras que Label , Editor y Grid se disponen verticalmente en StackLayout . Para obtener más
información sobre la creación de la interfaz de usuario, consulte interfaz de usuario en el análisis detallado
de inicio rápido de Xamarin.Forms.
Guarde los cambios en MainPage.xaml presionando CTRL+S y cierre el archivo.
6. En el Explorador de soluciones, en el proyecto Notes, expanda MainPage.xaml y haga doble clic en
MainPage.xaml.cs para abrirlo:
7. En MainPage.xaml.cs, quite todo el código de plantilla y sustitúyalo por el siguiente código:
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);
}
}
Este código define un campo _fileName , que hace referencia a un archivo denominado notes.txt que
almacenará los datos de la nota en la carpeta de datos de la aplicación local para la aplicación. Cuando se
ejecuta el constructor de páginas, el archivo se lee, si existe, y se muestra en el Editor . Al pulsar el botón
Guardar Button , se ejecuta el controlador de eventos OnSaveButtonClicked , que guarda el contenido de
Editor en el archivo. Al pulsar el botón Eliminar Button , se ejecuta el controlador de eventos
OnDeleteButtonClicked , que elimina el archivo, siempre que exista, y quita cualquier texto de Editor . Para
obtener más información acerca de la interacción del usuario, consulte responde a la interacción del usuario
en el análisis detallado de inicio rápido de Xamarin.Forms.
Guarde los cambios en MainPage.xaml.cs presionando CTRL+S y cierre el archivo.
Compilar el tutorial rápido
1. En Visual Studio, seleccione el elemento de menú Compilación > Compilar solución (o presione F6). La
solución se compilará y aparecerá un mensaje de operación correcta en la barra de estado de Visual Studio:
Si hay errores, repita los pasos anteriores y corrija los errores hasta que la solución se compile
correctamente.
2. En la barra de herramientas de Visual Studio, pulse el botón Iniciar (el botón triangular que parece un
botón de reproducción) para iniciar la aplicación en la instancia elegida de Android Emulator:
NOTE
Los pasos siguientes solo deben realizarse si se tiene un equipo Mac emparejado que cumpla los requisitos del
sistema para el desarrollo de Xamarin.Forms.
3. En la barra de herramientas de Visual Studio, haga clic con el botón derecho en el proyecto Notes.iOS y
seleccione Establecer como proyecto de inicio.
4. En la barra de herramientas de Visual Studio, pulse el botón Iniciar (el botón triangular que parece un
botón de reproducción) para iniciar la aplicación en la instancia elegida de iOS Simulator:
Para obtener más información sobre la biblioteca de .NET Standard creada, vea Anatomía de una aplicación
de Xamarin.Forms en Análisis detallado de inicio rápido de Xamarin.Forms.
5. En el Panel de solución, en el proyecto Notes, haga doble clic en MainPage.xaml para abrirlo:
Este código define mediante declaración la interfaz de usuario para la página, que consta de un Label para
mostrar texto, un Editor para entrada de texto y dos Button instancias que dirigir la aplicación para
guardar o eliminar un archivo. Las dos instancias de Button se disponen horizontalmente en Grid ,
mientras que Label , Editor y Grid se disponen verticalmente en StackLayout . Para obtener más
información sobre la creación de la interfaz de usuario, consulte interfaz de usuario en el análisis detallado
de inicio rápido de Xamarin.Forms.
Guarde los cambios en MainPage.xaml eligiendo Archivo > Guardar (o presionando ⌘ + S ) y cierre el
archivo.
7. En el Panel de solución, en el proyecto Notes, expanda MainPage.xaml y haga doble clic en
MainPage.xaml.cs para abrirlo:
8. En MainPage.xaml.cs, quite todo el código de plantilla y sustitúyalo por el siguiente código:
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);
}
}
Este código define un campo _fileName , que hace referencia a un archivo denominado notes.txt que
almacenará los datos de la nota en la carpeta de datos de la aplicación local para la aplicación. Cuando se
ejecuta el constructor de páginas, el archivo se lee, si existe, y se muestra en el Editor . Al pulsar el botón
Guardar Button , se ejecuta el controlador de eventos OnSaveButtonClicked , que guarda el contenido de
Editor en el archivo. Al pulsar el botón Eliminar Button , se ejecuta el controlador de eventos
OnDeleteButtonClicked , que elimina el archivo, siempre que exista, y quita cualquier texto de Editor . Para
obtener más información acerca de la interacción del usuario, consulte responde a la interacción del usuario
en el análisis detallado de inicio rápido de Xamarin.Forms.
Guarde los cambios en MainPage.xaml.cs eligiendo Archivo > Guardar (o presionando ⌘ + S ) y cierre
el archivo.
Compilación del inicio rápido
1. En Visual Studio para Mac, seleccione el elemento de menú Compilación > Compilar todo (o pulse ⌘ +
B ). El proyecto se compilará y aparecerá un mensaje de operación correcta en la barra de herramientas de
Visual Studio para Mac.
Si hay errores, repita los pasos anteriores y corrija los errores hasta que la solución se compile
correctamente.
2. En el panel de solución, seleccione el Notes.iOS proyecto, secundario y seleccione establecer como
proyecto de inicio:
3. En la barra de herramientas de Visual Studio para Mac, pulse el botón Iniciar (el botón triangular similar a
un botón de reproducción) para iniciar la aplicación en la instancia elegida de iOS Simulator:
5. En la barra de herramientas de Visual Studio para Mac, pulse el botón Iniciar (el botón triangular similar a
un botón de reproducción) para iniciar la aplicación en la instancia elegida de Android Emulator:
Pasos siguientes
En este tutorial, ha aprendido cómo:
Crear una aplicación de Xamarin.Forms multiplataforma.
Definir la interfaz de usuario para una página con el lenguaje de marcado de aplicaciones eXtensible (XAML ).
Interactuar con elementos de interfaz de usuario XAML desde el código.
Para activar esta aplicación de página única en una aplicación de varias página, continúe con el siguiente inicio
rápido.
Siguiente
Vínculos relacionados
Notes (ejemplo)
Análisis detallado de inicio rápido de Xamarin.Forms
Realizar la navegación en una aplicación de
Xamarin.Forms de varias páginas
11/07/2019 • 26 minutes to read • Edit Online
descargar el ejemplo
En este tutorial, obtendrá información sobre cómo:
Agregar páginas adicionales a una solución de Xamarin.Forms.
Realizar la navegación entre páginas.
Utilice el enlace de datos para sincronizar datos entre los elementos de la interfaz de usuario y su origen de
datos.
El tutorial le guía a través de cómo convertir una aplicación de Xamarin.Forms multiplataforma de página única,
que puede almacenar una sola nota, en una aplicación de varias página, capaz de almacenar varias notas. A
continuación se muestra la aplicación final:
Requisitos previos
Debe completar correctamente el inicio rápido anterior antes de intentar este inicio rápido. Como alternativa,
descargue el anterior ejemplo de tutorial rápido y usarlo como punto de partida para este inicio rápido.
5. En el Agregar nuevo elemento cuadro de diálogo, seleccione Visual C# elementos > clase, asigne al
nuevo archivo Notay haga clic en el agregar botón:
Esto agregará una clase denominada Nota a la modelos carpeta de la notas proyecto.
6. En Note.cs, quite todo el código de plantilla y sustitúyalo por el código siguiente:
using System;
namespace Notes.Models
{
public class Note
{
public string Filename { get; set; }
public string Text { get; set; }
public DateTime Date { get; set; }
}
}
Esta clase define un Note modelo donde se almacenará los datos sobre todas las notas de la aplicación.
Guarde los cambios en Note.cs presionando CTRL+Sy cierre el archivo.
7. En el Explorador de soluciones, haga doble clic en el notas del proyecto y seleccione Agregar > nuevo
elemento... . En el Agregar nuevo elemento cuadro de diálogo, seleccione Visual C# elementos >
Xamarin.Forms > página de contenido, asigne al nuevo archivo NoteEntryPagey haga clic en el
Agregar botón:
Esto agregará una nueva página denominada NoteEntryPage a la carpeta raíz del proyecto. Esta página
será la segunda página de la aplicación.
8. En NoteEntryPage.xaml, quite todo el código de plantilla y sustitúyalo por el código siguiente:
<?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>
Este código define mediante declaración la interfaz de usuario para la página, que consta de un Editor
para entrada de texto y dos Button instancias que dirigir la aplicación para guardar o eliminar un archivo.
Los dos Button instancias están dispuestas horizontalmente en un Grid , con el Editor y Grid se
dispuestos verticalmente en una StackLayout . Además, el Editor utiliza el enlace de datos para enlazar el
Text propiedad de la Note modelo. Para obtener más información sobre el enlace de datos, vea enlace de
datos en el análisis detallado de inicio rápido de Xamarin.Forms.
Guarde los cambios en NoteEntryPage.xaml presionando CTRL+Sy cierre el archivo.
9. En NoteEntryPage.xaml.cs, quite todo el código de plantilla y sustitúyalo por el código siguiente:
using System;
using System.IO;
using Xamarin.Forms;
using Notes.Models;
namespace Notes
{
public partial class NoteEntryPage : ContentPage
{
public NoteEntryPage()
{
InitializeComponent();
}
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();
}
if (File.Exists(note.Filename))
{
File.Delete(note.Filename);
}
await Navigation.PopAsync();
}
}
}
Este código se almacena un Note instancia, que representa una sola nota, en el BindingContext de la
página. Cuando el guardar Button se presiona el OnSaveButtonClicked se ejecuta el controlador de
eventos, ya sea guarda el contenido de la Editor en un archivo nuevo con un nombre de archivo generado
aleatoriamente, o a un archivo existente si se está actualizando una nota. En ambos casos, el archivo se
almacena en la carpeta de datos de aplicación local para la aplicación. A continuación, el método se desplaza
a la página anterior. Cuando el eliminar Button se presiona el OnDeleteButtonClicked se ejecuta el
controlador de eventos, lo que elimina el archivo, siempre que exista y se desplaza a la página anterior. Para
obtener más información sobre la navegación, consulte navegación en el análisis detallado de inicio rápido
de Xamarin.Forms.
Guarde los cambios en NoteEntryPage.xaml.cs presionando CTRL+Sy cierre el archivo.
WARNING
Al intentar compilar la aplicación en este momento se producirá errores que se corregirán en pasos posteriores.
10. En el Explorador de soluciones, haga doble clic en el notas del proyecto y seleccione Agregar > nuevo
elemento... . En el Agregar nuevo elemento cuadro de diálogo, seleccione Visual C# elementos >
Xamarin.Forms > página de contenido, asigne al nuevo archivo NotesPagey haga clic en el agregar
botón.
Esto agregará una página denominada NotesPage a la carpeta raíz del proyecto. Esta página será la página
raíz de la aplicación.
11. En NotesPage.xaml, quite todo el código de plantilla y sustitúyalo por el código siguiente:
Este código define mediante declaración la interfaz de usuario para la página, que consta de un ListView y
un ToolbarItem . El ListView utiliza enlace de datos para mostrar las notas que se recuperan por la
aplicación y seleccionar una nota, irá a la NoteEntryPage donde se puede modificar la nota. Como
alternativa, puede crearse una nueva nota presionando el ToolbarItem . Para obtener más información
sobre el enlace de datos, vea enlace de datos en el análisis detallado de inicio rápido de Xamarin.Forms.
Guarde los cambios en NotesPage.xaml presionando CTRL+Sy cierre el archivo.
12. En NotesPage.xaml.cs, quite todo el código de plantilla y sustitúyalo por el código siguiente:
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();
}
listView.ItemsSource = notes
.OrderBy(d => d.Date)
.ToList();
}
Este código define la funcionalidad para el NotesPage . Cuando aparezca la página, el OnAppearing se
ejecuta el método, que rellena la ListView con las notas que se han recuperado desde la carpeta de datos
de aplicación local. Cuando el ToolbarItem se presiona el OnNoteAddedClicked se ejecuta el controlador de
eventos. Este método se desplaza a la NoteEntryPage , estableciendo el BindingContext de la NoteEntryPage
a un nuevo Note instancia. Cuando un elemento de la ListView está seleccionado el
OnListViewItemSelected se ejecuta el controlador de eventos. Este método se desplaza a la NoteEntryPage ,
estableciendo el BindingContext de la NoteEntryPage seleccionada Note instancia. Para obtener más
información sobre la navegación, consulte navegación en el análisis detallado de inicio rápido de
Xamarin.Forms.
Guarde los cambios en NotesPage.xaml.cs presionando CTRL+Sy cierre el archivo.
WARNING
Al intentar compilar la aplicación en este momento se producirá errores que se corregirán en pasos posteriores.
13. En el Explorador de soluciones, haga doble clic en App.xaml.cs para abrirlo. A continuación, reemplace
el código existente por el código siguiente:
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());
}
// ...
}
}
Este código agrega una declaración de espacio de nombres para el System.IO espacio de nombres y agrega
una declaración para una variable static FolderPath propiedad de tipo string . El FolderPath propiedad se
utiliza para almacenar la ruta de acceso en el dispositivo donde se almacenarán los datos de la nota.
Además, el código inicializa el FolderPath propiedad en el App constructor e inicializa el MainPage
propiedad sea un NavigationPage que hospeda una instancia de NotesPage . Para obtener más información
sobre la navegación, consulte navegación en el análisis detallado de inicio rápido de Xamarin.Forms.
Guarde los cambios en App.xaml.cs presionando CTRL+S y cierre el archivo.
14. En el Explorador de soluciones, en el notas del proyecto, haga clic en MainPage.xamly seleccione
eliminar. En el cuadro de diálogo que aparece presione el Aceptar botón para quitar el archivo de disco
duro.
Esto quita una página que ya no se utiliza.
15. Compile y ejecute el proyecto en cada plataforma. Para obtener más información, consulte crear la Guía de
inicio rápido.
En el NotesPage presione el + botón para navegar a la NoteEntryPage y escriba una nota. Después de
guardar la nota de la aplicación navegará a la NotesPage.
Escriba un número de notas, de longitud variable, observar el comportamiento de la aplicación.
2. En el panel de solución, seleccione el notas proyecto, secundario y seleccione Agregar > nueva carpeta:
5. En el nuevo archivo cuadro de diálogo, seleccione General > clase vacía, asigne al nuevo archivo Notay
haga clic en el New botón:
Esto agregará una clase denominada Nota a la modelos carpeta de la notas proyecto.
6. En Note.cs, quite todo el código de plantilla y sustitúyalo por el código siguiente:
using System;
namespace Notes.Models
{
public class Note
{
public string Filename { get; set; }
public string Text { get; set; }
public DateTime Date { get; set; }
}
}
Esta clase define un Note modelo donde se almacenará los datos sobre todas las notas de la aplicación.
Guarde los cambios en Note.cs eligiendo archivo > Guardar (o presionando ⌘ + S ) y cierre el archivo.
7. En el panel de solución, seleccione el notas proyecto, con el botón secundario y seleccione Agregar >
nuevo archivo... . En el nuevo archivo cuadro de diálogo, seleccione formularios > formularios
ContentPage XAML, asigne al nuevo archivo NoteEntryPagey haga clic en el New botón:
Esto agregará una nueva página denominada NoteEntryPage a la carpeta raíz del proyecto. Esta página
será la segunda página de la aplicación.
8. En NoteEntryPage.xaml, quite todo el código de plantilla y sustitúyalo por el código siguiente:
Este código define mediante declaración la interfaz de usuario para la página, que consta de un Editor
para entrada de texto y dos Button instancias que dirigir la aplicación para guardar o eliminar un archivo.
Los dos Button instancias están dispuestas horizontalmente en un Grid , con el Editor y Grid se
dispuestos verticalmente en una StackLayout . Además, el Editor utiliza el enlace de datos para enlazar el
Text propiedad de la Note modelo. Para obtener más información sobre el enlace de datos, vea enlace de
datos en el análisis detallado de inicio rápido de Xamarin.Forms.
Guarde los cambios en NoteEntryPage.xaml eligiendo archivo > Guardar (o presionando ⌘ + S ) y
cierre el archivo.
9. En NoteEntryPage.xaml.cs, quite todo el código de plantilla y sustitúyalo por el código siguiente:
using System;
using System.IO;
using Xamarin.Forms;
using Notes.Models;
namespace Notes
{
public partial class NoteEntryPage : ContentPage
{
public NoteEntryPage()
{
InitializeComponent();
}
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();
}
if (File.Exists(note.Filename))
{
File.Delete(note.Filename);
}
await Navigation.PopAsync();
}
}
}
Este código se almacena un Note instancia, que representa una sola nota, en el BindingContext de la
página. Cuando el guardar Button se presiona el OnSaveButtonClicked se ejecuta el controlador de
eventos, ya sea guarda el contenido de la Editor en un archivo nuevo con un nombre de archivo generado
aleatoriamente, o a un archivo existente si se está actualizando una nota. En ambos casos, el archivo se
almacena en la carpeta de datos de aplicación local para la aplicación. A continuación, el método se desplaza
a la página anterior. Cuando el eliminar Button se presiona el OnDeleteButtonClicked se ejecuta el
controlador de eventos, lo que elimina el archivo, siempre que exista y se desplaza a la página anterior. Para
obtener más información sobre la navegación, consulte navegación en el análisis detallado de inicio rápido
de Xamarin.Forms.
Guarde los cambios en NoteEntryPage.xaml.cs eligiendo archivo > Guardar (o presionando ⌘ + S ) y
cierre el archivo.
WARNING
Al intentar compilar la aplicación en este momento se producirá errores que se corregirán en pasos posteriores.
10. En el panel de solución, seleccione el notas proyecto, con el botón secundario y seleccione Agregar >
nuevo archivo... . En el nuevo archivo cuadro de diálogo, seleccione formularios > formularios
ContentPage XAML, asigne al nuevo archivo NotesPagey haga clic en el New botón.
Esto agregará una página denominada NotesPage a la carpeta raíz del proyecto. Esta página será la página
raíz de la aplicación.
11. En NotesPage.xaml, quite todo el código de plantilla y sustitúyalo por el código siguiente:
Este código define mediante declaración la interfaz de usuario para la página, que consta de un ListView y
un ToolbarItem . El ListView utiliza enlace de datos para mostrar las notas que se recuperan por la
aplicación y seleccionar una nota, irá a la NoteEntryPage donde se puede modificar la nota. Como
alternativa, puede crearse una nueva nota presionando el ToolbarItem . Para obtener más información
sobre el enlace de datos, vea enlace de datos en el análisis detallado de inicio rápido de Xamarin.Forms.
Guarde los cambios en NotesPage.xaml eligiendo archivo > Guardar (o presionando ⌘ + S ) y cierre el
archivo.
12. En NotesPage.xaml.cs, quite todo el código de plantilla y sustitúyalo por el código siguiente:
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();
}
listView.ItemsSource = notes
.OrderBy(d => d.Date)
.ToList();
}
Este código define la funcionalidad para el NotesPage . Cuando aparezca la página, el OnAppearing se
ejecuta el método, que rellena la ListView con las notas que se han recuperado desde la carpeta de datos
de aplicación local. Cuando el ToolbarItem se presiona el OnNoteAddedClicked se ejecuta el controlador de
eventos. Este método se desplaza a la NoteEntryPage , estableciendo el BindingContext de la NoteEntryPage
a un nuevo Note instancia. Cuando un elemento de la ListView está seleccionado el
OnListViewItemSelected se ejecuta el controlador de eventos. Este método se desplaza a la NoteEntryPage ,
estableciendo el BindingContext de la NoteEntryPage seleccionada Note instancia. Para obtener más
información sobre la navegación, consulte navegación en el análisis detallado de inicio rápido de
Xamarin.Forms.
Guarde los cambios en NotesPage.xaml.cs eligiendo archivo > Guardar (o presionando ⌘ + S ) y cierre
el archivo.
WARNING
Al intentar compilar la aplicación en este momento se producirá errores que se corregirán en pasos posteriores.
13. En el panel de solución, haga doble clic en App.xaml.cs para abrirlo. A continuación, reemplace el código
existente por el código siguiente:
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());
}
// ...
}
}
Este código agrega una declaración de espacio de nombres para el System.IO espacio de nombres y agrega
una declaración para una variable static FolderPath propiedad de tipo string . El FolderPath propiedad se
utiliza para almacenar la ruta de acceso en el dispositivo donde se almacenarán los datos de la nota.
Además, el código inicializa el FolderPath propiedad en el App constructor e inicializa el MainPage
propiedad sea un NavigationPage que hospeda una instancia de NotesPage . Para obtener más información
sobre la navegación, consulte navegación en el análisis detallado de inicio rápido de Xamarin.Forms.
Guarde los cambios en App.xaml.cs eligiendo Archivo > Guardar (o presionando ⌘ + S ) y cierre el
archivo.
14. En el panel de solución, en el notas del proyecto, haga clic en MainPage.xamly seleccione quitar. En el
cuadro de diálogo que aparece presione el eliminar botón para quitar el archivo de disco duro.
Esto quita una página que ya no se utiliza.
15. Compile y ejecute el proyecto en cada plataforma. Para obtener más información, consulte crear la Guía de
inicio rápido.
En el NotesPage presione el + botón para navegar a la NoteEntryPage y escriba una nota. Después de
guardar la nota de la aplicación navegará a la NotesPage.
Escriba un número de notas, de longitud variable, observar el comportamiento de la aplicación.
Pasos siguientes
En este tutorial, ha aprendido cómo:
Agregar páginas adicionales a una solución de Xamarin.Forms.
Realizar la navegación entre páginas.
Utilice el enlace de datos para sincronizar datos entre los elementos de la interfaz de usuario y su origen de
datos.
Para modificar la aplicación para que almacena sus datos en una base de datos local de SQLite.NET, continúe con
el siguiente inicio rápido.
Siguiente
Vínculos relacionados
Notes (ejemplo)
Análisis detallado de inicio rápido de Xamarin.Forms
Store los datos en una base de datos Local de
SQLite.NET
12/07/2019 • 18 minutes to read • Edit Online
Descargar el ejemplo
En este tutorial, obtendrá información sobre cómo:
Use el Administrador de paquetes de NuGet para agregar un paquete de NuGet a un proyecto.
Store datos localmente en una base de datos de SQLite.NET.
La Guía de inicio rápido le guía a través almacenar datos en una base de datos local de SQLite.NET. A
continuación se muestra la aplicación final:
Requisitos previos
Debe completar correctamente el inicio rápido anterior antes de intentar este inicio rápido. Como alternativa,
descargue el anterior ejemplo de tutorial rápido y usarlo como punto de partida para este inicio rápido.
NOTE
Hay varios paquetes NuGet con nombres similares. El paquete correcto tiene estos atributos:
Autores: Frank A. Krueger
Id.: sqlite-net-pcl
Vínculo de NuGet: sqlite-net-pcl
A pesar del nombre del paquete, este paquete NuGet puede usarse en proyectos de .NET Standard.
namespace Notes.Models
{
public class Note
{
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
public string Text { get; set; }
public DateTime Date { get; set; }
}
}
Esta clase define un Note modelo donde se almacenará los datos sobre todas las notas de la aplicación. El
ID propiedad está marcada con PrimaryKey y AutoIncrement atributos para asegurarse de que cada Note
instancia en la base de datos de SQLite.NET tendrá un identificador único proporcionado por SQLite.NET.
Guarde los cambios en Note.cs presionando CTRL+Sy cierre el archivo.
WARNING
Al intentar compilar la aplicación en este momento se producirá errores que se corregirán en pasos posteriores.
5. En el Explorador de soluciones, agregue una nueva carpeta denominada datos a la notas proyecto.
6. En el Explorador de soluciones, en el notas proyecto, agregar una nueva clase denominada
NoteDatabase a la datos carpeta.
7. En NoteDatabase.cs, reemplace el código existente por el código siguiente:
using System.Collections.Generic;
using System.Threading.Tasks;
using SQLite;
using Notes.Models;
namespace Notes.Data
{
public class NoteDatabase
{
readonly SQLiteAsyncConnection _database;
Esta clase contiene código para crear la base de datos, leen datos, escribir datos en él y eliminar datos. El
código usa API asincrónicas de SQLite.NET que mueven las operaciones de base de datos a subprocesos
en segundo plano. Además, el constructor NoteDatabase toma la ruta de acceso del archivo de base de
datos como un argumento. Esta ruta de acceso será proporcionado por el App clase en el paso siguiente.
Guarde los cambios en NoteDatabase.cs presionando CTRL+Sy cierre el archivo.
WARNING
Al intentar compilar la aplicación en este momento se producirá errores que se corregirán en pasos posteriores.
8. En el Explorador de soluciones, en el notas del proyecto, haga doble clic en App.xaml.cs para abrirlo. A
continuación, reemplace el código existente por el código siguiente:
using System;
using System.IO;
using Xamarin.Forms;
using Notes.Data;
namespace Notes
{
public partial class App : Application
{
static NoteDatabase database;
public App()
{
InitializeComponent();
MainPage = new NavigationPage(new NotesPage());
}
Este código define un Database propiedad que se crea un nuevo NoteDatabase instancia como un
singleton, pasando el nombre de archivo de la base de datos como el argumento para el NoteDatabase
constructor. La ventaja de exponer la base de datos como un singleton es que se crea una conexión de base
de datos única que se mantiene abierta mientras la aplicación se ejecuta, lo que evita el gasto de abrir y
cerrar el archivo de base de datos cada vez que se realiza una operación de base de datos.
Guarde los cambios en App.xaml.cs presionando CTRL+S y cierre el archivo.
WARNING
Al intentar compilar la aplicación en este momento se producirá errores que se corregirán en pasos posteriores.
9. En el Explorador de soluciones, en el notas del proyecto, haga doble clic en NotesPage.xaml.cs para
abrirlo. A continuación, reemplace el OnAppearing método con el código siguiente:
protected override async void OnAppearing()
{
base.OnAppearing();
Este código rellena la ListView con las notas que se almacenan en la base de datos.
Guarde los cambios en NotesPage.xaml.cs presionando CTRL+Sy cierre el archivo.
WARNING
Al intentar compilar la aplicación en este momento se producirá errores que se corregirán en pasos posteriores.
El NoteEntryPage almacena un Note instancia, que representa una sola nota, en el BindingContext de la
página. Cuando el OnSaveButtonClicked se ejecuta el controlador de eventos, el Note instancia se guarda
en la base de datos y la aplicación regresa a la página anterior. Cuando el OnDeleteButtonClicked se ejecuta
el controlador de eventos, el Note instancia se elimina de la base de datos y la aplicación regresa a la
página anterior.
Guarde los cambios en NoteEntryPage.xaml.cs presionando CTRL+Sy cierre el archivo.
11. Compile y ejecute el proyecto en cada plataforma. Para obtener más información, consulte crear la Guía de
inicio rápido.
En el NotesPage presione el + botón para navegar a la NoteEntryPage y escriba una nota. Después de
guardar la nota de la aplicación navegará a la NotesPage.
Escriba un número de notas, de longitud variable, observar el comportamiento de la aplicación.
NOTE
Hay varios paquetes NuGet con nombres similares. El paquete correcto tiene estos atributos:
Autor: Frank A. Krueger
Id.: sqlite-net-pcl
Vínculo de NuGet: sqlite-net-pcl
A pesar del nombre del paquete, este paquete NuGet puede usarse en proyectos de .NET Standard.
namespace Notes.Models
{
public class Note
{
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
public string Text { get; set; }
public DateTime Date { get; set; }
}
}
Esta clase define un Note modelo donde se almacenará los datos sobre todas las notas de la aplicación. El
ID propiedad está marcada con PrimaryKey y AutoIncrement atributos para asegurarse de que cada Note
instancia en la base de datos de SQLite.NET tendrá un identificador único proporcionado por SQLite.NET.
Guarde los cambios en Note.cs eligiendo archivo > Guardar (o presionando ⌘ + S ) y cierre el archivo.
WARNING
Al intentar compilar la aplicación en este momento se producirá errores que se corregirán en pasos posteriores.
5. En el panel de solución, agregue una nueva carpeta denominada datos a la notas proyecto.
6. En el panel de solución, en el notas proyecto, agregar una nueva clase denominada NoteDatabase a la
datos carpeta.
7. En NoteDatabase.cs, reemplace el código existente por el código siguiente:
using System.Collections.Generic;
using System.Threading.Tasks;
using SQLite;
using Notes.Models;
namespace Notes.Data
{
public class NoteDatabase
{
readonly SQLiteAsyncConnection _database;
Esta clase contiene código para crear la base de datos, leen datos, escribir datos en él y eliminar datos. El
código usa API asincrónicas de SQLite.NET que mueven las operaciones de base de datos a subprocesos
en segundo plano. Además, el constructor NoteDatabase toma la ruta de acceso del archivo de base de
datos como un argumento. Esta ruta de acceso será proporcionado por el App clase en el paso siguiente.
Guarde los cambios en NoteDatabase.cs eligiendo archivo > Guardar (o presionando ⌘ + S ) y cierre el
archivo.
WARNING
Al intentar compilar la aplicación en este momento se producirá errores que se corregirán en pasos posteriores.
8. En el panel de solución, en el notas del proyecto, haga doble clic en App.xaml.cs para abrirlo. A
continuación, reemplace el código existente por el código siguiente:
using System;
using System.IO;
using Xamarin.Forms;
using Notes.Data;
namespace Notes
{
public partial class App : Application
{
static NoteDatabase database;
public App()
{
InitializeComponent();
MainPage = new NavigationPage(new NotesPage());
}
Este código define un Database propiedad que se crea un nuevo NoteDatabase instancia como un
singleton, pasando el nombre de archivo de la base de datos como el argumento para el NoteDatabase
constructor. La ventaja de exponer la base de datos como un singleton es que se crea una conexión de base
de datos única que se mantiene abierta mientras la aplicación se ejecuta, lo que evita el gasto de abrir y
cerrar el archivo de base de datos cada vez que se realiza una operación de base de datos.
Guarde los cambios en App.xaml.cs eligiendo Archivo > Guardar (o presionando ⌘ + S ) y cierre el
archivo.
WARNING
Al intentar compilar la aplicación en este momento se producirá errores que se corregirán en pasos posteriores.
9. En el panel de solución, en el notas del proyecto, haga doble clic en NotesPage.xaml.cs para abrirlo. A
continuación, reemplace el OnAppearing método con el código siguiente:
Este código rellena la ListView con las notas que se almacenan en la base de datos.
Guarde los cambios en NotesPage.xaml.cs eligiendo archivo > Guardar (o presionando ⌘ + S ) y cierre
el archivo.
WARNING
Al intentar compilar la aplicación en este momento se producirá errores que se corregirán en pasos posteriores.
10. En el panel de solución, haga doble clic en NoteEntryPage.xaml.cs para abrirlo. A continuación,
reemplace el OnSaveButtonClicked y OnDeleteButtonClicked métodos con el código siguiente:
El NoteEntryPage almacena un Note instancia, que representa una sola nota, en el BindingContext de la
página. Cuando el OnSaveButtonClicked se ejecuta el controlador de eventos, el Note instancia se guarda
en la base de datos y la aplicación regresa a la página anterior. Cuando el OnDeleteButtonClicked se ejecuta
el controlador de eventos, el Note instancia se elimina de la base de datos y la aplicación regresa a la
página anterior.
Guarde los cambios en NoteEntryPage.xaml.cs eligiendo archivo > Guardar (o presionando ⌘ + S ) y
cierre el archivo.
11. Compile y ejecute el proyecto en cada plataforma. Para obtener más información, consulte crear la Guía de
inicio rápido.
En el NotesPage presione el + botón para navegar a la NoteEntryPage y escriba una nota. Después de
guardar la nota de la aplicación navegará a la NotesPage.
Escriba un número de notas, de longitud variable, observar el comportamiento de la aplicación.
Pasos siguientes
En este tutorial, ha aprendido cómo:
Use el Administrador de paquetes de NuGet para agregar un paquete de NuGet a un proyecto.
Store datos localmente en una base de datos de SQLite.NET.
Para aplicar estilo a la aplicación con los estilos XAML, continúe con el siguiente inicio rápido.
Siguiente
Vínculos relacionados
Notes (ejemplo)
Análisis detallado de inicio rápido de Xamarin.Forms
Aplicar estilo a una aplicación de Xamarin.Forms
multiplataforma
13/07/2019 • 10 minutes to read • Edit Online
Descargar el ejemplo
En este tutorial, obtendrá información sobre cómo:
Aplicar estilo a una aplicación de Xamarin.Forms con estilos XAML.
La Guía de inicio rápido le guía en una aplicación de Xamarin.Forms multiplataforma de estilo con estilos XAML. A
continuación se muestra la aplicación final:
Requisitos previos
Debe completar correctamente el inicio rápido anterior antes de intentar este inicio rápido. Como alternativa,
descargue el anterior ejemplo de tutorial rápido y usarlo como punto de partida para este inicio rápido.
<Thickness x:Key="PageMargin">20</Thickness>
</Application.Resources>
</Application>
Este código define un Thickness valor, una serie de Color valores y los estilos implícitos para el
NavigationPage y ContentPage . Observe que estos estilos, que se encuentran en el nivel de aplicación
ResourceDictionary , pueden utilizarse en toda la aplicación. Para obtener más información acerca de la
aplicación de estilos de XAML, vea estilo en el análisis detallado de inicio rápido de Xamarin.Forms.
Guarde los cambios en App.xaml presionando CTRL+Sy cierre el archivo.
3. En el Explorador de soluciones, en el notas del proyecto, haga doble clic en NotesPage.xaml para
abrirlo. A continuación, reemplace el código existente por el código siguiente:
<?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 agrega un estilo implícito para la ListView para el nivel de página ResourceDictionary y
establece el ListView.Margin propiedad a un valor definido en el nivel de aplicación ResourceDictionary .
Tenga en cuenta que el ListView estilo implícito se agregó en el nivel de página ResourceDictionary , ya que
sólo es usado por el NotesPage . Para obtener más información acerca de la aplicación de estilos de XAML,
vea estilo en el análisis detallado de inicio rápido de Xamarin.Forms.
Guarde los cambios en NotesPage.xaml presionando CTRL+Sy cierre el archivo.
4. En el Explorador de soluciones, en el notas del proyecto, haga doble clic en NoteEntryPage.xaml para
abrirlo. A continuación, reemplace el código existente por el código siguiente:
<?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>
</ContentPage>
Este código agrega los estilos implícitos para el Editor y Button vistas en el nivel de página
ResourceDictionary y establece el StackLayout.Margin propiedad a un valor definido en el nivel de
aplicación ResourceDictionary . Tenga en cuenta que el Editor y Button se agregaron los estilos implícitos
en el nivel de página ResourceDictionary , ya que solo consumen el NoteEntryPage . Para obtener más
información acerca de la aplicación de estilos de XAML, vea estilo en el análisis detallado de inicio rápido de
Xamarin.Forms.
Guarde los cambios en NoteEntryPage.xaml presionando CTRL+Sy cierre el archivo.
5. Compile y ejecute el proyecto en cada plataforma. Para obtener más información, consulte crear la Guía de
inicio rápido.
En el NotesPage presione el + botón para navegar a la NoteEntryPage y escriba una nota. En cada
página, observe cómo ha cambiado el estilo desde el inicio rápido anterior.
<Thickness x:Key="PageMargin">20</Thickness>
</Application.Resources>
</Application>
Este código define un Thickness valor, una serie de Color valores y los estilos implícitos para el
NavigationPage y ContentPage . Observe que estos estilos, que se encuentran en el nivel de aplicación
ResourceDictionary , pueden utilizarse en toda la aplicación. Para obtener más información acerca de la
aplicación de estilos de XAML, vea estilo en el análisis detallado de inicio rápido de Xamarin.Forms.
Guarde los cambios en App.xaml eligiendo archivo > Guardar (o presionando ⌘ + S ) y cierre el archivo.
3. En el panel de solución, en el notas del proyecto, haga doble clic en NotesPage.xaml para abrirlo. A
continuación, reemplace el código existente por el código siguiente:
<?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 agrega un estilo implícito para la ListView para el nivel de página ResourceDictionary y
establece el ListView.Margin propiedad a un valor definido en el nivel de aplicación ResourceDictionary .
Tenga en cuenta que el ListView estilo implícito se agregó en el nivel de página ResourceDictionary , ya que
sólo es usado por el NotesPage . Para obtener más información acerca de la aplicación de estilos de XAML,
vea estilo en el análisis detallado de inicio rápido de Xamarin.Forms.
Guarde los cambios en NotesPage.xaml eligiendo archivo > Guardar (o presionando ⌘ + S ) y cierre el
archivo.
4. En el panel de solución, en el notas del proyecto, haga doble clic en NoteEntryPage.xaml para abrirlo. A
continuación, reemplace el código existente por el código siguiente:
<?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>
</ContentPage>
Este código agrega los estilos implícitos para el Editor y Button vistas en el nivel de página
ResourceDictionary y establece el StackLayout.Margin propiedad a un valor definido en el nivel de
aplicación ResourceDictionary . Tenga en cuenta que el Editor y Button se agregaron los estilos implícitos
en el nivel de página ResourceDictionary , ya que solo consumen el NoteEntryPage . Para obtener más
información acerca de la aplicación de estilos de XAML, vea estilo en el análisis detallado de inicio rápido de
Xamarin.Forms.
Guarde los cambios en NoteEntryPage.xaml eligiendo archivo > Guardar (o presionando ⌘ + S ) y
cierre el archivo.
5. Compile y ejecute el proyecto en cada plataforma. Para obtener más información, consulte crear la Guía de
inicio rápido.
En el NotesPage presione el + botón para navegar a la NoteEntryPage y escriba una nota. En cada
página, observe cómo ha cambiado el estilo desde el inicio rápido anterior.
Pasos siguientes
En este tutorial, ha aprendido cómo:
Aplicar estilo a una aplicación de Xamarin.Forms con estilos XAML.
Para obtener más información sobre los aspectos básicos del desarrollo de aplicaciones con Xamarin.Forms,
continúe con el análisis detallado de inicio rápido.
Siguiente
Vínculos relacionados
Notes (ejemplo)
Análisis detallado de inicio rápido de Xamarin.Forms
Análisis detallado de inicio rápido de
Xamarin.Forms
11/07/2019 • 36 minutes to read • Edit Online
Para maximizar la reutilización del código de inicio, las aplicaciones de Xamarin.Forms tienen una
clase única denominada App que es responsable de crear instancias de la primera página que
mostrará la aplicación en cada plataforma, como se muestra en el siguiente ejemplo de código:
using Xamarin.Forms;
namespace Notes
{
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new NavigationPage(new NotesPage());
}
...
}
}
Este código establece la MainPage propiedad de la App clase a un NavigationPage instancia cuyo
contenido es un NotesPage instancia.
Además, el AssemblyInfo.cs archivo contiene un atributo de aplicación único, que se aplica en el
nivel de ensamblado:
using Xamarin.Forms.Xaml;
[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
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);
}
}
}
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());
}
}
}
Xamarin.Forms.Forms.Init (e);
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
...
}
namespace Notes.UWP
{
public sealed partial class MainPage
{
public MainPage()
{
this.InitializeComponent();
this.LoadApplication(new Notes.App());
}
}
}
Interfaz de usuario
Hay cuatro grupos principales de control usados para crear la interfaz de usuario de una
aplicación de Xamarin.Forms:
1. Páginas: las páginas de Xamarin.Forms representan pantallas de aplicaciones móviles
multiplataforma. Usa la aplicación de notas de la ContentPage clase para mostrar pantallas
únicas. Para obtener más información sobre las páginas, consulte Xamarin.Forms Pages
(Páginas de Xamarin.Forms).
2. Vistas: las vistas de Xamarin.Forms son los controles que se muestran en la interfaz de
usuario, como etiquetas, botones y cuadros de entrada de texto. Usa la aplicación finalizada de
notas el ListView , Editor , y Button vistas. Para obtener más información sobre las vistas,
consulte Xamarin.Forms Views (Vistas de Xamarin.Forms).
3. Diseños: los diseños de Xamarin.Forms son contenedores que se usan para crear vistas en
estructuras lógicas. Usa la aplicación de notas de la StackLayout clase para organizar las
vistas en una pila vertical y el Grid clase para organizar botones horizontalmente. Para
obtener más información sobre los diseños, consulte Xamarin.Forms Layouts (Diseños de
Xamarin.Forms).
4. Celdas: las celdas de Xamarin.Forms son elementos especializados que se usan para los
elementos de una lista, y describen cómo debe dibujarse cada elemento de una lista. Usa la
aplicación de notas de la TextCell para mostrar los dos elementos para cada fila en la lista.
Para obtener más información sobre las celdas, consulte Xamarin.Forms Cells (Celdas de
Xamarin.Forms).
En tiempo de ejecución, cada control se asignará a su equivalente nativo, que es lo que se
representará.
Diseño
Usa la aplicación de notas de la StackLayout para simplificar el desarrollo de aplicaciones
multiplataforma al organizar automáticamente las vistas en la pantalla, independientemente del
tamaño de pantalla. Cada elemento secundario se coloca uno detrás del otro, ya sea horizontal o
verticalmente, en el orden en el que se ha agregado. La cantidad de espacio que usará la clase
StackLayout depende de cómo se establezcan las propiedades HorizontalOptions y
VerticalOptions , pero StackLayout intentará usar toda la pantalla de forma predeterminada.
El código XAML siguiente muestra un ejemplo del uso de un StackLayout al diseño del
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>
De forma predeterminada el StackLayout asume una orientación vertical. Sin embargo, se puede
cambiar a una orientación horizontal estableciendo el StackLayout.Orientation propiedad a la
StackOrientation.Horizontal miembro de enumeración.
NOTE
Se puede establecer el tamaño de las vistas a través de la HeightRequest y WidthRequest
propiedades.
NOTE
El archivo de código subyacente de una clase XAML puede tener acceso a un objeto que se ha definido
en XAML con el nombre asignado a él con el atributo x:Name . El valor que se ha asignado a este
atributo tiene las mismas reglas que las variables de C#, ya que debe comenzar con una letra o guion
bajo y no contener espacios incrustados.
Listas
El ListView es responsable de mostrar una colección de elementos verticalmente en una lista.
Cada elemento en el ListView se incluirá en una sola celda.
El siguiente ejemplo de código muestra la ListView desde el NotesPage :
<ListView x:Name="listView"
Margin="{StaticResource PageMargin}"
ItemSelected="OnListViewItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Text}"
Detail="{Binding Date}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Este código rellena la ListView con las notas que se almacenan en la base de datos.
Cuando se selecciona una fila en la ListView , ItemSelected desencadena el evento. Un
controlador de eventos, llamado OnListViewItemSelected , se ejecuta cuando se activa el evento:
El ItemSelected evento puede tener acceso al objeto que se asoció a la celda a través de la
e.SelectedItem propiedad.
Para obtener más información sobre la ListView de clases, vea ListView.
Navegación
Xamarin.Forms proporciona una serie de experiencias de navegación de páginas diferente, en
función del tipo de Page que se use. Para ContentPage navegación instancias puede ser
jerárquica, o no modales. Para obtener información sobre la navegación modal, consulte páginas
modales de Xamarin.Forms.
NOTE
Las clases CarouselPage , MasterDetailPage y TabbedPage proporcionan experiencias de navegación
alternativas. Para obtener más información, consulte Navigation (Navegación).
En la navegación jerárquica, el NavigationPage clase se utiliza para navegar a través de una pila
de ContentPage objetos hacia delante y hacia atrás, según sea necesario. La clase implementa la
navegación como una pila de objetos Page en la que el último en entrar es el primero en salir
(LIFO ). Para pasar de una página a otra, una aplicación insertará una nueva página en la pila de
navegación, donde se convertirá en la página activa. Para volver a la página anterior, la aplicación
mostrará la página actual de la pila de navegación y la nueva página de nivel superior se
convertirá en la página activa.
La clase NavigationPage también agregará una barra de navegación en la parte superior de la
página que muestra un título y un botón Atrás adecuado para la plataforma para volver a la
página anterior.
La primera página que se agrega a una pila de navegación se conoce como el raíz página de la
aplicación y en el ejemplo de código siguiente muestra cómo se consigue en la aplicación de
notas:
public App ()
{
...
MainPage = new NavigationPage (new NotesPage ());
}
Todas las instancias ContentPage tienen una propiedad Navigation que expone métodos para
modificar la pila de la página. Solo se deberían invocar estos métodos si la aplicación incluye una
NavigationPage . Para navegar a la NoteEntryPage , es necesario invocar el método PushAsync
como se muestra en el ejemplo de código siguiente:
Esto hace que el nuevo NoteEntryPage objeto se inserte en la pila de navegación, donde se
convertirá en la página activa.
La página activa se puede extraer de la pila de navegación. Para ello, pulse el botón Atrás del
dispositivo, independientemente de si se trata de un botón físico en el dispositivo o de un botón
en la pantalla. Para volver mediante programación a la página original, el objeto NoteEntryPage
debe invocar el método PopAsync , como se muestra en el ejemplo de código siguiente:
await Navigation.PopAsync();
Para obtener más información sobre la navegación jerárquica, consulte Hierarchical Navigation
(Navegación jerárquica).
Enlace de datos
El enlace de datos se usa para simplificar la forma en que una aplicación de Xamarin.Forms
muestra e interactúa con sus datos. Establece una conexión entre la interfaz de usuario y la
aplicación subyacente. La clase BindableObject contiene gran parte de la infraestructura para
admitir el enlace de datos.
El enlace de datos conecta dos objetos, denominados origen y destino. El objeto de origen
proporciona los datos. El objeto de destino usa (y, a menudo, muestra) los datos del objeto de
origen. Por ejemplo, un Editor (destino objeto) normalmente enlazará su Text propiedad para
un público string propiedad en un origen objeto. En el diagrama siguiente se muestra la
relación de enlace:
El principal beneficio del enlace de datos es que ya no tiene que preocuparse de sincronizar los
datos entre las vistas y el origen de datos. Los cambios en el objeto de origen se insertan
automáticamente en el objeto de destino en segundo plano por medio del marco de enlace,
mientras que los cambios en el objeto de destino pueden insertarse de manera opcional en el
objeto de origen.
Establecer datos de enlace es un proceso de dos pasos:
La propiedad BindingContext del objeto de destino se debe establecer en el de origen.
Es necesario establecer un enlace entre el destino y el origen. En XAML, esto se consigue
mediante la extensión de marcado Binding .
En la aplicación de notas, el destino de enlace es el Editor que muestra una nota, mientras que
el Note instancia establecida como el BindingContext de NoteEntryPage es el enlace código
fuente.
El BindingContext de la NoteEntryPage se establece durante la navegación en páginas, como se
muestra en el ejemplo de código siguiente:
Se establece un enlace entre la propiedad Editor.Text y la propiedad Text del objeto de origen.
Los cambios realizados en el Editor se propagarán automáticamente a la Note objeto. De
forma similar, si se realizan cambios en el Note.Text propiedad, el motor de enlace de
Xamarin.Forms también actualizará el contenido de la Editor . Esto se conoce como enlace
bidireccional.
Para obtener más información sobre el enlace de datos, vea Enlace de datos de Xamarin.Forms.
Aplicación de estilos
A menudo, las aplicaciones de Xamarin.Forms contienen varios elementos visuales que tienen
una apariencia idéntica. Establecer la apariencia de cada elemento visual puede ser repetitiva y
propensas a errores. En su lugar, pueden crearse estilos que definen la apariencia y, a
continuación, se aplica a los elementos visuales necesarios.
El Style clase agrupa una colección de valores de propiedad en un objeto que, a continuación,
se puede aplicar a varias instancias del elemento visual. Los estilos se almacenan en un
ResourceDictionary , ya sea en el nivel de aplicación, el nivel de página o el nivel de vista. Elegir
dónde se puede definir un Style impactos en el que se puede usar:
Style las instancias definidas en el nivel de aplicación se pueden aplicar a lo largo de la
aplicación.
Style las instancias definidas en el nivel de página se pueden aplicar a la página y a sus
elementos secundarios.
Style las instancias definidas en el nivel de vista se pueden aplicar a la vista y a sus
elementos secundarios.
IMPORTANT
Los estilos que se usan en toda la aplicación se almacenan en el diccionario de recursos de la aplicación
para evitar la duplicación. Sin embargo, XAML que es específico de una página no debería incluirse en el
diccionario de recursos de la aplicación, como los recursos, a continuación, se analizarán al iniciarse la
aplicación en lugar de cuando se solicite una página.
Cada Style instancia contiene una colección de uno o varios Setter objetos, con cada Setter
tener un Property y un Value . El Property es el nombre de la propiedad enlazable del
elemento que se aplica el estilo, y el Value es el valor que se aplica a la propiedad. En el ejemplo
de código siguiente se muestra un 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>
NOTE
Aplicar un estilo a una aplicación de Xamarin.Forms tradicionalmente se logra mediante el uso de estilos
XAML. Sin embargo, Xamarin.Forms también admite los elementos de estilo visual con hojas de estilos en
cascada (CSS). Para obtener más información, consulte aplicaciones estilo Xamarin.Forms con hojas de
estilos en cascada (CSS).
Para obtener más información sobre los estilos XAML, vea aplicar estilos a las aplicaciones de
Xamarin.Forms con estilos XAML.
Proporcionar estilos específicos de la plataforma
El OnPlatform las extensiones de marcado le permiten personalizar la apariencia de la interfaz de
usuario en forma de acuerdo con la 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>
Prueba e implementación
Tanto Visual Studio para Mac como Visual Studio ofrecen numerosas opciones para probar e
implementar una aplicación. Depurar aplicaciones es una parte común del ciclo de vida del
desarrollo de la aplicación y ayuda a diagnosticar problemas de código. Para obtener más
información, consulte Set a Breakpoint (Establecer un punto de interrupción), Step Through Code
(Recorrer el código paso a paso) y Output Information to the Log Window (Información de salida
para la ventana Registro).
Los simuladores son un buen lugar para comenzar a implementar y probar una aplicación, y
cuentan con una funcionalidad que resulta útil a la hora de probar las aplicaciones. Sin embargo,
los usuarios no usarán la aplicación final en un simulador, por lo que las aplicaciones deben
probarse en dispositivos reales desde el primer momento y con frecuencia. Para obtener más
información sobre el aprovisionamiento de dispositivos de iOS, consulte Aprovisionamiento de
dispositivos. Para obtener más información sobre el aprovisionamiento de dispositivos de
Android, consulte Configurar el dispositivo para el desarrollo.
Pasos siguientes
Este análisis detallado de ha examinado los aspectos básicos del desarrollo de aplicaciones con
Xamarin.Forms. Se recomienda que, como paso siguiente, lea sobre las funcionalidades que se
indican a continuación:
Existen cuatro grupos de control principales que se usan para crear la interfaz de usuario de
una aplicación de Xamarin.Forms. Para obtener más información, vea Referencia de controles.
El enlace de datos es la técnica que consiste en vincular las propiedades de dos objetos para
que los cambios en una propiedad se reflejen automáticamente en la otra propiedad. Para
obtener más información, vea Enlace de datos.
Xamarin.Forms proporciona una serie de experiencias de navegación de páginas diferente, en
función del tipo de página que se use. Para obtener más información, consulte Navigation
(Navegación).
Los estilos permiten reducir el uso de marcado repetitivo y conseguir que la apariencia de las
aplicaciones pueda cambiarse con mayor facilidad. Para obtener más información, vea
Aplicación de estilos a aplicaciones de Xamarin.Forms.
Las extensiones de marcado XAML extienden las funciones avanzadas y la flexibilidad de
XAML al permitir establecer atributos de elementos desde orígenes distintos de cadenas de
texto literales. Para obtener más información, vea Extensiones de marcado XAML.
Las plantillas de datos permiten definir la presentación de los datos en las vistas admitidas.
Para obtener más información, consulte Data Templates (Plantillas de datos).
Cada página, diseño y control se representan de forma diferente en cada plataforma mediante
una clase Renderer que, a su vez, crea un control nativo, lo organiza en la pantalla y agrega el
comportamiento especificado al código compartido. Los desarrolladores pueden implementar
sus propias clases Renderer personalizadas para personalizar la apariencia o el
comportamiento de un control. Para obtener más información, consulte Custom Renderers
(Representadores personalizados).
Los efectos también permiten personalizar los controles nativos de cada plataforma. Los
efectos se crean en proyectos específicos de la plataforma mediante la creación de subclases
de la clase PlatformEffect . Para usarlos, se adjuntan a un control adecuado de
Xamarin.Forms. Para obtener más información, consulte Effects (Efectos).
El código compartido puede tener acceso a la funcionalidad nativa mediante la clase
DependencyService . Para obtener más información, consulte Accessing Native Features with
DependencyService (Acceso a características nativas con DependencyService).
También es recomendable el libro de Charles Petzold titulado Creating Mobile Apps with
Xamarin.Forms (Creación de aplicaciones móviles con Xamarin.Forms) para obtener más
información sobre Xamarin.Forms. El libro está disponible como un archivo PDF o en una
variedad de formatos de libro electrónico.
Vínculos relacionados
Lenguaje de marcado de aplicaciones eXtensible (XAML )
Enlace de datos
Controls Reference (Referencia de controles)
Extensiones de marcado XAML
Xamarin.Forms Samples (Ejemplos de Xamarin.Forms)
Getting Started Samples (Ejemplos de introducción)
Referencia de la API de Xamarin.Forms
Aprendizaje autoguiado gratuito (vídeo)
Lenguaje de marcado de aplicaciones eXtensible
(XAML)
11/07/2019 • 6 minutes to read • Edit Online
XAML es un lenguaje de marcado declarativo que puede utilizarse para definir las interfaces de usuario. La
interfaz de usuario se define en un archivo XML utilizando la sintaxis XAML, mientras que el comportamiento de
tiempo de ejecución se define en un archivo de código subyacente independiente.
Controles de XAML
Todas las vistas que se definen en Xamarin.Forms pueden hacer referencia a partir de los archivos XAML.
Compilación de XAML
XAML se puede compilar de forma opcional directamente en lenguaje intermedio (IL ) con el compilador XAML
(XAMLC ). Este artículo describe cómo usar XAMLC y sus ventajas.
Modificadores de campo
El x:FieldModifier namespace (atributo) especifica el nivel de acceso para los campos generados para los
elementos XAML con nombre.
Paso de argumentos
XAML puede utilizarse para pasar argumentos a métodos de fábrica o constructores no predeterminados. En este
artículo muestra cómo utilizar los atributos XAML que se pueden usar para pasar argumentos a los constructores
para llamar a métodos de fábrica y para especificar el tipo de argumento genérico.
Propiedades enlazables
En Xamarin.Forms, la funcionalidad de las propiedades de common language runtime (CLR ) se extiende por las
propiedades enlazables. Una propiedad enlazable es un tipo especial de propiedad, donde el valor de propiedad se
realiza el seguimiento por el sistema de propiedades de Xamarin.Forms. Este artículo proporciona una
introducción a las propiedades enlazables y muestra cómo crear y consumirlos.
Propiedades asociadas
Una propiedad adjunta es un tipo especial de propiedad enlazable, definido en una clase pero conectado a otros
objetos y reconocible en XAML como un atributo que contiene una clase y un nombre de propiedad separados por
un punto. Este artículo proporciona una introducción a las propiedades adjuntas y muestra cómo crear y
consumirlos.
Diccionarios de recursos
Recursos XAML son definiciones de objetos que se pueden usar más de una vez. Un ResourceDictionary permite
que los recursos definidos en una sola ubicación y volver a utilizarse en toda una aplicación de Xamarin.Forms. En
este artículo se muestra cómo crear y consumir un ResourceDictionary y cómo combinar una ResourceDictionary
a otro.
Descargar el ejemplo
Las vistas son objetos de interfaz de usuario, como etiquetas, botones y los controles deslizantes que se conocen
normalmente como controles o widgets en otros entornos de programación de gráficos. Las vistas compatibles con
Xamarin.Forms todos se derivan los View clase.
Todas las vistas que se definen en Xamarin.Forms pueden hacer referencia a partir de los archivos XAML.
Vistas de presentación
BoxView
<BoxView Color="Accent"
Muestra un rectángulo de un color determinado. WidthRequest="150"
HeightRequest="150"
HorizontalOptions="Center">
API / guía
Image
<Image Source="https://aka.ms/campus.jpg"
muestra un mapa de bits. Aspect="AspectFit"
HorizontalOptions="Center" />
API / guía
Etiqueta
<Label Text="Hello, Xamarin.Forms!"
Muestra una o varias líneas de texto. FontSize="Large"
FontAttributes="Italic"
HorizontalTextAlignment="Center" />
API / guía
Map
<maps:Map ItemsSource="{Binding Locations}" />
muestra un mapa.
API / guía
WebView
<WebView
Muestra las páginas Web o contenido HTML. Source="https://docs.microsoft.com/xamarin/"
VerticalOptions="FillAndExpand" />
API / guía
Botón
<Button Text="Click Me!"
Muestra el texto en un objeto rectangular. Font="Large"
BorderWidth="1"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Clicked="OnButtonClicked" />
API / guía
ImageButton
<ImageButton Source="XamarinLogo.png"
Muestra una imagen de un objeto rectangular. HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Clicked="OnImageButtonClicked" />
API / guía
Barra de búsqueda
<SearchBar Placeholder="Xamarin.Forms Property"
Muestra una barra de búsqueda, para realizar una búsqueda.
SearchButtonPressed="OnSearchBarButtonPressed" />
API
Para establecer valores de las vistas
CheckBox
<CheckBox IsChecked="true"
Permite la selección de un boolean valor. HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
Guía
Slider
<Slider Minimum="0"
Permite la selección de un double valor desde un intervalo Maximum="100"
continuo. VerticalOptions="CenterAndExpand" />
API / guía
Control de incremento
<Stepper Minimum="0"
Permite la selección de un double valor a partir de un Maximum="10"
intervalo incremental. Increment="0.1"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
API / guía
Modificador
<Switch IsToggled="false"
Permite la selección de un boolean valor. HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
API / guía
DatePicker
<DatePicker Format="D"
Permite la selección de una fecha. VerticalOptions="CenterAndExpand" />
API / guía
TimePicker
<TimePicker Format="T"
Permite la selección de una hora. VerticalOptions="CenterAndExpand" />
API / guía
Entrada
<Entry Keyboard="Email"
Permite que una sola línea de texto que se especifique y se Placeholder="Enter email address"
puede editar. VerticalOptions="CenterAndExpand" />
API / guía
Editor
<Editor VerticalOptions="FillAndExpand" />
Permite varias líneas de texto que se especifique y se puede
editar.
API / guía
ActivityIndicator
<ActivityIndicator IsRunning="True"
Muestra una animación para mostrar que la aplicación esté
implicada en una actividad larga, sin dar ninguna indicación VerticalOptions="CenterAndExpand" />
del progreso.
API
ProgressBar
<ProgressBar Progress=".5"
Muestra una animación para mostrar que la aplicación está VerticalOptions="CenterAndExpand" />
progresando a través de una actividad larga.
API
CollectionView
<CollectionView ItemsSource="{Binding Monkeys}">
muestra una lista desplazable de elementos de datos ItemTemplate="{StaticResource
seleccionable, utilizando las especificaciones de diseño MonkeyTemplate}"
diferente. <CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical"
Span="2" />
</CollectionView.ItemsLayout>
</CollectionView/>
Guía
ListView
<ListView ItemsSource="{Binding Monkeys}">
Muestra una lista desplazable de elementos de datos ItemTemplate="{StaticResource
seleccionable. MonkeyTemplate}" />
API / guía
Selector
<Picker Title="Select a monkey"
Muestra un elemento select de una lista de cadenas de texto. 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>
API / guía
TableView
<TableView Intent="Settings">
Muestra una lista de filas interactivas. <TableRoot>
<TableSection Title="Ring">
<SwitchCell Text="New Voice Mail" />
<SwitchCell Text="New Mail" On="true"
/>
</TableSection>
</TableRoot>
API / guía </TableView>
Vínculos relacionados
Ejemplo de Xamarin.Forms FormsGallery
Xamarin.Forms Samples (Ejemplos de Xamarin.Forms)
Documentación de la API de Xamarin.Forms
Parte 1. Introducción a XAML
11/07/2019 • 31 minutes to read • Edit Online
descargar el ejemplo
En una aplicación de Xamarin.Forms, se usa principalmente para definir el contenido visual de una página XAML
y funciona junto con un C# archivo de código subyacente.
El archivo de código subyacente proporciona compatibilidad de código para el marcado. Juntos, estos dos archivos
contribuyen a una nueva definición de clase que incluye vistas secundarias e inicialización de la propiedad. En el
archivo XAML, se hace referencia a clases y propiedades con los elementos y atributos XML y se establecen
vínculos entre el código y marcado.
Crear la solución
Para comenzar a editar el primer archivo XAML, utilice Visual Studio o Visual Studio para Mac para crear una
nueva solución de Xamarin.Forms. (Seleccione la pestaña siguiente correspondiente a su entorno).
Visual Studio
Visual Studio para Mac
En Windows, use Visual Studio para seleccionar archivo > Nuevo > proyecto en el menú. En el nuevo
proyecto cuadro de diálogo, seleccione Visual C# > multiplataforma a la izquierda y, a continuación,
aplicación móvil (Xamarin.Forms) en la lista en el centro.
Seleccione una ubicación para la solución, asígnele un nombre de XamlSamples (o lo que prefiere) y presione
Aceptar.
En la siguiente pantalla, seleccione el aplicación vacía plantilla y la .NET Standard estrategia de uso compartido
de código:
Presione Aceptar.
Se crean cuatro proyectos en la solución: el XamlSamples biblioteca .NET Standard, XamlSamples.Android,
XamlSamples.iOSy la plataforma Universal de Windows solución de XamlSamples.UWP.
Después de crear el XamlSamples solución, desea probar el entorno de desarrollo seleccionando los diversos
proyectos de plataforma como proyecto de inicio de la solución y crear e implementar la aplicación simple crean
por la plantilla de proyecto en dispositivos reales o emuladores de teléfono.
A menos que necesite escribir código específico de plataforma, el recurso compartido XamlSamples proyecto de
biblioteca de .NET Standard es donde va a pasar prácticamente todo su tiempo de programación. Estos artículos
no se atreviesen fuera de ese proyecto.
Anatomía de un archivo XAML
Dentro de la XamlSamples biblioteca .NET Standard son un par de archivos con los nombres siguientes:
App.XAML, el archivo XAML; y
App.Xaml.cs, un C# código archivo asociado con el archivo XAML.
Necesitará hacer clic en la flecha situada junto a App.xaml para ver el archivo de código subyacente.
Ambos App.xaml y App.xaml.cs contribuyen a una clase denominada App que se deriva de Application . La
mayoría de otras clases con archivos XAML contribuyen a una clase que derive de ContentPage ; esos archivos
usan XAML para definir el contenido visual de una página completa. Es el caso de los dos archivos en el
XamlSamples proyecto:
MainPage.xaml, el archivo XAML; y
MainPage.xaml.cs, el C# archivo de código subyacente.
El MainPage.xaml archivo tiene este aspecto (aunque el formato puede ser un poco 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>
El espacio de nombres XML dos ( xmlns ) declaraciones hagan referencia a los URI, la primera aparentemente en
el sitio web de Xamarin y la segunda en Microsoft. No se moleste en comprobar qué esos URI que quiera. No hay
nada. Son simplemente los URI que pertenecen a Xamarin y Microsoft, y básicamente funcionan como
identificadores de versión.
La primera declaración de espacio de nombres XML significa que las etiquetas definidas en el archivo XAML con
ningún prefijo hacen referencia a las clases de Xamarin.Forms, por ejemplo ContentPage . La segunda declaración
de espacio de nombres define un prefijo de x . Esto sirve para varios elementos y atributos que son intrínsecos de
XAML propio y que son compatibles con otras implementaciones de XAML. Sin embargo, estos elementos y
atributos son ligeramente diferentes según el año incrustado en el URI. Xamarin.Forms es compatible con la
especificación de XAML 2009, pero no todos del mismo.
El local declaración de espacio de nombres permite obtener acceso a otras clases desde el proyecto de biblioteca
.NET Standard.
Al final de la primera etiqueta, el x prefijo se utiliza para un atributo denominado Class . Dado que el uso de este
x prefijo es prácticamente universal para el espacio de nombres XAML, los atributos XAML, como Class casi
siempre se conocen como x:Class .
El x:Class atributo especifica un nombre de clase de .NET completo: el MainPage clase en el XamlSamples espacio
de nombres. Esto significa que este archivo XAML define una clase nueva denominada MainPage en el
XamlSamples espacio de nombres que se deriva de ContentPage : la etiqueta en el que el x:Class atributo aparece.
El x:Class atributo solo puede aparecer en el elemento raíz de un archivo XAML para definir una derivada C#
clase. Se trata de la clase solo nueva definida en el archivo XAML. Todo el contenido que aparece en el archivo
XAML está en su lugar simplemente crear instancias de clases existentes e inicializado.
El MainPage.xaml.cs archivo tiene este aspecto (aparte de sin usar using directivas):
using Xamarin.Forms;
namespace XamlSamples
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
}
}
El MainPage clase se deriva de ContentPage , pero tenga en cuenta el partial definición de clase. Esto sugiere que
debe haber otra definición de clase parcial para MainPage , pero ¿dónde está? Y ¿qué es eso InitializeComponent
método?
Cuando Visual Studio compila el proyecto, analiza el archivo XAML para generar un C# archivo de código. Si
observa la XamlSamples\XamlSamples\obj\Debug directory, encontrará un archivo denominado
XamlSamples.MainPage.xaml.g.cs. La "g" son las siglas de generadas. Se trata de la otra definición de clase
parcial de MainPage que contiene la definición de la InitializeComponent método se llama desde el MainPage
constructor. Estos dos parcial MainPage las definiciones de clase, a continuación, se pueden compilar juntas.
Dependiendo de si el XAML se compila o no, el archivo XAML o en un formato binario del archivo XAML se
incrusta en el archivo ejecutable.
En tiempo de ejecución de código en el proyecto de plataforma concreta llama a un LoadApplication método y
pasa a él una nueva instancia de la App class en la biblioteca .NET Standard. El App crea una instancia de
constructor de clase MainPage . El constructor de esa clase llama a InitializeComponent , que llama a la
LoadFromXaml método que se extrae el archivo XAML (o el binario compilado) de la biblioteca .NET Standard.
LoadFromXaml Inicializa todos los objetos definidos en el archivo XAML, se conectan todos juntos en las relaciones
de elementos primarios y secundarios, adjunta los controladores de eventos definidos en el código para los
eventos que se establece en el archivo XAML y establece el árbol resultante de objetos como el contenido de la
página.
Aunque normalmente no es necesario pasar mucho tiempo con archivos de código generado, en ocasiones, en
tiempo de ejecución se producen excepciones en código en los archivos generados, por lo que debe estar
familiarizado con ellas.
Al compilar y ejecutar este programa, el Label elemento aparece en el centro de la página, tal como sugiere el
XAML:
Para los objetos visuales más interesantes, todo lo que necesita es más interesante de XAML.
<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>
El ContentPage.Content etiquetas forman parte de la sintaxis de XAML única. En primer lugar, es posible que
parecen ser XML no válido, pero son válidas. El período no es un carácter especial en XML.
El ContentPage.Contentse denominan etiquetas property (elemento ) etiquetas. Content es una propiedad de
ContentPage y generalmente se establece en una vista única o un diseño con vistas secundarias. Normalmente las
propiedades se convierten en atributos en XAML, pero sería complicado establecer un Content atributo a un
objeto complejo. Por ese motivo, la propiedad se expresa como un elemento XML formada por el nombre de clase
y el nombre de propiedad separados por un punto. Ahora el Content propiedad puede establecerse entre el
ContentPage.Content etiquetas, similar al siguiente:
<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>
</ContentPage.Content>
</ContentPage>
Cada una de las letras poco es un dígito hexadecimal. Aquí es cómo se incluye un canal alfa:
TextColor="#aarrggbb">
Para el canal alfa, tenga en cuenta que es completamente opaco FF y 00 es completamente transparente.
Otros dos formatos le permiten especificar un único dígito hexadecimal para cada canal:
TextColor="#rgb" TextColor="#argb"
En estos casos, el dígito se repite para formar el valor. Por ejemplo, #CF3 es el color RGB CC -FF -33.
Navegación de páginas
Al ejecutar el XamlSamples programa, el MainPage se muestra. Para ver el nuevo HelloXamlPage puede
establecer que, como el inicio de la nueva página en el App.xaml.cs de archivos o vaya a la nueva página desde
MainPage .
Para implementar la navegación, cambie primero el código de la App.xaml.cs constructor para que un
NavigationPage se crea el objeto:
public App()
{
InitializeComponent();
MainPage = new NavigationPage(new MainPage());
}
En el MainPage.xaml.cs constructor, puede crear una sencilla Button y usar el controlador de eventos para
navegar a HelloXamlPage :
public MainPage()
{
InitializeComponent();
Content = button;
}
Puede navegar hasta MainPage utilizando el < Atrás botón en iOS, mediante la flecha izquierda en la parte
superior de la página o en la parte inferior del teléfono en Android, o con la flecha izquierda en la parte superior
de la página en Windows 10.
No dude en experimentar con el XAML para las distintas formas representar el Label . Si tiene que insertar
caracteres Unicode en el texto, puede usar la sintaxis XML estándar. Por ejemplo, para poner el saludo en las
comillas tipográficas, use:
<Label Text="“Hello, XAML!”" … />
Este es su aspecto:
<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" />
namespace XamlSamples
{
public partial class XamlPlusCodePage
{
public XamlPlusCodePage()
{
InitializeComponent();
}
}
}
}
Tenga en cuenta que la asignación de un controlador a un evento tiene la misma sintaxis que asignar un valor a
una propiedad.
Si el controlador para el ValueChanged eventos de la Slider va a utilizar el Label para mostrar el valor actual, el
controlador necesita hacer referencia a ese objeto desde el código. El Label necesita un nombre, que se especifica
con el x:Name atributo.
<Label x:Name="valueLabel"
Text="A simple Label"
Font="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
O bien, podría obtener el controlador de la Slider objeto que genera este evento desde el sender argumento y
obtener el Value propiedad desde que:
Al ejecutar el programa, en primer lugar el Label no muestra el Slider valor porque el ValueChanged aún no ha
desencadenado el evento. Pero cualquier manipulación de los Slider hace que el valor que se mostrará:
Ahora el Button . Vamos a simular una respuesta a un Clicked eventos mediante una alerta con el Text del
botón. El controlador de eventos puede difundir con seguridad el sender argumento para un Button y, a
continuación, obtener acceso a sus propiedades:
El método se define como async porque el DisplayAlert método es asincrónico y debe ir precedido por el await
operador, que se devuelve cuando se completa el método. Dado que este método obtiene la Button
desencadenando el evento desde el sender argumento, el mismo controlador podría usarse para varios botones.
Ha visto que un objeto definido en XAML puede desencadenar un evento que se controla en el archivo de código
subyacente y que el archivo de código subyacente puede tener acceso a un objeto definido en XAML con el
nombre asignado a él con el x:Name atributo. Estas son las dos maneras fundamentales que interactúan de código
y XAML.
Algunas características adicionales sobre cómo funciona el XAML se puede deducir examinando recién generado
XamlPlusCode.xaml.g.cs archivo, que ahora incluye cualquier nombre asignado a cualquier x:Name atributo
como un campo privado. Esta es una versión simplificada de ese archivo:
La declaración de este campo permite que la variable se usan libremente en cualquier lugar dentro de la
XamlPlusCodePage archivo de clase parcial en su jurisdicción. En tiempo de ejecución, el campo se asigna después
de que se ha analizado el XAML. Esto significa que el valueLabel campo es null cuando el XamlPlusCodePage
constructor comienza válido, pero después InitializeComponent se llama.
Después de InitializeComponent devuelve el control vuelve al constructor, se han construido los objetos visuales
de la página como si se tenía inicializados en el código y crea una instancia. El archivo XAML ya no desempeña
ningún rol en la clase. Puede manipular estos objetos en la página de cualquier manera que desee, por ejemplo,
mediante la adición de vistas para la StackLayout , o la configuración de la Content propiedad de la página a otra
cosa completamente. Se puede "recorrer el árbol" examinando el Content propiedad de la página y los elementos
de la Children colecciones de diseños. Puede establecer las propiedades de las vistas que se tiene acceso de esta
forma, o controladores de eventos se les asignan dinámicamente.
No dude. Es la página y XAML es sólo una herramienta para crear su contenido.
Resumen
Con esta introducción, ha visto cómo contribuir con un archivo XAML y el archivo de código para una definición
de clase, y cómo interactúan los archivos XAML y código. Pero XAML también tiene sus propias características
sintácticas únicas que le permiten que se usará de forma muy flexible. Puede empezar a explorar estos en parte 2.
Sintaxis XAML esencial.
Vínculos relacionados
XamlSamples
Parte 2. Sintaxis XAML esencial
Parte 3. Extensiones de marcado XAML
Parte 4. Conceptos básicos del enlace de datos
Parte 5. Desde el enlace de datos a MVVM
Parte 2. Sintaxis XAML esencial
11/07/2019 • 18 minutes to read • Edit Online
descargar el ejemplo
XAML está diseñado principalmente para crear instancias e inicializar objetos. Pero a menudo, se deben
establecer propiedades en objetos complejos que no pueden representarse fácilmente como cadenas XML y a
veces se deben establecer las propiedades definidas por una clase en una clase secundaria. Estas dos necesidades
requieren las características de sintaxis XAML esencial de los elementos de propiedad y las propiedades adjuntas.
Elementos de propiedad
En XAML, las propiedades de las clases normalmente se establecen como atributos XML:
Sin embargo, hay una manera alternativa de establecer una propiedad en XAML. Para probar esta alternativa con
TextColor , primero elimine existente TextColor configuración:
</Label>
Dentro de estas etiquetas, agregue las etiquetas inicial y final que se componen de nombre de clase y un nombre
de propiedad separados por un período de:
</Label.TextColor>
</Label>
Establezca el valor de propiedad como contenido de estas nuevas etiquetas, similar al siguiente:
<Label Text="Hello, XAML!"
VerticalOptions="Center"
FontAttributes="Bold"
FontSize="Large">
<Label.TextColor>
Aqua
</Label.TextColor>
</Label>
Estas dos maneras de especificar el TextColor propiedad son funcionalmente equivalentes, pero no use las dos
maneras para la misma propiedad ya que podría ser establecer de forma efectiva la propiedad dos veces y podría
ser ambiguo.
Con esta nueva sintaxis, se puede introducir cierta terminología útil:
Label es un elemento object. Es un objeto Xamarin.Forms expresado como un elemento XML.
Text , VerticalOptions , FontAttributes y FontSize son atributos de la propiedad. Son propiedades de
Xamarin.Forms expresadas como atributos XML.
En ese fragmento final, TextColor se ha convertido en un elemento property. Es una propiedad de
Xamarin.Forms, pero ahora es un elemento XML.
En primer lugar parecer la definición de propiedad, es posible que los elementos en sean una infracción de la
sintaxis XML, pero no lo es. El período no tiene ningún significado especial en XML. Para un descodificador de
XML, Label.TextColor es simplemente un elemento secundario normal.
En XAML, sin embargo, esta sintaxis es muy especial. Una de las reglas de los elementos de propiedad es que
nada puede aparecer en la Label.TextColor etiqueta. El valor de la propiedad siempre se define como contenido
entre el elemento de propiedad etiquetas inicial y final.
Puede usar la sintaxis de elemento de propiedad en más de una propiedad:
O bien, puede usar sintaxis de elemento de propiedad para todas las propiedades:
<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>
En primer lugar, sintaxis de elemento de propiedad pueden parecer un reemplazo extiende innecesario para algo
comparativamente bastante simple y, en estos ejemplos que es ciertamente el caso.
Sin embargo, la sintaxis de elemento de propiedad es de importancia fundamental cuando el valor de una
propiedad es demasiado complejo para expresarse como una cadena simple. Dentro de las etiquetas de elemento
de propiedad puede crear una instancia de otro objeto y establecer sus propiedades. Por ejemplo, se puede
establecer explícitamente una propiedad como VerticalOptions a un LayoutOptions valor con valores de
propiedad:
<Label>
...
<Label.VerticalOptions>
<LayoutOptions Alignment="Center" />
</Label.VerticalOptions>
</Label>
Otro ejemplo: El Grid tiene dos propiedades denominadas RowDefinitions y ColumnDefinitions . Estas dos
propiedades son de tipo RowDefinitionCollection y ColumnDefinitionCollection , que son colecciones de
RowDefinition y ColumnDefinition objetos. Deberá utilizar la sintaxis de elemento de propiedad para establecer
estas colecciones.
Este es el comienzo del archivo XAML para un GridDemoPage (clase), que muestra las etiquetas de elemento de
propiedad para el RowDefinitions y ColumnDefinitions colecciones:
<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>
Tenga en cuenta la sintaxis abreviada para la definición de celdas de tamaño automático, las de ancho de píxel y el
alto y configuración de estrella.
Propiedades asociadas
Ya ha visto que la Grid requiere que los elementos de propiedad para el RowDefinitions y ColumnDefinitions
recopilaciones para definir las filas y columnas. Sin embargo, también debe haber alguna manera para el
programador indicar la fila y columna donde cada miembro secundario de la Grid reside.
Dentro de la etiqueta para cada miembro secundario de la Grid especificar la fila y columna de ese elemento
secundario con los siguientes atributos:
Grid.Row
Grid.Column
Los valores predeterminados de estos atributos son 0. También puede indicar si un elemento secundario abarca
más de una fila o columna con estos atributos:
Grid.RowSpan
Grid.ColumnSpan
<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>
<BoxView Color="Silver"
HeightRequest="0"
Grid.Row="0" Grid.Column="1" />
<BoxView Color="Teal"
Grid.Row="1" Grid.Column="0" />
</Grid>
</ContentPage>
El Grid.Row y Grid.Column configuración 0 no son necesarias, pero se incluyen con carácter general para una
mayor claridad.
Este es su aspecto:
A juzgar únicamente por la sintaxis, estos Grid.Row , Grid.Column , Grid.RowSpan , y Grid.ColumnSpan atributos
aparecen como campos estáticos ni propiedades de Grid , pero, curiosamente, Grid no define nada con el
nombre Row , Column , RowSpan , o ColumnSpan .
En su lugar, Griddefine cuatro propiedades enlazables denominadas RowProperty , ColumnProperty ,
RowSpanProperty , y ColumnSpanProperty . Estos son tipos especiales de propiedades enlazables conocidos como
propiedades adjuntas. Que define el Grid clase pero establece en elementos secundarios de la Grid .
Cuando se desea usarlas las propiedades adjuntas de código, el Grid clase proporciona métodos estáticos
denominados SetRow , GetColumn , y así sucesivamente. Pero en XAML, estas propiedades adjuntas se establecen
como atributos en los elementos secundarios de la Grid mediante nombres de propiedades simples.
Las propiedades adjuntas siempre son reconocibles en archivos XAML como atributos que contiene una clase y
un nombre de propiedad separados por un punto. Se denominan propiedades adjuntas porque ya están definidas
por una clase (en este caso, Grid ) pero conectado a otros objetos (en este caso, los elementos secundarios de la
Grid ). Durante el diseño, el Grid puede consultar los valores de estas propiedades adjuntas para saber dónde
colocar cada elemento secundario.
El AbsoluteLayout clase define dos propiedades adjuntas denominadas LayoutBounds y LayoutFlags . Este es un
patrón de tablero logrado usando el posicionamiento proporcional y las características de ajuste de tamaño de
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>
Y aquí es:
Para algo parecido a esto, podría preguntarse la conveniencia de usar de XAML. Sin duda, la repetición y la
regularidad del LayoutBounds rectángulo sugiere que se podría generarse mejor en código.
Sin duda es una preocupación legítima y no hay ningún problema con el uso de código y marcado de equilibrio al
definir las interfaces de usuario. Es fácil definir algunos de los objetos visuales en XAML y, a continuación, utilice
el constructor del archivo de código subyacente para agregar algunos elementos visuales más que podrían
generar mejor en bucles.
Propiedades de contenido
En los ejemplos anteriores, el StackLayout , Grid , y AbsoluteLayout objetos se establecen en el Content
propiedad de la ContentPage , y los elementos secundarios de estos diseños son realmente los elementos de la
Children colección. Aunque estos Content y Children propiedades son ningún destino en el archivo XAML.
Sin duda puede incluir el Content y Children propiedades como elementos de propiedad, como en el
XamlPlusCode ejemplo:
<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" />
La verdadera pregunta es: ¿Por qué estos elementos de propiedad no necesarios en el archivo XAML?
Los elementos definidos en Xamarin.Forms para su uso en XAML pueden tener una propiedad de marca en el
ContentProperty atributo de la clase. Si busca la ContentPage clase en la documentación de Xamarin.Forms en
línea, verá que este atributo:
[Xamarin.Forms.ContentProperty("Content")]
public class ContentPage : TemplatedPage
Esto significa que el Content no son necesarias las etiquetas de elemento de propiedad. Cualquier contenido
XML que aparece entre el inicio y finalización ContentPage etiquetas se supone que se asignará a la Content
propiedad.
StackLayout, Grid , AbsoluteLayout , y RelativeLayout todos se derivan Layout<View> , y si busca Layout<T> en
la documentación de Xamarin.Forms, verá otro ContentProperty atributo:
[Xamarin.Forms.ContentProperty("Children")]
public abstract class Layout<T> : Layout ...
Que permite que el contenido del diseño se agregan automáticamente a la Children colección sin explícita
Children etiquetas de elemento de propiedad.
También tienen otras clases ContentProperty definiciones de atributo. Por ejemplo, la propiedad content de
Label es Text . Consulte la documentación de API para que otros usuarios.
También puede hacer algo similar en XAML usando el OnPlatform y On clases. En primer lugar, incluya los
elementos de propiedad para el Padding propiedad cerca de la parte superior de la 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 de estas etiquetas, incluyen una OnPlatform etiqueta. OnPlatform es una clase genérica. Debe especificar
el argumento de tipo genérico, en este caso, Thickness , que es el tipo de Padding propiedad. Afortunadamente,
hay un atributo XAML específicamente para definir argumentos genéricos llama x:TypeArguments . Debe coincidir
con el tipo de la propiedad que 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 tiene una propiedad denominada Platforms que es un IList de On objetos. Use las etiquetas de
elemento de propiedad para la propiedad:
<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>
Ahora agregue On elementos. Para cada uno de ellos, establezca el Platform propiedad y el Value propiedad al
código de marcado para el Thickness propiedad:
<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>
Se puede simplificar este marcado. La propiedad content de OnPlatform es Platforms , por lo que se pueden
quitar esas etiquetas de elemento de propiedad:
<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>
El Platform propiedad de On es de tipo IList<string> , por lo que puede incluir varias plataformas, si los valores
son iguales:
<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>
Dado que Android y UWP se establecen en el valor predeterminado de Padding , que se puede quitar la etiqueta:
<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>
Esta es la manera estándar para establecer un depende de la plataforma Padding propiedad en XAML. Si el
Value configuración no puede representarse mediante una sola cadena, puede definir los elementos de
propiedad para él:
<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>
NOTE
El OnPlatform extensión de marcado también puede utilizarse en XAML para personalizar la apariencia de la interfaz de
usuario en forma de acuerdo con la plataforma. Proporciona la misma funcionalidad que el OnPlatform y On clases, pero
con una representación más concisa. Para obtener más información, consulte OnPlatform Markup Extension.
Resumen
Con los elementos de propiedad y las propiedades adjuntas, gran parte de la sintaxis XAML básica se ha
establecido. Sin embargo, a veces, deberá establecer propiedades a los objetos de una manera indirecta, por
ejemplo, en un diccionario de recursos. Este enfoque se trata en la siguiente parte, parte 3. Las extensiones de
marcado XAML.
Vínculos relacionados
XamlSamples
Parte 1. Introducción a XAML
Parte 3. Extensiones de marcado XAML
Parte 4. Conceptos básicos del enlace de datos
Parte 5. Desde el enlace de datos a MVVM
Parte 3. Extensiones de marcado XAML
11/07/2019 • 22 minutes to read • Edit Online
descargar el ejemplo
Las extensiones de marcado XAML constituyen una característica importante de XAML que permiten establecer
objetos o valores que se hace referencia indirectamente desde otros orígenes de propiedades. Las extensiones de
marcado XAML son especialmente importantes para compartir objetos y hacer referencia a las constantes que
se utilizan en toda una aplicación, pero encuentra su mayor utilidad los enlaces de datos.
En muchos casos, las extensiones de marcado XAML son reconocibles al instante en archivos XAML porque
aparecen como valores de atributo delimitados por llaves: {y}, pero a veces aparecen las extensiones de marcado
en el marcado como elementos convencionales.
Recursos compartidos
Algunas páginas XAML contienen varias vistas con propiedades establecidas en los mismos valores. Por
ejemplo, muchos de los valores de propiedad para estos Button objetos son iguales:
<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" />
</StackLayout>
</ContentPage>
Si una de estas propiedades debe cambiarse, es preferible realizar el cambio de una sola vez en lugar de tres
veces. Si se tratara de código, que es probable que va a utilizar constantes y los objetos de solo lectura estáticos
para ayudar a mantener tales valores coherentes y fáciles de modificar.
En XAML, una conocida solución consiste en almacenar estos valores u objetos en un diccionario de recursos. El
VisualElement clase define una propiedad denominada Resources typu ResourceDictionary , que es un
diccionario con claves de tipo string y valores de tipo object . Puede colocar objetos en este diccionario y, a
continuación, hacer referencia a ellos desde el marcado, todo ello en XAML.
Para usar un diccionario de recursos en una página, incluya un par de Resources etiquetas de elemento de
propiedad. Resulta más conveniente colocar estos elementos en la parte superior de la 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>
<ContentPage.Resources>
<ResourceDictionary>
</ResourceDictionary>
</ContentPage.Resources>
...
</ContentPage>
Ahora se pueden agregar objetos y valores de distintos tipos al diccionario de recursos. Estos tipos deben ser
instanciables. No pueden ser clases abstractas, por ejemplo. Estos tipos también deben tener un constructor
público sin parámetros. Cada elemento requiere una clave del diccionario especificada con el x:Key atributo. Por
ejemplo:
<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>
Estos dos elementos son valores de tipo de estructura LayoutOptions y cada una tiene una clave única y una o
dos propiedades establecidas. En el código y marcado, es mucho más habitual utilizar los campos estáticos de
LayoutOptions , pero aquí es más conveniente establecer las propiedades.
Ahora es necesario establecer la HorizontalOptions y VerticalOptions propiedades de estos botones para estos
recursos, y que se realiza con el StaticResource extensión de marcado XAML:
El StaticResource extensión de marcado siempre está delimitada por llaves e incluye la clave del diccionario.
El nombre lo distingue de DynamicResource , que también admite Xamarin.Forms.
StaticResource
DynamicResource es para las claves del diccionario asociadas con los valores que podrían cambiar en tiempo de
ejecución, mientras que StaticResource tiene acceso a los elementos del diccionario de solo una vez cuando se
construyen los elementos en la página.
Para el BorderWidth propiedad, es necesario almacenar un valor double en el diccionario. XAML define
convenientemente etiquetas para los tipos de datos comunes, como x:Double y 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>
No es necesario ponerlo en tres líneas. Esta entrada del diccionario para este ángulo de giro solo toma una línea
hacia arriba:
<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>
Se pueden hacer referencia a esos dos recursos en la misma manera que el LayoutOptions valores:
Para los recursos de tipo Color , puede usar las mismas representaciones de cadena que utilizar al asignar
directamente los atributos de estos tipos. Los convertidores de tipos se invocan cuando se crea el recurso. Este
es un recurso de tipo Color :
<Color x:Key="textColor">Red</Color>
Ahora todas las propiedades excepto Text definida según la configuración de recursos:
También es posible usar OnPlatform dentro del diccionario de recursos para definir valores diferentes para las
plataformas. Le mostramos cómo un OnPlatform objeto puede ser parte del diccionario de recursos para los
colores 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>
Tenga en cuenta que OnPlatform obtiene tanto un x:Key porque es un objeto en el diccionario de atributos y un
x:TypeArguments atributo porque es una clase genérica. El iOS , Android , y UWP atributos se convierten en
Color valores cuando se inicializa el objeto.
Este es el archivo XAML completo final con tres botones de acceso a seis valores compartidos:
<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}" />
</StackLayout>
</ContentPage>
<StackLayout>
<StackLayout.Resources>
<ResourceDictionary>
<Color x:Key="textColor">Blue</Color>
</ResourceDictionary>
</StackLayout.Resources>
...
</StackLayout>
Descubrirá que el color del texto de los botones ahora es azul. Básicamente, cada vez que el analizador de XAML
encuentra un StaticResource extensión de marcado, se busca en el árbol visual y se usa la primera
ResourceDictionary encuentra que contiene esa clave.
Uno de los tipos más comunes de los objetos almacenados en diccionarios de recursos es Xamarin.Forms Style
, que define una colección de valores de propiedad. Los estilos se tratan en el artículo estilos.
Los programadores nuevos en XAML se preguntan si puede colocar un elemento visual como Label o Button
en un ResourceDictionary . Si bien es seguramente posible, no tiene mucho sentido. El propósito de la
ResourceDictionary es compartir objetos. No se puede compartir un elemento visual. La misma instancia no
puede aparecer dos veces en una sola página.
Hasta ahora, esto no es muy impresionante. Pero la x:Static extensión de marcado puede hacer referencia a
propiedades o campos estáticos desde su propio código. Por ejemplo, este es un AppConstants clase que
contiene algunos campos estáticos que desea usar en varias páginas en toda una aplicación:
using System;
using Xamarin.Forms;
namespace XamlSamples
{
static class AppConstants
{
public static readonly Thickness PagePadding;
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 hacer referencia a los campos estáticos de esta clase en el archivo XAML, necesitará alguna manera de
indicar dentro del archivo XAML donde se encuentra este archivo. Hacer esto con una declaración de espacio de
nombres XML.
Recuerde que los archivos XAML que se creó como parte de la plantilla estándar de XAML de Xamarin.Forms
contienen dos declaraciones de espacio de nombres XML: uno para tener acceso a las clases de Xamarin.Forms y
otro para hacer referencia a las etiquetas y atributos intrínsecos de XAML:
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
Necesitará las declaraciones de espacio de nombres XML adicionales para tener acceso a otras clases. Cada
declaración de espacio de nombres XML adicional define un nuevo prefijo. Para obtener acceso a las clases de
locales a la biblioteca estándar de .NET de aplicación compartida, como AppConstants , a menudo, los
programadores XAML usan el prefijo local . La declaración de espacio de nombres debe indicar el nombre de
espacio de nombres CLR (Common Language Runtime), también conocido como el .NET espacio de nombres,
que es el nombre que aparece en C# namespace definición o en un using directiva:
xmlns:local="clr-namespace:XamlSamples"
También puede definir las declaraciones de espacio de nombres XML para los espacios de nombres de .NET en
cualquier ensamblado al que hace referencia la biblioteca .NET Standard. Por ejemplo, este es un sys prefijo
para .NET standard System espacio de nombres, que se encuentra en la mscorlib ensamblado, que una vez
significaba "Biblioteca común de Microsoft objeto en tiempo de ejecución", pero ahora significa "multilingüe
estándar Objeto en tiempo de ejecución biblioteca común." Se trata de otro ensamblado, también debe
especificar el nombre del ensamblado, en este caso mscorlib:
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Tenga en cuenta que la palabra clave clr-namespace seguida de dos puntos y, a continuación, el nombre de
espacio de nombres. NET, seguido por un punto y coma, la palabra clave assembly , un signo igual y el nombre
del ensamblado.
Sí, sigue una coma clr-namespace pero sigue el signo igual assembly . La sintaxis se definió en este modo
deliberadamente: La mayoría de las declaraciones de espacio de nombres XML hacen referencia a un URI que
empieza como un nombre de esquema de URI http , que siempre está seguido de dos puntos. El clr-namespace
parte de esta cadena está pensado para imitar esta convención.
Ambas declaraciones de espacio de nombres de estos se incluyen en el StaticConstantsPage ejemplo. Tenga en
cuenta que el BoxView dimensiones se establecen en Math.PI y Math.E , pero ha escalado por un factor 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" />
<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>
Quizás la lección más importante que se deben realizar desde este ejemplo es la sintaxis de la extensión de
marcado: Comillas no deben aparecer dentro de las llaves de una extensión de marcado. Al escribir la extensión
de marcado en un archivo XAML, es normal que desee incluir los valores de las propiedades de comillas.
¡ Resistir la tentación!
Resumen
Las extensiones de marcado XAML que se muestra a continuación proporcionan compatibilidad importante para
los archivos XAML. Pero quizás es la extensión de marcado XAML más valiosa Binding , que se trata en la
siguiente parte de esta serie, parte 4. Conceptos básicos del enlace de datos.
Vínculos relacionados
XamlSamples
Parte 1. Introducción a XAML
Parte 2. Sintaxis XAML esencial
Parte 4. Conceptos básicos del enlace de datos
Parte 5. Desde el enlace de datos a MVVM
Parte 4. Conceptos básicos del enlace de datos
11/07/2019 • 21 minutes to read • Edit Online
descargar el ejemplo
Enlaces de datos permiten propiedades de dos objetos se vinculen para que un cambio en uno provoca un
cambio en el otro. Esto es una herramienta muy valiosa, y mientras los enlaces de datos se pueden definir
completamente en código, XAML proporciona accesos directos y comodidad. Por lo tanto, se enlaza una de las
extensiones de marcado más importantes en Xamarin.Forms.
Enlaces de datos
Enlaces de datos conectan las propiedades de dos objetos, denominados el origen y destino. En el código, se
requieren dos pasos: El BindingContext propiedad del objeto de destino debe establecerse en el objeto de
origen y el SetBinding método (a menudo se usa junto con el Binding clase) debe invocarse en el objeto de
destino para enlazar una propiedad de ese objeto a una propiedad del origen de objeto.
La propiedad de destino debe ser una propiedad enlazable, lo que significa que el objeto de destino debe
derivar de BindableObject . La documentación de Xamarin.Forms en línea indica qué propiedades son
propiedades enlazables. Una propiedad de Label como Text está asociado con la propiedad enlazable
TextProperty .
En el marcado, también debe realizar los mismos dos pasos que son necesarios en el código, salvo que el
Binding extensión de marcado ocupa el lugar de la SetBinding llamar y la Binding clase.
Sin embargo, al definir los enlaces de datos en XAML, hay varias maneras de establecer el BindingContext del
objeto de destino. A veces se establece desde el archivo de código subyacente, en ocasiones, con un
StaticResource o x:Static extensión de marcado y a veces como el contenido de BindingContext etiquetas
de elemento de propiedad.
Los enlaces se usan con mayor frecuencia para conectarse a los objetos visuales de un programa con un
modelo de datos subyacente, normalmente en una realización de la arquitectura de aplicación MVVM (Model-
View -ViewModel), como se describe en parte 5. Enlaces de datos a MVVM, pero también son posibles otros
escenarios.
<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" />
El Slider contiene un x:Name atributo que se hace referencia a los dos Label vistas mediante el x:Reference
extensión de marcado.
El x:Reference extensión de enlace define una propiedad denominada Name para establecer en el nombre del
elemento que se hace referencia, en este caso slider . Sin embargo, el ReferenceExtension clase que define el
x:Reference extensión de marcado también define un ContentProperty atributo Name , lo que significa que no
requiere de forma explícita. Solo para diversas, la primera x:Reference incluye "nombre =" pero no así la
segunda:
BindingContext="{x:Reference Name=slider}"
…
BindingContext="{x:Reference slider}"
El Bindingpropia extensión de marcado puede tener varias propiedades, al igual que el BindingBase y
Binding clase. El ContentProperty para Binding es Path , pero la "ruta de acceso =" si la ruta de acceso es el
primer elemento de parte de la extensión de marcado que se puede omitir el Binding extensión de marcado.
El primer ejemplo tiene "ruta de acceso =", pero omite el segundo ejemplo:
Rotation="{Binding Path=Value}"
…
Text="{Binding Value, StringFormat='The angle is {0:F0} degrees'}"
Text="{Binding Value,
StringFormat='The angle is {0:F0} degrees'}"
El modo de enlace
Una vista única puede tener enlaces de datos en varias de sus propiedades. Sin embargo, cada vista solo puede
tener un BindingContext , por lo que varios enlaces de datos en esa vista, deben hacer referencia a propiedades
del mismo objeto.
La solución a este y otros problemas implica la Mode propiedad, que se establece en un miembro de la
BindingMode enumeración:
Default
OneWay : los valores se transfieren desde el origen al destino
OneWayToSource : los valores se transfieren desde el destino al origen
TwoWay : los valores se transfieren ambos sentidos entre el origen y destino
OneTime : datos van desde el origen al destino, pero solo cuando el BindingContext cambios
El programa siguiente muestra un uso habitual de la OneWayToSource y TwoWay modos de enlace. Cuatro
Slider vistas están pensadas para controlar la Scale , Rotate , RotateX , y RotateY las propiedades de un
Label . En primer lugar, parece como si estas cuatro propiedades de la Label debe ser los destinos de enlace
de datos porque cada una se establece un Slider . Sin embargo, el BindingContext de Label puede ser un
solo objeto, y hay cuatro controles deslizantes diferentes.
Por ese motivo, todos los enlaces se establecen aparentemente hacia atrás formas: El BindingContext de cada
uno de los controles cuatro deslizantes se establece en el Label , y los enlaces se establecen en el Value las
propiedades de los controles deslizantes. Mediante el uso de la OneWayToSource y TwoWay modos, estos Value
propiedades pueden establecer las propiedades de origen, que son el Scale , Rotate , RotateX , y RotateY
propiedades de la 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>
Los enlaces en tres de los Slider las vistas son OneWayToSource , lo que significa que el Slider valor provoca
un cambio en la propiedad de su BindingContext , que es el Label denominado label . Estos tres Slider
vistas provocan cambios en el Rotate , RotateX , y RotateY propiedades de la Label .
Sin embargo, el enlace para el Scale propiedad es TwoWay . Esto es porque el Scale propiedad tiene un valor
predeterminado de 1 y usar un TwoWay enlace hace que el Slider inicial del valor que se establecerá en 1 en
lugar de 0. Si fuera ese enlace OneWayToSource , Scale inicialmente se establecería la propiedad en 0 de la
Slider valor predeterminado. El Label no estará visible y que podría provocar confusión en el usuario.
NOTE
El VisualElement clase también tiene ScaleX y ScaleY propiedades, que escalen el VisualElement en los ejes x y
y respectivamente.
Sin embargo, los elementos de la ListView colección puede mostrarse como desee mediante el uso de un
plantilla, lo que implica una clase que deriva de Cell . La plantilla se clona para todos los elementos de la
ListView , y los enlaces de datos que se han establecido en la plantilla se transfieren a los clones individuales.
Muy a menudo, deseará crear una celda personalizada para estos elementos mediante el ViewCell clase. Este
proceso es un tanto confuso en código, pero en XAML resulta muy sencillo.
Incluye en el XamlSamples proyecto es una clase llamada NamedColor . Cada NamedColor objeto tiene Name y
FriendlyName las propiedades de tipo string y un Color propiedad de tipo Color . Además, NamedColor tiene
141 campos estáticos de sólo lectura de tipo Color correspondientes a los colores definidos en
Xamarin.Forms Color clase. Crea un constructor estático una IEnumerable<NamedColor> colección que contiene
NamedColor objetos correspondientes a estos campos estáticos y se asigna a su público estático All
propiedad.
Establecimiento estático NamedColor.All propiedad a la ItemsSource de un ListView es fácil mediante el
x:Static extensión de marcado:
<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">
</ContentPage>
La presentación resultante se establece que los elementos son realmente del tipo XamlSamples.NamedColor :
El Label elemento está establecido en el View propiedad de la ViewCell . (El ViewCell.View etiquetas no son
necesarios porque el View propiedad es la propiedad content de ViewCell .) Este marcado se muestra el
FriendlyName propiedad de cada uno NamedColor objeto:
Mucho mejor. Ahora todo lo necesario es refinar la plantilla de elemento con el color real y obtener más
información. Para admitir esta plantilla, algunos valores y los objetos se han definido en el diccionario de
recursos de la 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>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout Orientation="Horizontal"
Spacing="0">
<Label Text="{Binding Color.R,
Converter={StaticResource intConverter},
ConverterParameter=255,
StringFormat='R={0:X2}'}" />
Tenga en cuenta el uso de OnPlatform para definir el tamaño de un BoxView y el alto de la ListView filas.
Aunque los valores para todas las plataformas son iguales, el marcado fácilmente podría ser adaptado para
otros valores ajustar la visualización.
namespace XamlSamples
{
class DoubleToIntConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
double multiplier;
El ConvertBack método desempeñan un papel en este programa porque los enlaces son sólo una forma de
origen al destino.
Un enlace hace referencia a un conversor de enlaces con el Converter propiedad. Un conversor de enlaces
también puede aceptar un parámetro especificado con el ConverterParameter propiedad. Para algunos
versatilidad, es cómo se especifica el multiplicador. El conversor de enlaces comprueba el parámetro de
convertidor para válido double valor.
Por lo que se puede compartir entre varios enlaces, se crea una instancia de convertidor en el diccionario de
recursos:
Enlaces de datos de tres hacen referencia a esta instancia. Tenga en cuenta que el Binding extensión de
marcado contiene incrustada StaticResource extensión de marcado:
Este es el resultado:
El ListView es bastante sofisticada en el control de cambios que se produzcan dinámicamente en los datos
subyacentes, pero solo si realizar ciertos pasos. Si la colección de elementos que se asigna a la ItemsSource
propiedad de la ListView cambios en tiempo de ejecución: es decir, si los elementos se pueden agregar a o
quitar de la colección, utilice un ObservableCollection clase para estos elementos. ObservableCollection
implementa el INotifyCollectionChanged interfaz, y ListView instalará un controlador para el
CollectionChanged eventos.
Si las propiedades de los propios elementos cambian en tiempo de ejecución, los elementos de la colección
deben implementar la INotifyPropertyChanged cambios de interfaz y la señal a los valores de propiedad
mediante la PropertyChanged eventos. Esto se muestra en la siguiente parte de esta serie, parte 5. Desde el
enlace de datos a MVVM.
Resumen
Los enlaces de datos proporcionan un mecanismo eficaz para vincular las propiedades entre dos objetos
dentro de una página, o entre objetos visuales y los datos subyacentes. Pero cuando la aplicación comienza a
funcionar con orígenes de datos, un patrón arquitectónico popular aplicación comienza a aparecer como un
paradigma útil. Este tema se trata en parte 5. Enlaces de datos a MVVM.
Vínculos relacionados
XamlSamples
Parte 1. Introducción a XAML (ejemplo)
Parte 2. Sintaxis de XAML esencial (ejemplo)
Parte 3. Extensiones de marcado de XAML (ejemplo)
Parte 5. De enlaces de datos a MVVM (ejemplo)
Parte 5. Enlaces de datos a MVVM
11/07/2019 • 22 minutes to read • Edit Online
descargar el ejemplo
El patrón de arquitectura Model-View -ViewModel (MVVM ) se inventó con XAML en mente. El patrón exige una
separación entre las tres capas de software, la interfaz de usuario XAML, llama a la vista; los datos subyacentes,
denominados modelo; y un intermediario entre la vista y el modelo, se denominan ViewModel. La vista y el
ViewModel a menudo están conectados a través de enlaces de datos definidos en el archivo XAML.
BindingContext para la vista normalmente es una instancia de ViewModel.
Un Simple ViewModel
Como una introducción a ViewModel, veamos primero un programa sin uno. Antes vimos cómo definir una
nueva declaración de espacio de nombres XML para permitir que un archivo XAML para las clases de
referencia de otros ensamblados. Este es un programa que define una declaración de espacio de nombres XML
para el System espacio de nombres:
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Puede usar el programa x:Static para obtener la fecha y hora actuales de estático DateTime.Now propiedad y
establecer que DateTime valor para el BindingContext en un StackLayout :
<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>
</ContentPage>
Por supuesto, el gran problema es que la fecha y hora son una vez que se genera por primera vez cuando la
página de conjunto y nunca cambian:
Un archivo XAML puede mostrar un reloj que siempre se muestra la hora actual, pero necesita algo de código
para ayudar a. Al pensar en términos de MVVM, Model y ViewModel son clases escritas completamente en
código. La vista a menudo es un archivo XAML que hace referencia a las propiedades definidas en el modelo de
vista a través de enlaces de datos.
Un modelo adecuado es que ignoran la persistencia del ViewModel y un ViewModel adecuado es que ignoran
la persistencia de la vista. Sin embargo, muy a menudo, un programador adapta los tipos de datos expuestos
por el ViewModel a los tipos de datos asociados con las interfaces de usuario determinado. Por ejemplo, si un
modelo tiene acceso a una base de datos que contiene las cadenas de caracteres de 8 bits ASCII, necesitaría el
ViewModel convertir entre esas cadenas para cadenas Unicode para acomodar el uso exclusivo de Unicode en
la interfaz de usuario.
En ejemplos sencillos de MVVM (como los mostrados aquí), a menudo hay ningún modelo en absoluto y el
patrón implica simplemente una vista y ViewModel vincula a enlaces de datos.
Este es un modelo de vista de un reloj con una propiedad única denominada DateTime , pero que las
actualizaciones que se DateTime propiedad cada segundo:
using System;
using System.ComponentModel;
using Xamarin.Forms;
namespace XamlSamples
{
class ClockViewModel : INotifyPropertyChanged
{
DateTime dateTime;
public ClockViewModel()
{
this.DateTime = DateTime.Now;
Device.StartTimer(TimeSpan.FromSeconds(1), () =>
{
this.DateTime = DateTime.Now;
return true;
});
}
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("DateTime"));
}
}
}
get
{
return dateTime;
}
}
}
}
También es posible tener acceso a propiedades individuales de la DateTime propiedad del ViewModel mediante
la separación de las propiedades con los puntos:
MVVM interactivo
MVVM con bastante frecuencia se utiliza con los enlaces de datos bidireccional para una vista interactiva
basada en un modelo de datos subyacente.
Esta es una clase denominada HslViewModel que convierte un Color valor en Hue , Saturation ,y Luminosity
valores y viceversa:
using System;
using System.ComponentModel;
using Xamarin.Forms;
using Xamarin.Forms;
namespace XamlSamples
{
public class HslViewModel : INotifyPropertyChanged
{
double hue, saturation, luminosity;
Color color;
Hue = value.Hue;
Saturation = value.Saturation;
Luminosity = value.Luminosity;
}
}
get
{
return color;
}
}
void SetNewColor()
{
Color = Color.FromHsla(Hue, Saturation, Luminosity);
}
Cambia a la Hue , Saturation , y Luminosity propiedades causa el Color propiedad quiere cambiar y los
cambios realizados en Color hace que las tres propiedades cambiar. Esto puede parecer un bucle infinito, salvo
que la clase no invocar el PropertyChanged eventos a menos que realmente ha cambiado la propiedad. Esto
acabe con el bucle de comentarios en caso contrario, no controlado.
El siguiente archivo XAML contiene una BoxView cuyo Color propiedad está enlazada a la Color propiedad
del ViewModel y tres Slider y tres Label vistas enlazado a la Hue , Saturation y Luminosity propiedades:
<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>
El enlace en cada Label es el valor predeterminado OneWay . Solo se necesita para mostrar el valor. Pero el
enlace en cada Slider es TwoWay . Esto permite la Slider van a inicializar desde el modelo de vista. Tenga en
cuenta que el Color propiedad está establecida en Aqua cuando se crea una instancia de ViewModel. Pero un
cambio en el Slider también necesita establecer un nuevo valor para la propiedad en ViewModel, que, a
continuación, calcula un nuevo color.
Con la excepción de la SearchBar y ListView elemento, estos elementos definen dos propiedades:
Command de tipo System.Windows.Input.ICommand
CommandParameter de tipo Object
ViewModel puede definir las propiedades de tipo ICommand . A continuación, puede enlazar estas propiedades
para el Command propiedad de cada uno Button u otro elemento, o quizás una vista personalizada que
implementa esta interfaz. Opcionalmente, puede establecer el CommandParameter propiedad para identificar
individuales Button objetos (u otros elementos) que están enlazados a esta propiedad ViewModel.
Internamente, el Button llamadas la Execute método cada vez que el usuario pulsa el Button , pasando a la
Execute método su CommandParameter .
El CanExecute método y CanExecuteChanged se usan para los casos donde un Button tap puede no ser
actualmente válido, en cuyo caso el Button debe deshabilitarse. El Button llamadas CanExecute cuando el
Command propiedad se establece en primer lugar y en cualquier momento el CanExecuteChanged desencadena el
evento. Si CanExecute devuelve false , Button deshabilita a sí mismo y no genera Execute llamadas.
Para obtener ayuda en Agregar comandos a sus ViewModels, Xamarin.Forms define dos clases que
implementan ICommand : Command y Command<T> donde T es el tipo de los argumentos Execute y CanExecute .
Estas dos clases definen varios constructores más una ChangeCanExecute método que ViewModel puede llamar
para forzar la Command objeto para desencadenar la CanExecuteChanged eventos.
Este es un modelo de vista para un teclado simple que sirve para escribir números de teléfono. Tenga en cuenta
que el Execute y CanExecute método se definen como funciones directamente en el constructor de lambda:
using System;
using System.ComponentModel;
using System.Windows.Input;
using Xamarin.Forms;
namespace XamlSamples
{
class KeypadViewModel : INotifyPropertyChanged
{
string inputString = "";
string displayText = "";
char[] specialChars = { '*', '#' };
// Constructor
public KeypadViewModel()
{
AddCharCommand = new Command<string>((key) =>
{
// Add the key to the input string.
InputString += key;
});
// Public properties
public string InputString
{
protected set
{
{
if (inputString != value)
{
inputString = value;
OnPropertyChanged("InputString");
DisplayText = FormatText(inputString);
// ICommand implementations
public ICommand AddCharCommand { protected set; get; }
Este ViewModel se da por supuesto que el AddCharCommand propiedad está enlazada a la Command propiedad de
varios botones (o cualquier otra cosa que tiene una interfaz de comandos), cada uno de los cuales se identifica
mediante el CommandParameter . Estos botones agregan caracteres a un InputString propiedad, que, a
continuación, se da formato como un número de teléfono para el DisplayText propiedad.
También hay una segunda propiedad de tipo ICommand denominado DeleteCharCommand . Esto está enlazado a
un botón Atrás espaciado, pero el botón debe deshabilitarse si no hay ningún carácter que se va a eliminar.
El teclado siguiente no es como visualmente sofisticado como podría ser. En su lugar, el marcado se ha reducido
al mínimo para mostrar más claramente el uso de la interfaz de comandos:
<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>
<Frame Grid.Column="0"
OutlineColor="Accent">
<Label Text="{Binding DisplayText}" />
</Frame>
<Button Text="⇦"
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>
El Command propiedad de la primera Button que aparece en este marcado se enlaza a la DeleteCharCommand ; el
resto se enlazan a la AddCharCommand con un CommandParameter que es el mismo que el carácter que aparece en
el Button cara. Este es el programa en acción:
Invocar métodos asincrónicos
Los comandos también pueden invocar los métodos asincrónicos. Esto se logra mediante el uso de la async y
await palabras clave al especificar el Execute método:
void Download ()
{
...
}
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"),
El archivo XAML para MainPage define un ListBox cuyo ItemsSource propiedad está establecida en el que
All propiedad y que contiene un TextCell para mostrar el Title y Description las propiedades 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">
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 sencilla con Xamarin.Forms y Prism
Resumen
XAML es una herramienta eficaz para definir las interfaces de usuario en las aplicaciones de Xamarin.Forms,
especialmente cuando el enlace de datos y se usan MVVM. El resultado es una representación limpia, elegante
y potencialmente dispone de herramientas de una interfaz de usuario con toda la compatibilidad en segundo
plano en el código.
Vínculos relacionados
XamlSamples
Parte 1. Introducción a XAML
Parte 2. Sintaxis XAML esencial
Parte 3. Extensiones de marcado XAML
Parte 4. Conceptos básicos del enlace de datos
Compilación de XAML en Xamarin.Forms
11/07/2019 • 2 minutes to read • Edit Online
XAML se puede compilar opcionalmente directamente en lenguaje intermedio (IL ) con el compilador XAML
(XAMLC ).
Compilación de XAML ofrece una serie de ventajas:
Realiza la comprobación en tiempo de compilación de XAML, notificando al usuario de los errores.
Reduce parte del tiempo de carga y creación de instancias para los elementos XAML.
Facilita reducir el tamaño de archivo del ensamblado final al dejar de incluir archivos .xaml.
Compilación de XAML está deshabilitado de forma predeterminada para garantizar la compatibilidad con
versiones anteriores. Puede habilitarse en el nivel de clase y ensamblado agregando la XamlCompilation atributo.
En el ejemplo de código siguiente se muestra cómo habilitar la compilación de XAML en el nivel de ensamblado:
using Xamarin.Forms.Xaml;
...
[assembly: XamlCompilation (XamlCompilationOptions.Compile)]
namespace PhotoApp
{
...
}
En este ejemplo, se realizará la comprobación de todo el XAML contenido dentro del ensamblado de tiempo de
compilación, con errores XAML que se notifica en tiempo de compilación en lugar de tiempo de ejecución. Por lo
tanto, el assembly prefijo para el XamlCompilation atributo especifica que el atributo se aplica a todo el
ensamblado.
NOTE
El XamlCompilation atributo y el XamlCompilationOptions enumeración residen en el Xamarin.Forms.Xaml espacio de
nombres que debe importarse al usarlas.
En el ejemplo de código siguiente se muestra cómo habilitar la compilación de XAML en el nivel de clase:
using Xamarin.Forms.Xaml;
...
[XamlCompilation (XamlCompilationOptions.Compile)]
public class HomePage : ContentPage
{
...
}
En este ejemplo, la comprobación de que el XAML para el tiempo de compilación la HomePage se realizará la clase
y los errores se notifican como parte del proceso de compilación.
NOTE
Enlaces compilados se pueden habilitar para mejorar el rendimiento de enlace de datos en las aplicaciones de
Xamarin.Forms. Para obtener más información, consulte compilado enlaces.
Vínculos relacionados
XamlCompilation
XamlCompilationOptions
Cuadro de herramientas de XAML de Xamarin.Forms
11/07/2019 • 2 minutes to read • Edit Online
Visual Studio 2017 versión 15,8 y Visual Studio para Mac 7.6 ahora tienen un cuadro de herramientas disponible al
editar archivos XAML de Xamarin.Forms. El cuadro de herramientas contiene todos los controles integrados de
Xamarin.Forms y diseños, que se pueden arrastrar en el editor de XAML.
Visual Studio
Visual Studio para Mac
En Visual Studio 2017, abra un archivo XAML de Xamarin.Forms para su edición. Se puede mostrar el cuadro de
herramientas, presione Ctrl + W, X en el teclado, o eligiendo el Ver > cuadro de herramientas elemento de
menú.
El cuadro de herramientas puede ser oculto y acoplada como otros paneles en Visual Studio 2017, con los iconos
en la parte superior derecha o en el menú contextual. El cuadro de herramientas XAML de Xamarin.Forms tiene
opciones de vista personalizada que se pueden cambiar con el botón secundario en cada sección. Alternar el vista
de lista opción para cambiar entre la lista y vistas compactas:
Cuando se abre un archivo XAML de Xamarin.Forms para su edición, arrastre cualquier control o diseño del
cuadro de herramientas en el archivo, y aprovechar las ventajas de Intellisense para personalizar la interfaz de
usuario.
Controlador de vista previa XAML para
Xamarin.Forms
11/07/2019 • 5 minutes to read • Edit Online
Información general
El controlador de vista previa de XAML muestra el aspecto de la página XAML de Xamarin.Forms en iOS y
Android. Al realizar cambios en el XAML, verá una vista previa inmediatamente junto con el código. El controlador
de vista previa de XAML está disponible en Visual Studio y Visual Studio para Mac.
Introducción
Visual Studio 2019
Puede abrir a la vista previa de XAML, haga clic en las flechas en el panel de vista de división. Si desea cambiar el
valor predeterminado divide el comportamiento de la vista, use el Herramientas > Opciones > Xamarin >
controlador de vista previa de formularios cuadro de diálogo. En este cuadro de diálogo, puede seleccionar la
vista de documento predeterminada y la orientación dividida.
Al abrir un archivo XAML, se abrirá el editor en tamaño completo o en siguiente para el controlador de vista
previa, en función de la configuración seleccionada en el Herramientas > Opciones > Xamarin > controlador
de vista previa de formularios cuadro de diálogo. Sin embargo, se puede cambiar la división para cada archivo
en la ventana del editor.
Controles de vista previa XAML
Elija si desea ver el código, el controlador de vista previa de XAML, o ambos mediante la selección de estos
botones en la división ver panel. El botón central intercambia qué lado de la vista previa y el código están en:
if (DesignMode.IsDesignModeEnabled)
{
// Previewer only code
}
if (!DesignMode.IsDesignModeEnabled)
{
// Don't run in the Previewer
}
Esta propiedad es útil si inicializar una biblioteca en el constructor de la página que no se puede ejecutar en
tiempo de diseño.
Solución de problemas
Compruebe los siguientes problemas y la foros de Xamarin, si el controlador de vista previa no funciona.
Controlador de vista previa de XAML no está visible o muestra un error
Puede tardar algún tiempo para el controlador de vista previa en iniciarse, verá "Inicializando Render" hasta
que esté listo.
Intente cerrar y volver a abrir el archivo XAML.
Asegúrese de que su App clase tiene un constructor sin parámetros.
Comprobar la versión de Xamarin.Forms: debe ser al menos 3.6 de Xamarin.Forms. Puede actualizar a la
última versión de Xamarin.Forms a través de NuGet.
Comprobación de la instalación de JDK - vista previa de Android requiere al menos JDK 8.
Pruebe cualquier ajuste inicializa las clases en la página C# código subyacente en
if (!DesignMode.IsDesignModeEnabled) .
Algunos diseños son difíciles de visualizar sin datos. Utilice estos consejos para sacar el máximo partido de la vista
previa de las páginas de datos con mucha actividad en la vista previa de XAML.
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Después de agregar los espacios de nombres, puede colocar d: delante de cualquier atributo o un control para
mostrarlo en la vista previa de XAML. Elementos con d: no se muestran en tiempo de ejecución.
Por ejemplo, puede agregar texto a una etiqueta que normalmente tiene datos enlazados a él.
En este ejemplo, sin d:Text , el controlador de vista previa de XAML mostraría nada para la etiqueta. En su lugar,
muestra "Name". donde la etiqueta tendrá datos reales en tiempo de ejecución.
Puede usar d: con cualquier atributo para un control de Xamarin.Forms, como colores, tamaños de fuente y
espaciado. Incluso puede agregarlo al propio control:
<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 ejemplo muestra un ListView de tres TextCells en la vista previa de XAML. Puede cambiar x:String a un
modelo de datos existente en el proyecto.
Consulte app de Hanselman.Forms de James Montemagno para obtener un ejemplo más complejo.
Solución de problemas
Requisitos
Datos en tiempo de diseño requieren una versión mínima de Xamarin.Forms 3.6.
IntelliSense muestra con líneas onduladas Mis datos en tiempo de diseño
Esto es un problema conocido y se corregirá en una próxima versión de Visual Studio. El proyecto aún se
compilará sin errores.
El controlador de vista previa de XAML ha dejado de funcionar
Intente cerrar y volver a abrir el archivo XAML y limpiar y recompilar el proyecto.
Representar controles personalizados en la vista
previa XAML
11/07/2019 • 3 minutes to read • Edit Online
A veces, los controles personalizados no funcionan según lo previsto en la vista previa de XAML. Use las
instrucciones de este artículo para conocer las limitaciones de vista previa de los controles personalizados.
namespace MyProject
{
[DesignTimeVisible(true)]
public class MyControl : BaseControl
{
// Your control's code here
}
Controles de SkiaSharp
Actualmente, solo se admiten controles de SkiaSharp, cuando es una vista previa en iOS. No se representarán en
la versión preliminar de Android.
Solución de problemas
Comprobar la versión de Xamarin.Forms
Asegúrese de tener al menos 3.6 Xamarin.Forms instalado. Puede actualizar su versión de Xamarin.Forms en
NuGet.
Incluso con [DesignTimeVisible(true)] , mi control personalizado no está representando correctamente.
Controles personalizados que dependen en gran medida de los datos de código subyacente o de back-end no
siempre funcionan en la vista previa de XAML. Puede probar:
Mover el control, por lo que no inicializa si está habilitado el modo de diseño
Configurar datos en tiempo de diseño para mostrar datos falsos desde el back-end
El controlador de vista previa de XAML muestra el error "Los controles personalizados no están representar
correctamente"
Intente limpiar y recompilar el proyecto, o cerrar y volver a abrir el archivo XAML.
Espacios de nombres XAML en Xamarin.Forms
11/07/2019 • 8 minutes to read • Edit Online
XAML usa el atributo xmlns XML para las declaraciones de espacio de nombres. Este artículo presenta la sintaxis
del espacio de nombres XAML y muestra cómo declarar un espacio de nombres XAML para tener acceso a un
tipo.
Información general
Hay dos declaraciones de espacio de nombres XAML que siempre están dentro del elemento raíz de un archivo
XAML. La primera define el espacio de nombres predeterminado, tal como se muestra en el ejemplo de código
XAML siguiente:
xmlns="http://xamarin.com/schemas/2014/forms"
El espacio de nombres predeterminado especifica que los elementos definidos dentro del archivo XAML con
ningún prefijo hace referencia a clases de Xamarin.Forms, como ContentPage .
La segunda declaración de espacio de nombres usa el x prefijo, como se muestra en el ejemplo de código
XAML siguiente:
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
XAML usa los prefijos para declarar los espacios de nombres no predeterminados, con el prefijo que se va a usar
cuando se hace referencia a tipos del espacio de nombres. El x declaración de espacio de nombres especifica
que los elementos definen en el XAML con el prefijo x se usan para los elementos y atributos que son
intrínsecos de XAML (específicamente la especificación de XAML 2009).
La siguiente tabla se describen los x atributos de espacio de nombres compatibles con Xamarin.Forms:
CONSTRUCCIÓN DESCRIPCIÓN
x:Key Especifica una clave única definida por el usuario para cada
recurso en un ResourceDictionary . El valor de clave se usa
para recuperar el recurso XAML y se utiliza normalmente
como argumento para el StaticResource extensión de
marcado.
Para obtener más información sobre la x:DataType atributo, vea compilado enlaces. Para obtener más
información sobre la x:FieldModifier atributo, vea modificadores de campo. Para obtener más información
sobre la x:Arguments , x:FactoryMethod , y x:TypeArguments atributos, vea pasar argumentos en XAML.
NOTE
Además de los atributos de espacio de nombres enumerados anteriormente, Xamarin.Forms también incluye las
extensiones de marcado que se pueden consumir mediante el x prefijo de espacio de nombres. Para obtener más
información, consulte las extensiones de marcado XAML de consumo.
En XAML, las declaraciones de espacio de nombres se heredan de elemento primario al elemento secundario. Por
lo tanto, al definir un espacio de nombres en el elemento raíz de un archivo XAML, todos los elementos dentro de
ese archivo heredan la declaración de espacio de nombres.
El local prefijo es una convención que se utiliza para indicar que los tipos del espacio de nombres son locales
de la aplicación. Como alternativa, si los tipos están en un ensamblado diferente, el nombre del ensamblado debe
también se define en la declaración de espacio de nombres, como se muestra en el ejemplo de código XAML
siguiente:
El prefijo de espacio de nombres, a continuación, se especifica al declarar una instancia de un tipo a partir de un
espacio de nombres importado, como se muestra en el ejemplo de código XAML siguiente:
<ListView ...>
<ListView.Behaviors>
<behaviors:EventToCommandBehavior EventName="ItemSelected" ... />
</ListView.Behaviors>
</ListView>
Para obtener información acerca de cómo definir un esquema del espacio de nombres personalizado, vea
esquemas de XAML personalizados Namespace.
Resumen
En este artículo introdujo la sintaxis del espacio de nombres XAML y se muestra cómo declarar un espacio de
nombres XAML para tener acceso a un tipo. XAML usa la xmlns puede hacer referencia a las declaraciones de
espacio de nombres y tipos de atributo XML en XAML mediante la declaración de un espacio de nombres XAML
con un prefijo.
Vínculos relacionados
Pasar argumentos en XAML
Esquemas personalizados Namespace XAML en
Xamarin.Forms
11/07/2019 • 7 minutes to read • Edit Online
descargar el ejemplo
Pueden consultar en una biblioteca de tipos de XAML al declarar un espacio de nombres XAML para la biblioteca,
con la declaración de espacio de nombres especificando el nombre de espacio de nombres de Common Language
Runtime (CLR ) y un nombre de ensamblado:
<ContentPage ...
xmlns:controls="clr-namespace:MyCompany.Controls;assembly="MyCompany.Controls">
...
</ContentPage>
Sin embargo, al especificar un nombre de espacio de nombres y ensamblado CLR en un xmlns definición puede
ser difícil y propenso a errores. Además, varias declaraciones de espacio de nombres XAML pueden ser necesarias
si la biblioteca contiene tipos en varios espacios de nombres.
Un enfoque alternativo es definir un esquema del espacio de nombres personalizado, como
http://mycompany.com/schemas/controls , que se asigna a uno o varios espacios de nombres CLR. Esto permite una
sola declaración de espacio de nombres XAML hacer referencia a todos los tipos en un ensamblado, incluso si se
encuentran en diferentes espacios de nombres. También permite una sola declaración de espacio de nombres
XAML a tipos de referencia en varios ensamblados.
Para obtener más información acerca de los espacios de nombres XAML, vea espacios de nombres XAML en
Xamarin.Forms.
using Xamarin.Forms;
namespace MyCompany.Controls
{
public class CircleButton : Button
{
...
}
}
Todos los controles de la biblioteca que residen en el MyCompany.Controls espacio de nombres. Estos controles
pueden exponerse a un ensamblado que realiza la llamada a través de un esquema del espacio de nombres
personalizado.
Un esquema del espacio de nombres personalizado se define con el XmlnsDefinitionAttribute (clase), que
especifica la asignación entre un espacio de nombres XAML y uno o varios espacios de nombres CLR. El
XmlnsDefinitionAttribute toma dos argumentos: el nombre de espacio de nombres XAML y el nombre del
espacio de nombres CLR. El nombre de espacio de nombres XAML se almacena en el
XmlnsDefinitionAttribute.XmlNamespace propiedad y el nombre del espacio de nombres CLR se almacena en el
XmlnsDefinitionAttribute.ClrNamespace propiedad.
NOTE
El XmlnsDefinitionAttribute clase también tiene una propiedad denominada AssemblyName , que se puede establecer
opcionalmente para el nombre del ensamblado. Esto solo es necesario cuando un espacio de nombres CLR al que hace
referencia desde un XmlnsDefinitionAttribute está en un ensamblado externo.
El XmlnsDefinitionAttribute debe definirse en el nivel de ensamblado en el proyecto que contiene los espacios de
nombres CLR que se asignará en el esquema del espacio de nombres personalizado. El ejemplo siguiente se
muestra el AssemblyInfo.cs archivo desde la aplicación de ejemplo:
using Xamarin.Forms;
using MyCompany.Controls;
[assembly: Preserve]
[assembly: XmlnsDefinition("http://mycompany.com/schemas/controls", "MyCompany.Controls")]
Este código crea un esquema del espacio de nombres personalizado que se asigna el
http://mycompany.com/schemas/controls dirección URL a la MyCompany.Controls espacio de nombres CLR. Además,
el Preserve atributo se especifica en el ensamblado, para asegurarse de que el vinculador conserva todos los
tipos del ensamblado.
IMPORTANT
El Preserve atributo se debe aplicar a las clases del ensamblado que se asignan mediante el esquema del espacio de
nombres personalizado o aplicado a todo el ensamblado.
A continuación, el esquema del espacio de nombres personalizado puede utilizarse para la resolución de tipos en
archivos XAML.
namespace MyCompany.Controls
{
public static class Controls
{
public static void Init()
{
}
}
}
El Init , a continuación, se puede llamar al método desde el ensamblado que consume los tipos del esquema del
espacio de nombres personalizado:
using Xamarin.Forms;
using MyCompany.Controls;
namespace CustomNamespaceSchemaDemo
{
public partial class MainPage : ContentPage
{
public MainPage()
{
Controls.Init();
InitializeComponent();
}
}
}
WARNING
Se producirá un error al incluir este tipo de referencia de código en el compilador XAML que no se pueda localizar el
ensamblado que contiene los tipos de esquema del espacio de nombres personalizado.
Para consumir el CircleButton control, se declara un espacio de nombres XAML, con la declaración de espacio de
nombres que especifica la dirección URL de esquema de espacio de nombres 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 las instancias, a continuación, se pueden agregar a la ContentPage declarando con el controls
prefijo de espacio de nombres.
Para buscar el espacio de nombres personalizado de tipos de esquema, buscará en ensamblados de referencia
para Xamarin.Forms XmlnsDefinitionAttribute instancias. Si el xmlns atributo para un elemento en un archivo
XAML coincide con el XmlNamespace valor de propiedad en un XmlnsDefinitionAttribute , Xamarin.Forms
intentará usar la XmlnsDefinitionAttribute.ClrNamespace valor de propiedad para la resolución del tipo. Si se
produce un error en la resolución de tipos, Xamarin.Forms seguirá tratando de resolución de tipos en función de
cualquier coincidencia adicional XmlnsDefinitionAttribute instancias.
El resultado es que dos CircleButton se muestran las instancias:
Vínculos relacionados
Esquemas personalizados de Namespace (ejemplo)
Prefijos recomendados de espacio de nombres de XAML
Espacios de nombres XAML en Xamarin.Forms
XAML Namespace recomienda prefijos en
Xamarin.Forms
11/07/2019 • 2 minutes to read • Edit Online
La XmlnsPrefixAttribute clase puede ser usada por los autores de controles para especificar un prefijo
recomendado para asociar a un espacio de nombres XAML para el uso XAML. El prefijo es útil cuando se admiten
la serialización del árbol de objetos para XAML, o al interactuar con un entorno de diseño que tiene características
de edición de XAML. Por ejemplo:
Editores de texto XAML podrían utilizar el XmlnsPrefixAttribute como una sugerencia para un espacio de
nombres XAML inicial xmlns asignación.
Los entornos de diseño XAML podrían utilizar el XmlnsPrefixAttribute se agreguen asignaciones para el
XAML al arrastrar objetos fuera de un cuadro de herramientas y a una superficie de diseño visual.
Recomienda que los prefijos de espacio de nombres deben definirse en el nivel de ensamblado con el
XmlnsPrefixAttribute constructor, que toma dos argumentos: una cadena que especifica el identificador de un
espacio de nombres XAML y una cadena que especifica un prefijo recomendado:
Los prefijos deben utilizar las cadenas cortas, porque el prefijo se aplica normalmente a todos los elementos
serializados que proceden del espacio de nombres XAML. Por lo tanto, la longitud de cadena del prefijo puede
tener un efecto notable en el tamaño de la salida XAML serializada.
NOTE
Más de un XmlnsPrefixAttribute pueden aplicarse a un ensamblado. Por ejemplo, si tiene un ensamblado que define los
tipos de más de un espacio de nombres XAML, podría definir los valores de prefijo diferente para cada espacio de nombres
XAML.
Vínculos relacionados
Esquemas de espacio de nombres personalizado XAML
Espacios de nombres XAML en Xamarin.Forms
Extensiones de marcado XAML
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Las extensiones de marcado XAML ayudar a ampliar la eficacia y flexibilidad de XAML al permitir que los
atributos del elemento que se pueden establecer desde orígenes que no sean cadenas de texto literal.
Por ejemplo, normalmente, debe establecer el Color propiedad de BoxView similar al siguiente:
En cualquier caso, la cadena de texto se establece en el Color atributo se convierte en un Color valor por el
ColorTypeConverter clase.
Es posible que prefiera en su lugar, establezca el Color desde un valor almacenado en un diccionario de recursos,
o desde el valor de una propiedad estática de una clase que ha creado o una propiedad de tipo de atributo Color
de otro elemento en la página, o construido desde Separe los valores de matiz, saturación y luminosidad.
Todas estas opciones son posibles mediante las extensiones de marcado XAML. Pero no permita que la frase
"extensiones de marcado" lo abrume: Extensiones de marcado XAML son no extensiones a XML. Incluso con las
extensiones de marcado XAML, XAML es siempre XML legal.
Una extensión de marcado es simplemente una manera diferente para expresar un atributo de un elemento. Las
extensiones de marcado XAML son normalmente identificables mediante una configuración de atributo que se
encierra entre llaves:
Es cualquier valor de atributo están entre llaves siempre una extensión de marcado XAML. Sin embargo, como
verá, las extensiones de marcado XAML también pueden hacer referencia sin el uso de llaves.
En este artículo se divide en dos partes:
Vínculos relacionados
Extensiones de marcado (ejemplo)
Capítulo de extensiones de marcado XAML de Xamarin.Forms libro
Diccionarios de recursos
Estilos dinámicos
Enlace de datos
Consumo de las extensiones de marcado XAML
11/07/2019 • 29 minutes to read • Edit Online
descargar el ejemplo
Las extensiones de marcado XAML que ayudan a mejorar la eficacia y flexibilidad de XAML al permitir que los
atributos del elemento debe establecerse en una variedad de orígenes. Varias extensiones de marcado XAML
forman parte de la especificación de XAML 2009. Esta información aparece en los archivos XAML con el habitual
x prefijo de espacio de nombres y se conocen comúnmente por este prefijo. En este artículo se describe las
extensiones de marcado siguiente:
x:Static : hacer referencia a propiedades estáticas, campos o los miembros de enumeración.
x:Reference – con el nombre de elementos de la página de referencia.
x:Type : establezca un atributo en un System.Type objeto.
x:Array : construya una matriz de objetos de un tipo determinado.
x:Null : establezca un atributo en un null valor.
OnPlatform : personalizar la apariencia de la interfaz de usuario en forma de acuerdo con la plataforma.
OnIdiom : personalizar la apariencia de la interfaz de usuario en función de la expresión del dispositivo se está
ejecutando la aplicación en.
DataTemplate : convierte un tipo en un DataTemplate .
Las extensiones de marcado XAML adicionales históricamente han sido compatible con otras implementaciones
de XAML y también son compatibles con Xamarin.Forms. Estos se describen con más detalle en otros artículos:
StaticResource – hacer referencia a objetos de un diccionario de recursos, como se describe en el artículo los
diccionarios de recursos.
DynamicResource – responder a cambios en los objetos en un diccionario de recursos, como se describe en el
artículo estilos dinámicos.
Binding – establecer un vínculo entre las propiedades de dos objetos, como se describe en el artículo enlace
de datos.
TemplateBinding – realiza el enlace de datos de una plantilla de control, como se describe en el artículo desde
una plantilla de Control de enlace.
El RelativeLayout diseño hace uso de la extensión de marcado personalizada ConstraintExpression . Esta
extensión de marcado se describe en el artículo RelativeLayout.
<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>
Esto se puede simplificar aún más, pero el cambio presenta parte de la nueva sintaxis: Consta de colocar el
StaticExtension clase y la configuración entre llaves del miembro. La expresión resultante se establece
directamente en el FontSize atributo:
Tenga en cuenta que hay ningún comillas encerrado entre llaves. El Member propiedad de StaticExtension ya no
es un atributo XML. En realidad es parte de la expresión para la extensión de marcado.
Tal como se puede abreviar x:StaticExtension a x:Static cuando se usa como un elemento de objeto, también
puede abreviar en la expresión entre llaves:
El StaticExtension clase tiene un ContentProperty que hacen referencia a la propiedad de atributo Member , que
marca esta propiedad como propiedad de contenido de la clase predeterminada. Para las extensiones de marcado
XAML que expresa entre llaves, puede eliminar el Member= forma parte de la expresión:
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Esto permite la Label tamaño de fuente debe establecerse en el campo estático Math.PI . Esto da como resultado
texto pequeño en su lugar, por lo que la Scale propiedad está establecida en Math.E :
<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>
El x:Reference extensión de marcado se utiliza exclusivamente con los enlaces de datos, que se describen con
más detalle en el artículo enlace de datos.
El x: Reference demostración página muestra dos usos de x:Reference con enlaces de datos, la primera que se
usa para establecer el Source propiedad de la Binding objeto y el segundo donde se usa para establecer el
BindingContext propiedad para los enlaces de datos de dos:
<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">
<Slider x:Name="slider"
Maximum="360"
VerticalOptions="Center" />
</StackLayout>
</ContentPage>
Ambos x:Reference expresiones usan la versión abreviada de la ReferenceExtension nombre de clase y elimine el
Name= forma parte de la expresión. En el primer ejemplo, el x:Reference extensión de marcado está incrustada en
el Binding extensión de marcado. Tenga en cuenta que el Source y StringFormat configuración está separada
por comas. Este es el programa que se ejecuta:
Dentro de Xamarin.Forms, hay varias propiedades que tienen argumentos de tipo Type . Algunos ejemplos son el
TargetType propiedad de Style y el x: TypeArguments atributo utilizado para especificar los argumentos en las
clases genéricas. Sin embargo, el analizador XAML se realiza el typeof operación automáticamente y el x:Type
extensión de marcado no se usa en estos casos.
Un único lugar donde x:Type es necesarios es con el x:Array extensión de marcado, como se describe en el
siguiente sección.
El x:Type extensión de marcado también es útil al construir un menú donde cada elemento de menú
correspondiente a un objeto de un tipo determinado. Puede asociar un Type con cada elemento de menú de
objetos y, a continuación, cree una instancia del objeto cuando se selecciona el elemento de menú.
Se trata cómo el menú de navegación en MainPage en el las extensiones de marcado programa works. El
MainPage.xaml archivo contiene un TableView con cada TextCell correspondiente a una página determinada
en el 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}" />
···
</TableRoot>
</TableView>
</ContentPage>
BindingContext = this;
}
El NavigateCommand propiedad es un Command objeto que implementa un comando execute con un argumento de
tipo Type — el valor de CommandParameter . Usa el método Activator.CreateInstance para crear una instancia de
la página y, a continuación, navega a ella. El constructor concluye estableciendo el BindingContext de la página a sí
mismo, lo que permite el Binding en Command funcione. Consulte la enlace de datos artículo y especialmente los
Commanding artículo para obtener más detalles sobre este tipo de código.
El x: Type demostración página usa una técnica similar para crear instancias de elementos de Xamarin.Forms y
agregarlos a un StackLayout . El archivo XAML inicialmente consta de tres Button elementos con sus Command
propiedades establecidas en un Binding y CommandParameter propiedades establecidas en los tipos de las tres
vistas de 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">
BindingContext = this;
}
El método que se ejecuta cuando un Button se presiona crea una nueva instancia del argumento, se establece su
VerticalOptions propiedad y lo agrega a la StackLayout . Los tres Button elementos, a continuación, compartan
la página con las vistas creadas dinámicamente:
x:Array (Extensión de marcado)
El x:Array extensión de marcado permite definir una matriz en el marcado. Es compatible con la ArrayExtension
(clase), que define dos propiedades:
Type de tipo Type , lo que indica el tipo de los elementos de la matriz.
Items de tipo IList , que es una colección de los propios elementos. Se trata de la propiedad content de
ArrayExtension .
El x:Array propia extensión de marcado nunca aparece entre llaves. En su lugar, x:Array etiquetas inicial y final
delimitan la lista de elementos. Establecer el Type propiedad a un x:Type extensión de marcado.
El x: Array demostración página muestra cómo usar x:Array para agregar elementos a un ListView
estableciendo el ItemsSource propiedad a una 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>
Hay varias maneras de especificar la persona Color elementos de esta matriz. Puede usar un x:Static extensión
de marcado:
<x:Static Member="Color.Blue" />
Hacia el final de este artículo, verá una extensión de marcado XAML personalizada que también crea un nuevo
valor de color:
Al definir matrices de tipos comunes, como cadenas o números, use las etiquetas enumeradas en el pasar
argumentos de Constructor artículo para delimitar los valores.
<ContentPage.Content>
<StackLayout Padding="10, 0">
<Label Text="Text 1" />
<Label Text="Text 2" />
A continuación, verá que para uno de los Label elementos, desea que todos los valores de propiedades en la
parte implícita Style , excepto para el FontFamily , que desee que sea el valor predeterminado. Puede definir otra
Style para ese propósito, pero un enfoque más sencillo consiste simplemente en establecer el FontFamily
propiedad de la instancia concreta Label a x:Null , tal y como se muestra en el centro de Label .
Este es el programa que se ejecuta:
Tenga en cuenta que cuatro de los Label elementos tienen una fuente de serif, pero el centro Label tiene la
fuente sans serif de forma predeterminada.
Extensión de marcado OnPlatform
El OnPlatform extensión de marcado permite personalizar la apariencia de la interfaz de usuario en forma de
acuerdo con la plataforma. Proporciona la misma funcionalidad que el OnPlatform y On clases, pero con una
representación más concisa.
El OnPlatform extensión de marcado es compatible con la OnPlatformExtension (clase), que define las siguientes
propiedades:
Default de tipo object , establecido en un valor predeterminado que se aplicará a las propiedades que
representan las plataformas.
Android de tipo object , que se establece en un valor que se aplicará de Android.
GTK de tipo object , que se establece en un valor que se aplicará de plataformas de GTK +.
iOS de tipo object , que se establece en un valor que se aplicará de iOS.
macOS de tipo object , que se establece en un valor que se aplicará de macOS.
Tizen de tipo object , que se establece en un valor que se aplicará de la plataforma Tizen.
UWP de tipo object , que se establece en un valor que se aplicará de la plataforma Universal de Windows.
WPF de tipo object , que se establece en un valor que se aplicará de la plataforma Windows Presentation
Foundation.
Converter de tipo IValueConverter , que se establece en un IValueConverter implementación.
ConverterParameter de tipo object , que se establecen en un valor para pasar el IValueConverter
implementación.
NOTE
El analizador XAML permite la OnPlatformExtension clase va a abreviar como OnPlatform .
El Default propiedad es la propiedad content de OnPlatformExtension . Por lo tanto, para las expresiones de
marcado XAML expresadas con llaves, puede eliminar el Default= forma parte de la expresión siempre que sea el
primer argumento.
IMPORTANT
El analizador XAML espera que se proporcionen valores del tipo correcto a las propiedades que se consume el OnPlatform
extensión de marcado. Si es necesaria, la conversión de tipos la OnPlatform extensión de marcado se intentará realizar
mediante los convertidores predeterminados proporcionados por Xamarin.Forms. Sin embargo, hay algunas conversiones de
tipos que no se puede realizar los convertidores de forma predeterminada y en estos casos el Converter propiedad debe
establecerse en un IValueConverter implementación.
En este ejemplo, las tres OnPlatform expresiones usan la versión abreviada de la OnPlatformExtension nombre de
clase. Los tres OnPlatform conjunto de extensiones de marcado el Color , WidthRequest , y HeightRequest
propiedades de la BoxView en valores distintos en iOS, Android y UWP. Las extensiones de marcado también
proporcionan valores predeterminados para estas propiedades en las plataformas que no están especificadas, al
tiempo que elimina la Default= forma parte de la expresión. Tenga en cuenta que las propiedades de extensión de
marcado que se establecen están separadas por comas.
Este es el programa que se ejecuta:
NOTE
El analizador XAML permite la OnIdiomExtension clase va a abreviar como OnIdiom .
El Default propiedad es la propiedad content de OnIdiomExtension . Por lo tanto, para las expresiones de marcado
XAML expresadas con llaves, puede eliminar el Default= forma parte de la expresión siempre que sea el primer
argumento.
IMPORTANT
El analizador XAML espera que se proporcionen valores del tipo correcto a las propiedades que se consume el OnIdiom
extensión de marcado. Si es necesaria, la conversión de tipos la OnIdiom extensión de marcado se intentará realizar
mediante los convertidores predeterminados proporcionados por Xamarin.Forms. Sin embargo, hay algunas conversiones de
tipos que no se puede realizar los convertidores de forma predeterminada y en estos casos el Converter propiedad debe
establecerse en un IValueConverter implementación.
En este ejemplo, las tres OnIdiom expresiones usan la versión abreviada de la OnIdiomExtension nombre de clase.
Los tres OnIdiom conjunto de extensiones de marcado el Color , WidthRequest , y HeightRequest propiedades de
la BoxView en valores distintos en el teléfono, tableta y escritorio expresiones. Las extensiones de marcado
también proporcionan valores predeterminados para estas propiedades en las expresiones que no se especifican,
mientras se elimina el Default= forma parte de la expresión. Tenga en cuenta que las propiedades de extensión
de marcado que se establecen están separadas por comas.
Este es el programa que se ejecuta:
NOTE
El analizador XAML permite la DataTemplateExtension clase va a abreviar como DataTemplate .
Un uso típico de esta extensión de marcado está en una aplicación de Shell, como se muestra en el ejemplo
siguiente:
<ShellContent Title="Monkeys"
Icon="monkey.png"
ContentTemplate="{DataTemplate views:MonkeysPage}" />
En este ejemplo, MonkeysPage se convierte de un ContentPage a un DataTemplate , que se establece como el valor
de la ShellContent.ContentTemplate propiedad. Esto garantiza que MonkeysPage es sólo cuando tenga lugar la
navegación a la página se han creado, en lugar de al iniciarse la aplicación.
Para obtener más información acerca de las aplicaciones de Shell, consulte Xamarin.Forms Shell.
Vínculos relacionados
Extensiones de marcado (ejemplo)
Capítulo de extensiones de marcado XAML de Xamarin.Forms libro
Diccionarios de recursos
Estilos dinámicos
Enlace de datos
Shell de Xamarin.Forms.
Creación de extensiones de marcado XAML
11/07/2019 • 10 minutes to read • Edit Online
descargar el ejemplo
En el nivel de programación, una extensión de marcado XAML es una clase que implementa el IMarkupExtension
o IMarkupExtension<T> interfaz. Puede explorar el código fuente de las extensiones de marcado estándar se
describe a continuación, en el MarkupExtensions directory del repositorio de Xamarin.Forms GitHub.
También es posible definir sus propias extensiones de marcado XAML personalizados derivando de
IMarkupExtension o IMarkupExtension<T> . Use el formulario genérico si la extensión de marcado Obtiene un valor
de un tipo determinado. Este es el caso con varias de las extensiones de marcado de Xamarin.Forms:
TypeExtension se deriva de IMarkupExtension<Type>
ArrayExtension se deriva de IMarkupExtension<Array>
DynamicResourceExtension se deriva de IMarkupExtension<DynamicResource>
BindingExtension se deriva de IMarkupExtension<BindingBase>
ConstraintExpression se deriva de IMarkupExtension<Constraint>
Puesto que IMarkupExtension<T> se deriva de IMarkupExtension e incluye el new palabra clave en ProvideValue ,
contiene ambos ProvideValue métodos.
Muy a menudo, las extensiones de marcado XAML definen propiedades que contribuyen al valor devuelto. (La
excepción obvia es NullExtension , en el que ProvideValue simplemente devuelve null .) El ProvideValue
método tiene un único argumento de tipo IServiceProvider que se tratará más adelante en este artículo.
Dado que IMarkupExtension<T> deriva IMarkupExtension , la clase debe contener dos ProvideValue métodos, uno
que devuelve Color y otra que devuelve object , pero el segundo método simplemente puede llamar primero al
método.
El demostración de Color HSL página muestra una variedad de formas que HslColorExtension puede aparecer
en un archivo XAML para especificar el color para un 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>
Tenga en cuenta que, cuando HslColorExtension es una etiqueta XML, las cuatro propiedades se establecen como
atributos, pero cuando aparece entre llaves, las cuatro propiedades están separadas por comas sin comillas. Los
valores predeterminados de H , S , y L son 0 y el valor predeterminado de A es 1, por lo que esas propiedades
se pueden omitir si quiere que estén establecidas en valores predeterminados. El último ejemplo muestra un
ejemplo donde la luminosidad es 0, lo que normalmente se produce en negro, pero el canal alfa es 0,5, por lo que
es semitransparente y aparece atenuado en el fondo blanco de la página:
Una extensión de marcado para tener acceso a los mapas de bits
El argumento ProvideValue es un objeto que implementa el IServiceProvider interfaz, que se define en .NET
System espacio de nombres. Esta interfaz tiene un miembro, un método denominado GetService con un Type
argumento.
El ImageResourceExtension clase se muestra a continuación muestra un uso posible de IServiceProvider y
GetService para obtener un IXmlLineInfoProvider objeto que puede proporcionar información de línea y el
carácter que indica donde se detectó un error determinado. En este caso, se produce una excepción cuando el
Source no se estableció la propiedad:
[ContentProperty("Source")]
class ImageResourceExtension : IMarkupExtension<ImageSource>
{
public string Source { set; get; }
ImageResourceExtension es útil cuando un archivo XAML necesita acceder a un archivo de imagen almacenado
como un recurso incrustado en el proyecto de biblioteca .NET Standard. Usa el Source propiedad para llamar a
estático ImageSource.FromResource método. Este método requiere un nombre de recurso completo, que está
formado por el nombre del ensamblado, el nombre de carpeta y el nombre de archivo separadas por puntos. El
segundo argumento para el ImageSource.FromResource método proporciona el nombre del ensamblado y solo es
necesaria para la versión se basa en UWP. No obstante, ImageSource.FromResource debe llamarse desde el
ensamblado que contiene el mapa de bits, lo que significa que esta extensión de recursos XAML no puede formar
parte de una biblioteca externa a menos que las imágenes también se encuentran en dicha biblioteca. (Consulte la
imágenes incrustadas artículo para obtener más información sobre cómo acceder a los mapas de bits que se
almacenan como recursos incrustados.)
Aunque ImageResourceExtension requiere la Source propiedad se establece, el Source propiedad se indica en un
atributo como la propiedad de contenido de la clase. Esto significa que el Source= se puede omitir la parte de la
expresión entre llaves. En el demostración del recurso de imagen página, el Image elementos capturar dos
imágenes con el nombre de carpeta y el nombre de archivo separadas por puntos:
<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>
</Grid>
</ContentPage>
Proveedores de servicios
Mediante el uso de la IServiceProvider argumento ProvideValue , las extensiones de marcado XAML pueden
obtener acceso a información útil sobre el archivo XAML en el que está usando. Pero para usar el
IServiceProvider argumento correctamente, deberá saber qué tipo de servicios están disponibles en contextos
determinados. La mejor manera para obtener una descripción de esta característica es estudiar el código fuente de
las extensiones de marcado XAML existentes en el MarkupExtensions carpeta en el repositorio de
Xamarin.Forms en GitHub. Tenga en cuenta que algunos tipos de servicios son internos para Xamarin.Forms.
En algunas extensiones de marcado XAML, este servicio puede ser útil:
El IProvideValueTarget interfaz define dos propiedades, TargetObject y TargetProperty . Cuando se obtiene esta
información en el ImageResourceExtension (clase), TargetObject es el Image y TargetProperty es un
BindableProperty de objeto para el Source propiedad de Image . Se trata de la propiedad en el que se ha
establecido la extensión de marcado XAML.
El GetServicellamada con un argumento de typeof(IProvideValueTarget) realmente devuelve un objeto de tipo
SimpleValueTargetProvider , que se define en el Xamarin.Forms.Xaml.Internals espacio de nombres. Si convierte el
valor devuelto de GetService a ese tipo, también puede acceder un ParentObjects propiedad, que es una matriz
que contiene el Image elemento, el Grid primario y el ImageResourceDemoPage primario de la Grid .
Conclusión
Las extensiones de marcado XAML desempeñan un papel fundamental en XAML mediante la extensión de la
capacidad de establecer los atributos de una variedad de orígenes. Además, si las extensiones de marcado XAML
existentes no proporcionan exactamente lo que necesita, también puede escribir su propio.
Vínculos relacionados
Extensiones de marcado (ejemplo)
Capítulo de extensiones de marcado XAML de Xamarin.Forms libro
Modificadores de campo XAML en Xamarin.Forms
11/07/2019 • 2 minutes to read • Edit Online
El x:FieldModifier namespace (atributo ) especifica el nivel de acceso para los campos generados para los
elementos XAML con nombre.
Información general
Los valores válidos del atributo son:
Public : Especifica que el campo generado para el elemento XAML es public .
NotPublic : Especifica que el campo generado para el elemento XAML es internal al ensamblado.
Si no se establece el valor del atributo, el campo generado para el elemento será private .
Las siguientes condiciones deben cumplirse para una x:FieldModifier atributo procesarse:
El elemento XAML debe ser válido x:Class .
El elemento actual de XAML tiene un x:Name especificado.
El XAML siguiente muestra ejemplos de establecer el atributo:
NOTE
El x:FieldModifier atributo no puede utilizarse para especificar el nivel de acceso de una clase XAML.
Pasar argumentos en XAML
11/07/2019 • 6 minutes to read • Edit Online
descargar el ejemplo
En este artículo muestra cómo utilizar los atributos XAML que pueden utilizarse para pasar argumentos a los
constructores no predeterminados, para llamar a métodos de fábrica y para especificar el tipo de argumento
genérico.
Información general
A menudo es necesario crear instancias de objetos con constructores que requieren argumentos, o mediante una
llamada a un método de creación estático. Esto puede lograrse en XAML mediante el uso de la x:Arguments y
x:FactoryMethod atributos:
El x:Arguments atributo se utiliza para especificar los argumentos de constructor para un constructor no
predeterminado, o para una declaración de objeto del método de fábrica. Para obtener más información,
consulte pasar argumentos de Constructor.
El x:FactoryMethod atributo se utiliza para especificar un método de fábrica que puede usarse para inicializar
un objeto. Para obtener más información, consulte llamar a métodos de generador.
Además, el x:TypeArguments atributo puede utilizarse para especificar los argumentos de tipo genérico para el
constructor de un tipo genérico. Para obtener más información, consulte especificando un argumento de tipo
genérico.
En el ejemplo de código siguiente se muestra cómo utilizar el x:Arguments atributo con tres Color constructores:
<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>
El número de elementos dentro de la x:Arguments etiqueta y los tipos de estos elementos, deben coincidir con
uno de los Color constructores. El Color constructor con un solo parámetro requiere un valor de escala de
grises de 0 (negro) a 1 (blanco). El Color constructor con tres parámetros requiere un valor de color rojo, verde y
azul comprendida entre 0 y 1. El Color constructor con cuatro parámetros agrega un canal alfa como cuarto
parámetro.
Las capturas de pantalla siguientes muestran el resultado de llamar a cada uno de ellos Color constructor con
los valores de argumento especificado:
Llamar a métodos de fábrica
Pueden llamar a los métodos de fábrica en XAML mediante la especificación del método con el nombre del
x:FactoryMethod atributo y sus argumentos mediante el x:Arguments atributo. Un método de fábrica es un
public static método que devuelve objetos o valores del mismo tipo que la clase o estructura que define los
métodos.
El Color estructura define una serie de métodos de generador y el código siguiente muestra que realiza la
llamada tres de ellas:
<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>
El número de elementos dentro de la x:Arguments etiqueta y los tipos de estos elementos, deben coincidir con los
argumentos de la llamada al método de fábrica. El FromRgba método de fábrica requiere cuatro Int32
parámetros, que representan los valores de rojos, verdes, azules y alfabéticos, comprendida entre 0 y 255,
respectivamente. El FromHsla método de fábrica requiere cuatro Double parámetros, que representan el matiz,
saturación, luminosidad y los valores alfa, comprendida entre 0 y 1 respectivamente. El FromHex método factory
requiere un String que representa el formato hexadecimal (A) color RGB.
Las capturas de pantalla siguientes muestran el resultado de llamar a cada uno de ellos Color método de fábrica
con los valores de argumento especificado:
Si se especifica un argumento de tipo genérico
Argumentos de tipo genérico para el constructor de un tipo genérico pueden especificarse mediante la
x:TypeArguments de atributo, como se muestra en el ejemplo de código siguiente:
<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>
El OnPlatform clase es una clase genérica y se deben crear instancias con un x:TypeArguments atributo que
coincida con el tipo de destino. En la clase On , el atributo Platform puede aceptar un único valor string o
varios valores string delimitados por comas. En este ejemplo, el StackLayout.Margin propiedad está establecida
en una plataforma específica Thickness .
Resumen
En este artículo se muestra usando los atributos XAML que pueden utilizarse para pasar argumentos a los
constructores no predeterminados, para llamar a métodos de fábrica y para especificar el tipo de argumento
genérico.
Vínculos relacionados
Espacios de nombres XAML
Pasar argumentos de Constructor (ejemplo)
Llamar a métodos de fábrica (ejemplo)
Propiedades enlazables
11/07/2019 • 16 minutes to read • Edit Online
descargar el ejemplo
En Xamarin.Forms, la funcionalidad de las propiedades de common language runtime (CLR ) se extiende por las
propiedades enlazables. Una propiedad enlazable es un tipo especial de propiedad, donde el valor de propiedad
se realiza el seguimiento por el sistema de propiedades de Xamarin.Forms. Este artículo proporciona una
introducción a las propiedades enlazables y muestra cómo crear y consumirlos.
Información general
Propiedades enlazables amplían la funcionalidad de propiedad CLR de seguridad de una propiedad con un
BindableProperty tipo, en lugar de una propiedad con un campo de respaldo. El propósito de las propiedades
enlazables es proporcionar un sistema de propiedades que admite el enlace de datos, estilos, plantillas y valores se
establecen a través de relaciones de elementos primarios y secundarios. Además, las propiedades enlazables
pueden proporcionar valores predeterminados, validación de los valores de propiedad y las devoluciones de
llamada que supervisen los cambios de propiedad.
Las propiedades deben implementarse como propiedades enlazables para admitir una o varias de las siguientes
características:
Que actúa como válido destino propiedad para el enlace de datos.
Establecer la propiedad a través de un estilo.
Proporcionar un valor de propiedad predeterminado que es diferente del valor predeterminado para el tipo de
la propiedad.
Validar el valor de la propiedad.
Supervisión de los cambios de propiedad.
Ejemplos de Xamarin.Forms que las propiedades enlazables Label.Text , Button.BorderRadius , y
StackLayout.Orientation . Cada propiedad enlazable le corresponde una public static readonly propiedad de
tipo BindableProperty que se expone en la misma clase y que es el identificador de la propiedad enlazable. Por
ejemplo, el identificador de propiedad enlazable correspondiente para el Label.Text propiedad es
Label.TextProperty .
Esto crea un BindablePropertyinstancia denominada EventName , del tipo string . La propiedad pertenece a la
EventToCommandBehavior clase y tiene un valor predeterminado de null . La convención de nomenclatura para las
propiedades enlazables es que el identificador de propiedad enlazable debe coincidir con el nombre de propiedad
especificado en el Create método con "Property" anexado a él. Por lo tanto, en el ejemplo anterior, el identificador
de propiedad enlazable es EventNameProperty .
Si lo desea, al crear un BindableProperty de instancia, los siguientes parámetros se pueden especificar:
Modo de enlace. Esto se utiliza para especificar la dirección en la que se propaguen los cambios de valor de
propiedad. En el modo de enlace predeterminada, los cambios se propaguen desde el origen a la destino.
Un delegado de validación que se invocará cuando se establece el valor de propiedad. Para obtener más
información, consulte las devoluciones de llamada de validación.
Un delegado de cambio de propiedad que se invoca cuando ha cambiado el valor de propiedad. Para obtener
más información, consulte detectar los cambios de propiedad.
Una propiedad de cambio de delegado que se invoca cuando cambia el valor de propiedad. Este delegado tiene
la misma firma que el delegado de la propiedad ha cambiado.
Un delegado del valor de coerción que se invoca cuando ha cambiado el valor de propiedad. Para obtener más
información, consulte devoluciones de llamada de valor de coerción.
Un Func que se usa para inicializar un valor de propiedad predeterminado. Para obtener más información,
consulte creación de un valor predeterminado con un elemento Func.
Creación de los descriptores de acceso
Los descriptores de acceso de propiedad deben usar la sintaxis de la propiedad para tener acceso a una propiedad
enlazable. El Get descriptor de acceso debe devolver el valor que se encuentra en la propiedad enlazable
correspondiente. Esto puede lograrse mediante una llamada a la GetValue método, pasando el identificador de
propiedad enlazable en la que se va a obtener el valor y, a continuación, convertir el resultado al tipo requerido. El
Set descriptor de acceso debe establecer el valor de la propiedad enlazable correspondiente. Esto puede lograrse
mediante una llamada a la SetValue método, pasando el identificador de propiedad enlazable en la que se va a
establecer el valor y el valor que se va a establecer.
El ejemplo de código siguiente muestra los descriptores de acceso para el EventName propiedad enlazable:
La declaración de espacio de nombres se utiliza al establecer el EventName propiedad enlazable, como se muestra
en el ejemplo de código XAML siguiente:
<ListView ...>
<ListView.Behaviors>
<local:EventToCommandBehavior EventName="ItemSelected" ... />
</ListView.Behaviors>
</ListView>
Escenarios avanzados
Al crear un BindableProperty de la instancia, hay una serie de parámetros opcionales que se pueden establecer
para habilitar escenarios avanzados de propiedad enlazable. Esta sección explora estos escenarios.
Detección de cambios de propiedad
Un static método de devolución de llamada de cambio de propiedad se puede registrar con una propiedad
enlazable especificando el propertyChanged parámetro para el BindableProperty.Create método. El método de
devolución de llamada especificada se invoca cuando cambia el valor de la propiedad enlazable.
El siguiente ejemplo de código muestra cómo el EventName propiedad enlazable registra el OnEventNameChanged
método como un método de devolución de llamada de cambio de propiedad:
public static readonly BindableProperty EventNameProperty =
BindableProperty.Create (
"EventName", typeof(string), typeof(EventToCommandBehavior), null, propertyChanged: OnEventNameChanged);
...
En el método de devolución de llamada de cambio de propiedad, el BindableObject parámetro se usa para indicar
qué instancia de la clase propietaria informó de un cambio y los valores de los dos object parámetros
representan los valores antiguos y nuevos de la propiedad enlazable.
Devoluciones de llamada de validación
Un static método de devolución de llamada de validación se puede registrar con una propiedad enlazable
especificando el validateValue parámetro para el BindableProperty.Create método. Se invocará el método de
devolución de llamada especificada cuando se establece el valor de la propiedad enlazable.
El siguiente ejemplo de código muestra cómo el Angle propiedad enlazable registra el IsValidValue método
como método de devolución de llamada de validación:
Las devoluciones de llamada de validación se proporcionan con un valor y debe devolver true si el valor es
válido para la propiedad, de lo contrario false . Se producirá una excepción si una devolución de llamada de
validación devuelve false , que debe controlarse por el desarrollador. Un uso típico de un método de devolución
de llamada de validación es restringir los valores de números enteros o dobles cuando se establece la propiedad
enlazable. Por ejemplo, el IsValidValue método comprueba que el valor de propiedad es un double dentro del
intervalo de 0 a 360.
CoerceValue Callbacks
Un static convertir el valor del método de devolución de llamada se puede registrar con una propiedad
enlazable especificando el coerceValue parámetro para el BindableProperty.Create método. El método de
devolución de llamada especificada se invoca cuando cambia el valor de la propiedad enlazable.
Las devoluciones de llamada se usan para forzar una reevaluación de una propiedad enlazable cuando cambia el
valor de la propiedad de valor de coerción. Por ejemplo, puede utilizarse una devolución de llamada de valor de
coerción para asegurarse de que el valor de una propiedad enlazable no es mayor que el valor de otra propiedad
enlazable.
El siguiente ejemplo de código muestra cómo el Angle propiedad enlazable registra el CoerceAngle método
como un método de devolución de llamada de valor de coerción:
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);
...
return input;
}
Resumen
En este artículo proporciona una introducción a las propiedades enlazables y se muestra cómo crear y
consumirlos. Una propiedad enlazable es un tipo especial de propiedad, donde el valor de propiedad se realiza el
seguimiento por el sistema de propiedades de Xamarin.Forms.
Vínculos relacionados
Espacios de nombres XAML
Evento para el comportamiento de comandos (ejemplo)
Devolución de llamada de validación (ejemplo)
Convertir el valor de devolución de llamada (ejemplo)
BindableProperty
BindableObject
Propiedades asociadas
11/07/2019 • 10 minutes to read • Edit Online
descargar el ejemplo
Una propiedad adjunta es un tipo especial de propiedad enlazable, definido en una clase pero conectado a
otros objetos y reconocible en XAML como un atributo que contiene una clase y un nombre de propiedad
separados por un punto. Este artículo proporciona una introducción a las propiedades adjuntas y muestra cómo
crear y consumirlos.
Información general
Adjunta propiedades habilitar un objeto para asignar un valor para una propiedad que no define su propia clase.
Por ejemplo, secundario, pueden usar los elementos vinculados propiedades para informar a su elemento
primario de cómo se presentarán en la interfaz de usuario. El Grid control permite la fila y columna de un
elemento secundario que se especifica estableciendo el Grid.Row y Grid.Column propiedades adjuntas.
Grid.Row y Grid.Column son las propiedades adjuntas porque se definen los elementos que son elementos
secundarios de un Grid , en lugar de en el Grid propio.
Propiedades enlazables deben implementarse como propiedades adjuntas en los escenarios siguientes:
Cuando no hay necesidad de tener un mecanismo de configuración de propiedades disponible para las clases
distintas de la definición de clase.
Cuando la clase representa un servicio que necesita para integrarse fácilmente con otras clases.
Para obtener más información acerca de las propiedades enlazables, vea propiedades enlazables.
Esto crea una propiedad adjunta mencionada HasShadow , del tipo bool . La propiedad pertenece a la
ShadowEffect clase y tiene un valor predeterminado de false . La convención de nomenclatura para las
propiedades adjuntas es que el identificador de propiedad adjunta debe coincidir con el nombre de propiedad
especificado en el CreateAttached método con "Property" anexado a él. Por lo tanto, en el ejemplo anterior, el
identificador de la propiedad adjunta es HasShadowProperty .
Para obtener más información acerca de cómo crear propiedades enlazables, incluidos los parámetros que se
pueden especificar durante la creación, consulte creación y consumo de una propiedad enlazable.
Creación de los descriptores de acceso
Estática Get PropertyName y Set PropertyName métodos son necesarios como descriptores de acceso para
la propiedad adjunta, en caso contrario, el sistema de propiedades no se puede usar el propiedad adjunta. El
Get PropertyName descriptor de acceso debe ajustarse a la firma siguiente:
El GetPropertyName descriptor de acceso debe devolver el valor que se encuentra en las correspondientes
BindableProperty campo para la propiedad adjunta. Esto puede lograrse mediante una llamada a la GetValue
método, pasando el identificador de propiedad enlazable en la que se va a obtener el valor y, a continuación,
convertir el valor resultante al tipo requerido.
El Set PropertyName descriptor de acceso debe ajustarse a la firma siguiente:
Escenarios avanzados
Al crear una propiedad adjunta, hay una serie de parámetros opcionales que se pueden establecer para habilitar
escenarios avanzados de propiedad adjunta. Esto incluye la detección de cambios de propiedad, validar los
valores de propiedad y la conversión de valores de propiedad. Para obtener más información, consulte
escenarios avanzados.
Resumen
En este artículo proporciona una introducción a las propiedades adjuntas y se muestra cómo crear y
consumirlos. Una propiedad adjunta es un tipo especial de propiedad enlazable, definida en una clase, pero
Unidos a otros objetos y reconocible en XAML como atributos que contienen una clase y un nombre de
propiedad separados por un punto.
Vínculos relacionados
Propiedades enlazables
Espacios de nombres XAML
Efecto de sombra paralela (ejemplo)
BindableProperty
BindableObject
Diccionarios de recursos
11/07/2019 • 16 minutes to read • Edit Online
descargar el ejemplo
Recursos XAML son definiciones de objetos que pueden compartir y volver a utilizarse en toda una aplicación de
Xamarin.Forms.
Estos objetos de recursos se almacenan en un diccionario de recursos. En este artículo se describe cómo crear y
consumir un diccionario de recursos y cómo se combinan los diccionarios de recursos.
Información general
Un ResourceDictionary es un repositorio para los recursos utilizados por una aplicación de Xamarin.Forms.
Recursos típicos que se almacenan en un ResourceDictionary incluyen estilos, plantillas de control, plantillas de
datos, colores y los convertidores de tipos.
En XAML, los recursos que se almacenan en un ResourceDictionary puedan recuperarse y aplica a los elementos
mediante el StaticResource extensión de marcado. En C#, también se pueden definir los recursos en un
ResourceDictionary y, a continuación, recuperar y aplicar a los elementos mediante el uso de un indexador de
cadena. Sin embargo, existen muy pocas ventajas al uso de un ResourceDictionary en C#, como objetos
compartidos simplemente se pueden almacenar como campos o propiedades y obtener acceso a directamente
sin tener que primero recuperarlos de un diccionario.
Un programa de Xamarin.Forms contiene sólo una clase que derive de Application pero a menudo hace uso de
muchas clases que derivan de VisualElement , incluidas las páginas, diseños y controles. Cualquiera de estos
objetos pueden tener su Resources propiedad establecida en un ResourceDictionary . Elegir dónde colocar un
determinado ResourceDictionary impactos donde se pueden usar los recursos:
Los recursos en un ResourceDictionary que está asociado a una vista como Button o Label sólo puede
aplicarse a ese objeto concreto, por lo que esto no es muy útil.
Los recursos en un ResourceDictionary adjunta a un diseño, como StackLayout o Grid se pueden aplicar
para el diseño y todos los elementos secundarios de ese diseño.
Los recursos en un ResourceDictionary definido en la página de nivel se puede aplicar a la página y a todos
sus elementos secundarios.
Los recursos en un ResourceDictionary definido en la aplicación de nivel se puede aplicar a lo largo de la
aplicación.
El siguiente XAML muestra los recursos definidos en un nivel de aplicación ResourceDictionary en el App.xaml
archivo creado como parte del programa de Xamarin.Forms estándar:
<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>
Esto ResourceDictionary define tres Color recursos y un Style recursos. Para obtener más información sobre
la App de clases, vea clase App.
A partir de 3.0 de Xamarin.Forms, la configuración explícita ResourceDictionary las etiquetas no son necesarias.
El ResourceDictionary objeto se crea automáticamente y los recursos puede insertar directamente entre el
Resources etiquetas de elemento de propiedad:
<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 tiene una clave que se especifica utilizando el x:Key atributo, que se convierte en la clave de
diccionario en el ResourceDictionary . La clave se usa para recuperar un recurso desde el ResourceDictionary por
la StaticResource extensión de marcado, como se muestra en el siguiente ejemplo de código XAML que se
muestra recursos adicionales definidos en el 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>
<ContentPage ...>
<ContentPage.Resources>
<local:MyResourceDictionary />
</ContentPage.Resources>
...
</ContentPage>
IMPORTANT
ResourceDictionary También define un MergedWith propiedad. No utilice esta propiedad; se ha quedado obsoleta en
Xamarin.Forms 3.0.
Una instancia de MyResourceDictionaryse pueden combinar en cualquier nivel de control, página o aplicación
ResourceDictionary . El ejemplo de código XAML siguiente muestra lo que se va a combinar en un nivel de
página ResourceDictionary utilizando el MergedDictionaries propiedad:
<ContentPage ...>
<ContentPage.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<local:MyResourceDictionary />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</ContentPage.Resources>
...
</ContentPage>
Ese marcado muestra solo una instancia de MyResourceDictionary que se agrega a la ResourceDictionary , pero
también puede hacer referencia otros ResourceDictionary instancias dentro de la MergedDictionary etiquetas de
elemento de propiedad y otros recursos fuera de esas etiquetas:
<ContentPage ...>
<ContentPage.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<local:MyResourceDictionary />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</ContentPage.Resources>
...
</ContentPage>
Puede haber solo un MergedDictionaries sección un ResourceDictionary , pero se puede colocar tantos
ResourceDictionary instancias allí como desee.
Cuando combina ResourceDictionary recursos comparten idénticos x:Key valores de atributo, Xamarin.Forms
utiliza la prioridad de recursos siguientes:
1. Los recursos locales para el diccionario de recursos.
2. Los recursos contenidos en el diccionario de recursos que se combinó a través del objeto desusado
MergedWith propiedad.
3. Los recursos contenidos en los diccionarios de recursos que se han combinado a través de la
MergedDictionaries colección, en el orden inverso que aparecen en la MergedDictionaries propiedad.
NOTE
La búsqueda de diccionarios de recursos puede ser una tarea de cálculo intensiva si una aplicación contiene varios
diccionarios de recursos grande. Por lo tanto, para evitar búsquedas innecesarias, debe asegurarse de que cada página en
una aplicación solo usa los diccionarios de recursos que son adecuados para la página.
<ContentPage ...>
<ContentPage.Resources>
<ResourceDictionary>
</ResourceDictionary>
</ContentPage.Resources>
...
</ContentPage>
Dado que Xamarin.Forms 3.0 crea automáticamente una instancia el ResourceDictionary , esos dos externas
ResourceDictionary etiquetas ya no son necesarias:
<ContentPage ...>
<ContentPage.Resources>
</ContentPage.Resources>
...
</ContentPage>
Esta nueva sintaxis no crear una instancia de la MyResourceDictionary clase. En su lugar, hace referencia al
archivo XAML. Por esa razón el archivo de código subyacente (MyResourceDictionary.xaml.cs) ya no es
necesario. También puede quitar el x:Class atributo de la etiqueta a la raíz de la MyResourceDictionary.xaml
archivo.
Resumen
En este artículo se explica cómo crear y consumir un ResourceDictionary y cómo se combinan los diccionarios
de recursos. Un ResourceDictionary permite que los recursos definidos en una sola ubicación y volver a
utilizarse en toda una aplicación de Xamarin.Forms.
Vínculos relacionados
Diccionarios de recursos (ejemplo)
Estilos
ResourceDictionary
Vídeo relacionado
Encuentre más vídeos de Xamarin en Channel 9 y YouTube.
XAML estándar (versión preliminar)
11/07/2019 • 2 minutes to read • Edit Online
Vínculos relacionados
NuGet de versión preliminar
Controls Reference (Referencia de controles)
Controles XAML estándar (versión preliminar)
11/07/2019 • 2 minutes to read • Edit Online
Esta página enumera los controles XAML estándar disponibles en la vista previa, junto con su control equivalente
de Xamarin.Forms.
También hay una lista de los controles que tienen los nuevos nombres de propiedad y enumeración en XAML
estándar.
Controles
XAMARIN.FORMS XAML ESTÁNDAR
Fotograma Borde
Selector ComboBox
ActivityIndicator ProgressRing
StackLayout StackPanel
Etiqueta TextBlock
Entrada TextBox
Modificador ToggleSwitch
IMPORTANT
Los elementos marcados con * están incompletos en la vista previa actual
Vínculos relacionados
NuGet de versión preliminar
Cargar XAML en tiempo de ejecución en
Xamarin.Forms
11/07/2019 • 4 minutes to read • Edit Online
descargar el ejemplo
El Xamarin.Forms.Xaml espacio de nombres incluye dos LoadFromXaml métodos de extensión que se pueden utilizar
para cargar y analizar XAML en tiempo de ejecución.
Fondo
Cuando se construye una clase de XAML de Xamarin.Forms, el LoadFromXaml indirectamente se llama al método.
Esto ocurre porque el archivo de código subyacente para un XAML llama a la clase el InitializeComponent método
desde su constructor:
Cuando Visual Studio compila un proyecto que contiene un archivo XAML, analiza el archivo XAML para generar
un C# archivo de código (por ejemplo, MainPage.xaml.g.cs) que contiene la definición de la InitializeComponent
método:
El InitializeComponent llamadas al método el LoadFromXaml método para extraer el archivo XAML (o el binario
compilado) de la biblioteca .NET Standard. Después de la extracción, inicializa todos los objetos definidos en el
archivo XAML, se conectan todos juntos en las relaciones de elementos primarios y secundarios, adjunta los
controladores de eventos definidos en el código para los eventos que se establece en el archivo XAML y establece
el árbol resultante de objetos como el contenido de la página.
WARNING
Cargar XAML en tiempo de ejecución tiene un gran costo de rendimiento y, por lo general debe evitarse.
El ejemplo de código siguiente muestra un uso sencillo:
using Xamarin.Forms.Xaml;
...
En este ejemplo, un Button se crea la instancia, con su Text define un valor de propiedad que se establece desde
el XAML en el string . El Button , a continuación, se agrega a un StackLayout que se ha definido en el XAML
para la página.
NOTE
El LoadFromXaml métodos de extensión permiten especificar un argumento de tipo genérico. Sin embargo, es no suele ser
necesario especificar el argumento de tipo, ya que será deriva del tipo de la instancia de su funcionamiento en.
El LoadFromXaml método puede utilizarse para inflado cualquier XAML, con el siguiente ejemplo se infla un
ContentPage y, a continuación, vaya a él:
using Xamarin.Forms.Xaml;
...
En este ejemplo, el XAML para un ContentPage se aumenta. Este XAML incluye una Label denominado
monkeyName , que se recupera mediante la FindByName método antes de que tenga Text se establece la propiedad.
Vínculos relacionados
LoadRuntimeXAML (ejemplo)
Aspectos básicos de la aplicación de Xamarin.Forms
11/07/2019 • 4 minutes to read • Edit Online
Accesibilidad
Sugerencias para incorporar características accesibles (como por ejemplo, la compatibilidad con herramientas de
lectura de pantalla) con Xamarin.Forms.
Clase de aplicación
La clase Application es el punto de partida para Xamarin.Forms: todas las aplicaciones necesitan implementar una
subclase App para establecer la página inicial. También proporciona la recopilación Properties para el
almacenamiento sencillo de datos. Se puede definir en C# o XAML.
Comportamientos
Los controles de la interfaz de usuario se pueden extender fácilmente sin incluir subclases mediante
comportamientos para agregar funcionalidad.
Representadores personalizados
Los representadores personalizados permiten a los desarrolladores reemplazar la representación predeterminada
de los controles de Xamarin.Forms para personalizar su apariencia y comportamiento en cada plataforma (usando
SDK nativos si lo prefiere).
Enlace de datos
El enlace de datos vincula las propiedades de dos objetos para que los cambios en una propiedad se reflejen
automáticamente en la otra propiedad. El enlace de datos es una parte integral de la arquitectura de aplicación
Model-View -ViewModel (MVVM ).
Servicio de dependencia
DependencyService proporciona un localizador simple para que pueda incluir código para interfaces en el código
compartido y proporcionar implementaciones específicas de la plataforma que se resuelvan automáticamente, lo
que facilita la referencia a funcionalidades específicas de la plataforma en Xamarin.Forms.
Efectos
Con los efectos se pueden personalizar los controles nativos de cada plataforma y normalmente se usan para
pequeños cambios de estilo.
Gestos
La clase GestureRecognizer de Xamarin.Forms admite los gestos de pulsar, reducir y desplazar lateralmente en
controles de interfaz de usuario.
Localización
El marco de trabajo de localización integrado de .NET puede usarse para generar aplicaciones multilingües
multiplataforma con Xamarin.Forms.
Centro de mensajería
MessagingCenter de Xamarin.Forms permite que los modelos de vista y otros componentes se comuniquen sin
tener que saber nada sobre los demás, salvo un sencillo contrato de mensajería.
Navegación
Xamarin.Forms proporciona una serie de experiencias de navegación de páginas diferentes, en función del tipo de
Page que se use.
Shell
Xamarin.Forms Shell reduce la complejidad del desarrollo de aplicaciones móviles al proporcionar las
características fundamentales que requieren la mayoría de aplicaciones móviles. Esto incluye una experiencia de
usuario de navegación común, un esquema de navegación basado en URI y un controlador de búsqueda integrada.
Desencadenadores
Actualice los controles respondiendo a los cambios de propiedades y eventos en XAML.
Accesibilidad de Xamarin.Forms
11/07/2019 • 3 minutes to read • Edit Online
Crear una aplicación accesible garantiza que la aplicación podrá ser usada por personas que interaccionan con la
interfaz de usuario con una variedad de necesidades y experiencias.
Hacer que una aplicación de Xamarin.Forms sea accesible significa pensar en el diseño de muchos elementos de
interfaz de usuario. Para obtener información sobre cuestiones que hay que tener en cuenta, vea la lista de
comprobación de accesibilidad. Ya se pueden solucionar muchos problemas de accesibilidad como las fuentes
grandes y la configuración adecuada de color y contraste mediante las API de Xamarin.Forms.
Las guías Accesibilidad para Android y Accesibilidad para iOS contienen información detallada de las API nativas
expuestas por Xamarin, y la Guía de accesibilidad UWP en MSDN explica el enfoque nativo en esa plataforma.
Estas API se usan para implementar por completo aplicaciones accesibles en cada plataforma.
Actualmente, Xamarin.Forms no tiene compatibilidad integrada con todas las API de accesibilidad que hay
disponibles en cada una de las plataformas subyacentes. Pero sí admite configurar las propiedades de
automatización en los elementos de la interfaz de usuario para admitir las herramientas de ayuda a la navegación y
el lector de pantalla, que es uno de los aspectos más importantes al crear aplicaciones accesibles. Para más
información, vea Propiedades de automatización.
En las aplicaciones de Xamarin.Forms también se puede especificar el orden de tabulación de los controles, con el
fin de mejorar la facilidad de uso y la accesibilidad. Para más información, consulte Accesibilidad del teclado.
Otras API de accesibilidad (como PostNotification en iOS ) pueden ser más adecuadas para una implementación
de DependencyService o Representador personalizado. No se tratarán en esta guía.
Probar la accesibilidad
Las aplicaciones de Xamarin.Forms normalmente van dirigidas a varias plataformas, lo que significa que las
pruebas de las características de accesibilidad se realizan según la plataforma. Siga estos vínculos para saber más
sobre cómo probar la accesibilidad en cada plataforma:
Pruebas en iOS
Pruebas en Android
Windows AccScope (MSDN )
Vínculos relacionados
Accesibilidad multiplataforma
Propiedades de automatización
Accesibilidad de teclado
Vídeo relacionado
Encuentre más vídeos de Xamarin en Channel 9 y YouTube.
Propiedades de automatización en Xamarin.Forms
11/07/2019 • 12 minutes to read • Edit Online
Descargar el ejemplo
Xamarin.Forms permite que los valores de accesibilidad se establezcan en elementos de la interfaz de usuario
mediante el uso de las propiedades adjuntas de la clase AutomationProperties, que a su vez establece valores de
accesibilidad nativa. Este artículo explica cómo usar la clase AutomationProperties, para que un lector de pantalla
pueda leer los elementos en la página.
Xamarin.Forms permite que las propiedades de automatización se establezcan en elementos de la interfaz de
usuario a través de las propiedades adjuntas siguientes:
AutomationProperties.IsInAccessibleTree : indica si el elemento está disponible para una aplicación accesible.
Para obtener más información, consulte AutomationProperties.IsInAccessibleTree.
AutomationProperties.Name : una breve descripción del elemento que actúa como un identificador con capacidad
de lectura para el elemento. Para obtener más información, consulte AutomationProperties.Name.
AutomationProperties.HelpText : una descripción más larga del elemento, que puede considerarse como el texto
de información sobre herramientas asociado al elemento. Para obtener más información, consulte
AutomationProperties.HelpText.
AutomationProperties.LabeledBy : permite que otro elemento defina la información de accesibilidad para el
elemento actual. Para obtener más información, consulte AutomationProperties.LabeledBy.
Estas propiedades adjuntas establecen los valores de accesibilidad nativa para que un lector de pantalla pueda leer
el elemento. Para más información sobre las propiedades adjuntas, consulte Propiedades asociadas.
IMPORTANT
El uso de las propiedades adjuntas AutomationProperties puede afectar a la ejecución de prueba de IU en Android. Las
propiedades AutomationId , AutomationProperties.Name y AutomationProperties.HelpText , establecen la propiedad
ContentDescription nativa, con los valores de propiedad AutomationProperties.Name y
AutomationProperties.HelpText con prioridad sobre el valor AutomationId (si tanto AutomationProperties.Name
como AutomationProperties.HelpText están establecidos, los valores se concatenarán). Esto significa que cualquier
prueba que busque AutomationId fallará si AutomationProperties.Name o AutomationProperties.HelpText también
están establecidos en el elemento. En este escenario, las pruebas de IU deben modificarse para buscar el valor de
AutomationProperties.Name o AutomationProperties.HelpText , o una concatenación de ambos.
Cada plataforma tiene un lector de pantalla diferente para leer los valores de accesibilidad:
iOS tiene VoiceOver. Para obtener más información, consulte Test Accessibility on Your Device with VoiceOver
(Probar la accesibilidad en un dispositivo con VoiceOver), en developer.apple.com.
Android tiene TalkBack. Para obtener más información, consulte Testing Your App's Accessibility (Prueba de la
accesibilidad de una aplicación), en developer.android.com.
Windows tiene el Narrador. Para obtener más información, consulte Verify main app scenarios by using
Narrator (Comprobar escenarios de aplicaciones principales mediante el uso del Narrador).
Sin embargo, el comportamiento exacto de un lector de pantalla depende del software y de la configuración del
usuario en él. Por ejemplo, la mayoría de los lectores de pantalla leen el texto asociado con un control cuando
queda focalizado, permitiendo a los usuarios orientarse a medida que se mueven entre los controles en la página.
Algunos lectores de pantalla leen también la interfaz de usuario de la aplicación completa cuando aparece una
página, lo cual permite que el usuario reciba todo de contenido informativo disponible de la página antes de
intentar navegar por ella.
Los lectores de pantalla también leen valores de accesibilidad distintos. En la aplicación de ejemplo:
VoiceOver leerá el valor Placeholder de Entry , seguido de las instrucciones para usar el control.
TalkBack leerá el valor Placeholder de Entry , seguido del valor AutomationProperties.HelpText , seguido de las
instrucciones para usar el control.
El Narrador leerá el valor AutomationProperties.LabeledBy de Entry , seguido de las instrucciones para usar el
control.
Además, el Narrador dará prioridad a AutomationProperties.Name , AutomationProperties.LabeledBy y, a
continuación, AutomationProperties.HelpText . En Android, TalkBack puede combinar los valores
AutomationProperties.Name y AutomationProperties.HelpText . Por lo tanto, se recomienda llevar a cabo pruebas de
accesibilidad exhaustivas en cada plataforma para garantizar una experiencia óptima.
AutomationProperties.IsInAccessibleTree
La propiedad adjunta AutomationProperties.IsInAccessibleTree es un valor boolean que determina si el elemento
es accesible, y por lo tanto visible, para los lectores de pantalla. Debe establecerse en true para usar las otras
propiedades adjuntas de accesibilidad. Esto se puede lograr en XAML de la siguiente manera:
NOTE
Tenga en cuenta que el método SetValue también se puede utilizar para establecer la propiedad adjunta de
AutomationProperties.IsInAccessibleTree ,
entry.SetValue(AutomationProperties.IsInAccessibleTreeProperty, true);
AutomationProperties.Name
El valor de la propiedad adjunta AutomationProperties.Name debe ser una cadena de texto corta y descriptiva que
usa un lector de pantalla anunciar un elemento. Esta propiedad debe establecerse para los elementos que tengan
un significado que sea importante para comprender el contenido o interactuar con la interfaz de usuario. Esto se
puede lograr en XAML de la siguiente manera:
<ActivityIndicator AutomationProperties.IsInAccessibleTree="true"
AutomationProperties.Name="Progress indicator" />
AutomationProperties.HelpText
La propiedad adjunta de AutomationProperties.HelpText debe establecerse en el texto que describe el elemento de
interfaz de usuario y puede ser considerarse el texto de información sobre herramientas asociado al elemento.
Esto se puede lograr en XAML de la siguiente manera:
NOTE
Tenga en cuenta que el método SetValue también se puede utilizar para establecer la propiedad adjunta de
AutomationProperties.HelpText ,
button.SetValue(AutomationProperties.HelpTextProperty, "Tap to toggle the activity indicator");
En algunas plataformas, para editar controles, como un elemento Entry , la propiedad HelpText a veces puede
omitirse y reemplazarse por el texto de marcador de posición. Por ejemplo, "Escriba aquí su nombre" es un buen
candidato para la propiedad Entry.Placeholder que coloca el texto en el control antes de la entrada real del
usuario.
AutomationProperties.LabeledBy
La propiedad adjunta AutomationProperties.LabeledBy permite que otro elemento defina la información de
accesibilidad para el elemento actual. Por ejemplo, un elemento Label junto a un elemento Entry puede
utilizarse para describir lo que representa Entry . Esto se puede lograr en XAML de la siguiente manera:
En Android, para establecer el texto que el lector de pantalla leerá para el botón de alternancia en
MasterDetailPage , agregue los recursos de cadena al proyecto de 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>
ToolbarItem
En iOS, Android y UWP, los lectores de pantalla leerán el valor de propiedad Text de las instancias de
ToolbarItem , siempre que no haya definido los valores AutomationProperties.Name y
AutomationProperties.HelpText .
En iOS y UWP, el valor de propiedad AutomationProperties.Name reemplazará el valor de propiedad Text que el
lector de pantalla lee.
En Android, los valores de propiedad AutomationProperties.Name o AutomationProperties.HelpText reemplazarán
por completo el valor de propiedad Text , que es visible y el lector de pantalla leerá. Tenga en cuenta que se trata
de una limitación de API inferior a 26.
Vínculos relacionados
Propiedades asociadas
Accesibilidad (ejemplo)
Accesibilidad del teclado en Xamarin.Forms
11/07/2019 • 7 minutes to read • Edit Online
Descargar el ejemplo
Los usuarios que emplean lectores de pantalla, o que tienen problemas de movilidad, pueden tener dificultades
para usar aplicaciones que no proporcionan acceso adecuado con el teclado. En las aplicaciones de Xamarin.Forms
se puede especificar un orden de tabulación esperado para mejorar su facilidad de uso y accesibilidad. La
especificación de un orden de tabulación para los controles permite la navegación con el teclado, prepara las
páginas de la aplicación para recibir la entrada en un orden concreto y permite que los lectores de pantalla lean
elementos activables para el usuario.
De forma predeterminada, el orden de tabulación de los controles es el mismo orden en que se están indicados en
XAML o agregados mediante programación a una colección secundaria. Este es el orden en que se navegará por
los controles con un teclado y en que se leerán con un lector de pantalla; a menudo, este orden predeterminado es
el mejor orden posible. Sin embargo, el orden predeterminado no es siempre el mismo que el orden previsto,
como se muestra en el ejemplo de código XAML siguiente:
<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>
La captura de pantalla siguiente muestra el orden de tabulación predeterminado para este ejemplo de código:
Aquí, el orden de tabulación está basado en filas y es el orden en el cual los controles se indican en el XAML. Por
lo tanto, al presionar la tecla TAB se navega por instancias Entry de nombre, seguidas por instancias Entry de
apellido. Sin embargo, una experiencia más intuitiva sería usar una navegación por tabulación de la columna en
primer lugar, para que al presionar la tecla TAB se navegara por los pares de nombre y apellido. Esto puede
lograrse mediante la especificación del orden de tabulación de los controles de entrada.
NOTE
En la Plataforma universal de Windows, se pueden definir métodos abreviados de teclado que proporcionen una manera
intuitiva para que los usuarios puedan navegar rápidamente e interactuar con la interfaz de usuario visible de la aplicación a
través de un teclado, en lugar de a través de funciones táctiles o un mouse. Para obtener más información, consulte Setting
VisualElement Access Keys (Configuración de claves de acceso de VisualElement).
La captura de pantalla siguiente muestra el orden de tabulación para este ejemplo de código:
Aquí, el orden de tabulación está basado en columnas. Por lo tanto, al presionar la tecla TAB se navega por pares
Entry de nombre y apellido.
IMPORTANT
Los lectores de pantalla de iOS y Android respetarán la propiedad TabIndex de un objeto VisualElement al leer los
elementos accesible en la pantalla.
Controles admitidos
Las propiedades TabIndex y IsTapStop se admiten en los siguientes controles, que aceptan entradas de teclado
en una o varias plataformas:
Button
DatePicker
Editor
Entry
NavigationPage
Picker
ProgressBar
SearchBar
Slider
Stepper
Switch
TabbedPage
TimePicker
NOTE
Cada uno de estos controles no puede recibir el foco del tabulador en todas las plataformas.
Vínculos relacionados
Accesibilidad (ejemplo)
Clase App de Xamarin.Forms
11/07/2019 • 8 minutes to read • Edit Online
La clase base Application ofrece las siguientes características, que se exponen en la subclase predeterminada
App de los proyectos:
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Photos.App">
</Application>
Además de establecer la propiedad MainPage , el código subyacente también debe llamar al método
InitializeComponent para cargar y analizar el XAML asociado.
Propiedad MainPage
La propiedad MainPage de la clase Application establece la página raíz de la aplicación.
Por ejemplo, puede crear lógica en la clase App para mostrar otra página en función de si el usuario ha iniciado
sesión o no.
La propiedad MainPage debe establecerse en el constructor App ,
public class App : Xamarin.Forms.Application
{
public App ()
{
MainPage = new ContentPage { Title = "App Lifecycle Sample" }; // your page here
}
}
Diccionario de propiedades
La subclase Application tiene un diccionario estático Properties que se puede usar para almacenar datos, en
particular para su uso en los métodos OnStart , OnSleep y OnResume . Se puede acceder a él desde cualquier lugar
del código de Xamarin.Forms con Application.Current.Properties .
El diccionario Properties usa una clave string y almacena un valor object .
Por ejemplo, puede establecer una propiedad persistente "id" en cualquier lugar del código (al seleccionar un
elemento, en el método OnDisappearing de una página, o en el método OnSleep ) del modo siguiente:
En los métodos OnStart u OnResume puede usar este valor para volver a crear la experiencia del usuario de
alguna manera. El diccionario Properties almacena elementos object , por lo que debe convertir su valor antes
de usarlo.
if (Application.Current.Properties.ContainsKey("id"))
{
var id = Application.Current.Properties ["id"] as int;
// do something with id
}
Verifique siempre la presencia de la clave antes de acceder para evitar errores inesperados.
NOTE
El diccionario Properties solo puede serializar tipos primitivos para el almacenamiento. El intento de almacenar otros tipos
(como List<string> ) puede producir un error en modo silencioso.
Persistencia
El diccionario Properties se guarda automáticamente en el dispositivo. Los datos agregados al diccionario están
disponibles cuando la aplicación vuelve desde el segundo plano o incluso después de su reinicio.
Xamarin.Forms 1.4 ha incorporado un método adicional a la clase Application ( SavePropertiesAsync() ) al que se
puede llamar para conservar de forma proactiva el diccionario Properties . Esto permite guardar propiedades
después de actualizaciones importantes en lugar de arriesgarse a que no se serialicen debido a un bloqueo o a su
eliminación por parte del sistema operativo.
Puede encontrar referencias al uso del diccionario Properties en los capítulos 6, 15 y 20 del libro Creating
Mobile Apps with Xamarin.Forms (Creación de aplicaciones móviles con Xamarin.Forms) y en los ejemplos
asociados.
La clase Application
A continuación se muestra una completa implementación de la clase Application como referencia:
Luego se crean instancias de esta clase en cada proyecto específico de plataforma y se pasa al método
LoadApplication , que es donde se carga MainPage y se muestra al usuario. El código para cada plataforma se
muestra en las secciones siguientes. Las plantillas de solución de Xamarin.Forms más recientes ya contienen todo
este código, preconfigurado para la aplicación.
Proyecto de iOS
La clase AppDelegate de iOS hereda de FormsApplicationDelegate . Debe:
Llamar a LoadApplication con una instancia de la clase App .
Devolver siempre 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 ();
Proyecto de Android
MainActivity de Android hereda de FormsAppCompatActivity . En la invalidación OnCreate , se llama al método
LoadApplication con una instancia de la clase 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);
<forms:WindowsPage
...
xmlns:forms="using:Xamarin.Forms.Platform.UWP"
...>
</forms:WindowsPage>
El código de C# detrás de la construcción debe llamar a LoadApplication para crear una instancia del elemento
App de Xamarin.Forms. Tenga en cuenta que es recomendable usar explícitamente el espacio de nombres de
aplicación para calificar a App , dado que las aplicaciones de UWP también tienen su propia clase App no
relacionada con Xamarin.Forms.
LoadApplication(new YOUR_NAMESPACE.App());
}
}
Tenga en cuenta que Forms.Init() debe llamarse desde App.xaml.cs en el proyecto UWP.
Para obtener más información, consulte Proyectos de instalación de Windows, donde se incluyen instrucciones
para agregar un proyecto UWP a una solución existente de Xamarin.Forms cuyo destino no es UWP.
Ciclo de vida de aplicaciones de Xamarin.Forms
17/07/2019 • 3 minutes to read • Edit Online
NOTE
No hay ningún método para la finalización de aplicaciones. En circunstancias normales (es decir, si no se produce un
bloqueo), la finalización de la aplicación se producirá desde el estado OnSleep, sin que se muestren notificaciones en el
código.
Para observar cuándo se llama a estos métodos, implemente una llamada WriteLine en cada uno (como se
muestra a continuación) y pruébelos en cada plataforma.
IMPORTANT
En Android, se llama al método OnStart por rotación y también cuando la aplicación se inicia por primera vez si la
actividad principal carece de ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation en el
atributo [Activity()] .
Estos eventos pueden usarse en escenarios en los que quiera realizar un seguimiento de las páginas a medida que
aparezcan en la pantalla.
NOTE
Los eventos PageAppearing y PageDisappearing se generan a partir de la clase base Page inmediatamente después de
los eventos Page.Appearing y Page.Disappearing , respectivamente.
NOTE
Los argumentos de evento ModalPopping de tipo ModalPoppingEventArgs contienen una propiedad Cancel . Cuando
Cancel se establece en true , se cancela la ventana emergente modal.
Indexación de la aplicación y vinculación en
profundidad
11/07/2019 • 18 minutes to read • Edit Online
Descargar el ejemplo
La indexación de la aplicación permite a aplicaciones que de lo contrario se olvidarían tras unos pocos usos
mantener su pertinencia al aparecer en los resultados de la búsqueda. La vinculación en profundidad permite a las
aplicaciones responder a un resultado de la búsqueda que contiene datos de aplicación, normalmente al navegar
a una página a la que se hace referencia a partir de un vínculo profundo. En este artículo se explica cómo usar la
indexación de la aplicación y la vinculación en profundidad para que el contenido de las aplicaciones
Xamarin.Forms permita efectuar búsquedas en dispositivos iOS y Android.
NOTE
La funcionalidad de la indexación de la aplicación y de la vinculación en profundidad de Xamarin.Forms solo está disponible
en las plataformas iOS y Android, y requiere como mínimo iOS 9 y API 23, respectivamente.
Programa de instalación
En las siguientes secciones se proporcionan las instrucciones de instalación adicionales para usar esta característica
en las plataformas iOS y Android.
iOS
En la plataforma iOS, asegúrese de que el proyecto de plataforma de iOS establezca el archivo Entitlements.plist
como de derechos personalizados para firmar el conjunto.
Para usar vínculos universales de iOS, realice lo siguiente:
1. Agregue un derecho de dominios asociados a la aplicación con la clave applinks , incluidos todos los dominios
que admitirá la aplicación.
2. Agregue un archivo de asociación de sitios de la aplicación de Apple a su sitio web.
3. Agregue la clave applinks al archivo de asociación de sitios de la aplicación de Apple.
Para obtener más información, vea Allowing Apps and Websites to Link to Your Content (Permitir la vinculación de
contenido a aplicaciones y sitios web) en developer.apple.com.
Android
En la plataforma Android, se deben cumplir los siguientes requisitos previos para usar la funcionalidad de la
indexación de la aplicación y de la vinculación en profundidad:
1. Es necesario tener una versión de la aplicación publicada en Google Play.
2. Es necesario haber registrado un sitio web complementario para la aplicación en la consola del desarrollador de
Google. Una vez que la aplicación esté asociada a un sitio web, las direcciones URL se pueden indexar de forma
que funcionen tanto para el sitio web como para la aplicación. De este modo, podrán aparecer después en los
resultados de la búsqueda. Para obtener más información, vea Indexar aplicaciones en la Búsqueda de Google
en el sitio web de Google.
3. La aplicación debe admitir las intenciones de dirección URL HTTP en la clase MainActivity , que indican a la
indexación de la aplicación los tipos de esquemas de datos de direcciones URL a los que esta puede dar
respuesta. Para obtener más información, vea Configuración del filtro de intención.
Una vez cumplidos estos requisitos previos, para usar la indexación de la aplicación y la vinculación en
profundidad de Xamarin.Forms en la plataforma Android se requiere la siguiente configuración adicional:
1. Instale el paquete NuGet Xamarin.Forms.AppLinks en el proyecto de la aplicación de Android.
2. En el archivo MainActivity.cs, agregue una declaración para usar el espacio de nombres
Xamarin.Forms.Platform.Android.AppLinks .
3. En el archivo MainActivity.cs, agregue una declaración para usar el espacio de nombres Firebase .
4. En un explorador web, cree un nuevo proyecto con la consola Firebase.
5. En la consola Firebase, agregue Firebase a la aplicación Android y escriba los datos necesarios.
6. Descargue el archivo google-services.json resultante.
7. Agregue el archivo google-services.json al directorio raíz del proyecto de Android y establezca el valor
Acción de compilación en GoogleServicesJson.
8. En la invalidación del elemento MainActivity.OnCreate , agregue la siguiente línea de código debajo de
Forms.Init(this, bundle) :
FirebaseApp.InitializeApp(this);
AndroidAppLinks.Init(this);
pageLink.KeyValues.Add("contentType", "TodoItemPage");
pageLink.KeyValues.Add("appName", App.AppName);
pageLink.KeyValues.Add("companyName", "Xamarin");
return pageLink;
}
La instancia AppLinkEntry contiene un número de propiedades cuyos valores son necesarios para indexar la
página y crear un vínculo profundo. Las propiedades Title , Description y Thumbnail se usan para identificar el
contenido indexado cuando este aparece en los resultados de la búsqueda. La propiedad IsLinkActive se
establece en true para indicar que se está visualizando el contenido indexado. La propiedad AppLinkUri es un
elemento Uri que contiene la información necesaria para volver a la página actual y mostrar el elemento
TodoItem actual. A continuación encontrará un elemento Uri de muestra para la aplicación de ejemplo:
http://deeplinking/DeepLinking.TodoItemPage?id=2
Application.Current.AppLinks.RegisterLink (appLink);
NOTE
El método RegisterLink también se puede utilizar para actualizar el contenido que se ha indexado para una página.
Una vez que la instancia AppLinkEntry se ha registrado para la indexación, esta puede aparecer en los resultados
de la búsqueda. La siguiente captura de pantalla muestra el contenido indexado que aparece en los resultados de la
búsqueda en la plataforma iOS:
Anulación del registro del contenido indexado
El método DeregisterLink se usa para eliminar el contenido indexado de los resultados de la búsqueda, tal como
se muestra en el siguiente ejemplo de código:
Application.Current.AppLinks.DeregisterLink (appLink);
NOTE
En Android no es posible eliminar contenido indexado de los resultados de la búsqueda.
El método OnAppLinkRequestReceived comprueba que el elemento Uri recibido esté dirigido a la aplicación, antes
de analizar el elemento Uri para la página a la que se navegará y el parámetro que se pasará a la página. Luego,
se crea una instancia de la página a la que se navegará y se recupera el elemento TodoItem representado por el
parámetro de la página. Posteriormente, el elemento BindingContext de la página a la que se navegará se
establece en TodoItem . Esto garantiza que, cuando el método PushAsync muestre TodoItemPage , se muestre
también el elemento TodoItem cuyo valor ID se encuentra en el vínculo profundo.
Asimismo, al salir de una página representada por un vínculo profundo, la propiedad AppLinkEntry.IsLinkActive
se puede establecer en false . En iOS y Android, esto evita que la instancia AppLinkEntry se anuncie en la
indexación de la búsqueda y, solo en iOS, también evita anunciar la instancia AppLinkEntry para Handoff. Esto se
puede conseguir en la invalidación del elemento Page.OnDisappearing , tal como se muestra en el siguiente ejemplo
de código:
protected override void OnDisappearing()
{
if (appLink != null)
{
appLink.IsLinkActive = false;
}
}
Los valores almacenados en la colección KeyValues se almacenarán en los metadatos de la página indexada y se
restaurarán cuando el usuario pulse un resultado de la búsqueda que contenga un vínculo profundo, o bien al
utilizar Handoff para ver el contenido en otro dispositivo en el que haya iniciado sesión.
Además, se pueden especificar valores para las siguientes claves:
contentType : string que especifica el identificador de tipo uniforme del contenido indexado. La convención
que se recomienda usar para este valor es el nombre del tipo de la página que contiene el contenido indexado.
associatedWebPage : string que representa la página web que se va a visitar si el contenido indexado también
se puede ver en la Web, o bien si la aplicación admite vínculos profundos de Safari.
shouldAddToPublicIndex : string de true o false que controla si se debe agregar el contenido indexado al
índice de la nube pública de Apple y que, posteriormente, se puede presentar a los usuarios que no hayan
instalado la aplicación en su dispositivo iOS. Sin embargo, el hecho de que el contenido se haya establecido
para la indexación pública no significa que se agregue automáticamente al índice de la nube pública de Apple.
Para obtener más información, vea Indexación de búsqueda pública. Tenga en cuenta que, al agregar datos
personales a la colección KeyValues , esta clave se debe establecer en false .
NOTE
La colección KeyValues no se usa en la plataforma Android.
Resumen
En este artículo se ha explicado cómo usar la indexación de la aplicación y la vinculación en profundidad para que
el contenido de las aplicaciones Xamarin.Forms permita efectuar búsquedas en dispositivos iOS y Android. La
indexación de la aplicación permite a aplicaciones que de lo contrario se olvidarían tras unos pocos usos mantener
su pertinencia al aparecer en los resultados de la búsqueda.
Vínculos relacionados
Muestra de vinculación en profundidad
API de búsqueda iOS
Vinculación de aplicaciones en Android 6.0
AppLinkEntry
IAppLinkEntry
IAppLinks
Comportamientos de Xamarin.Forms
11/07/2019 • 2 minutes to read • Edit Online
Los comportamientos permiten agregar funciones a los controles de interfaz de usuario sin tener que incluir
subclases. Los comportamientos se escriben en código y se agregan a controles en XAML o código.
Introducción a comportamientos
Los comportamientos permiten implementar el código que normalmente tendría que escribir como código
subyacente, ya que interactúa directamente con la API del control de manera que puede asociarse al control de
manera concisa. En este artículo se proporciona una introducción a los comportamientos.
Comportamientos asociados
Los comportamientos asociados son clases static con una o varias propiedades adjuntas. En este artículo se
explica cómo crear y consumir comportamientos asociados.
Comportamientos de Xamarin.Forms
Los comportamientos de Xamarin.Forms se crean derivando de la clase Behavior o Behavior<T> . En este artículo
se explica cómo crear y consumir comportamientos de Xamarin.Forms.
Comportamientos reutilizables
Los comportamientos se pueden reutilizar en más de una aplicación. En estos artículos se explica cómo crear
comportamientos útiles para realizar funciones usadas con frecuencia.
Introducción a los comportamientos
11/07/2019 • 2 minutes to read • Edit Online
Los comportamientos permiten agregar funciones a los controles de la interfaz de usuario sin tener que incluirlos
en subclases. En su lugar, la función se implementa en una clase de comportamiento y se asocia al control como si
fuera parte de este. En este artículo, se proporciona una introducción a los comportamientos.
Los comportamientos permiten implementar código que normalmente tendría que escribirse como código
subyacente, ya que interactúan directamente con la API del control, de manera que pueden asociarse al control de
manera concisa y empaquetarse para reutilizarlos en más de una aplicación. Pueden usarse para proporcionar una
amplia variedad de funciones para los controles, como:
Agregar un validador de correo electrónico a un elemento Entry .
Crear un control de calificación mediante un reconocedor de gestos de pulsar.
Controlar una animación.
Agregar un efecto a un control.
Los comportamientos también permiten escenarios más avanzados. En el contexto de los comandos, los
comportamientos son un método útil para conectar un control a un comando. Además, también pueden usarse
para asociar comandos a los controles que no se han diseñado para interactuar con los comandos. Por ejemplo,
pueden usarse para invocar un comando en respuesta a la activación de un evento.
Xamarin.Forms admite dos estilos de comportamiento:
Comportamientos de Xamarin.Forms: clases que derivan de la clase Behavior o Behavior<T> , donde T es
el tipo del control en el que tiene que aplicarse el comportamiento. Para obtener más información sobre los
comportamientos de Xamarin.Forms, vea Comportamientos de Xamarin.Forms y Comportamientos
reutilizables.
Comportamientos asociados: clases de static con una o varias propiedades asociadas. Para obtener más
información sobre los comportamientos asociados, vea Comportamientos asociados.
Esta guía se centra en los comportamientos de Xamarin.Forms, ya que son el método preferido para la creación de
comportamientos.
Vínculos relacionados
Comportamiento
Comportamiento<T>
Comportamientos asociados
11/07/2019 • 7 minutes to read • Edit Online
Descargar el ejemplo
Los comportamientos asociados son clases estáticas con una o varias propiedades asociadas. En este artículo, se
explica cómo crear y usar comportamientos asociados.
Información general
Una propiedad asociada es un tipo especial de propiedad enlazable. Se define en una clase, pero se asocia a otros
objetos y puede reconocerse en XAML como un atributo que contiene una clase y un nombre de propiedad
separado por un punto.
Una propiedad asociada puede definir un delegado propertyChanged que se ejecutará cuando cambie el valor de
la propiedad (por ejemplo, cuando la propiedad se establezca en un control). Cuando se ejecute el delegado
propertyChanged , se pasará una referencia al control donde esté asociado, así como los parámetros que contienen
los valores nuevos y anteriores de la propiedad. Este delegado puede usarse para agregar nuevas funciones al
control al que se asocie la propiedad; para hacerlo, se manipula la referencia en la que se pasa, como se muestra a
continuación:
1. El delegado propertyChanged transmite la referencia del control, que se recibe como un elemento
BindableObject , al tipo de control cuyo comportamiento se ha diseñado para mejorar.
2. El delegado propertyChanged modifica las propiedades del control, llama a métodos del control o registra
controladores de eventos expuestos por el control para implementar la función básica de comportamiento.
Un problema con los comportamientos asociados es que se definen en una clase static , con propiedades y
métodos de static . Esto hace que sea difícil crear comportamientos asociados que tengan un estado. Además,
los comportamientos de Xamarin.Forms han reemplazado a los comportamientos asociados como el método
preferido para la creación de comportamientos. Para obtener más información sobre los comportamientos de
Xamarin.Forms, vea Comportamientos de Xamarin.Forms y Comportamientos reutilizables.
NOTE
Los comportamientos asociados se escriben para un tipo de control específico (o una superclase que se puede aplicar a
muchos controles) y solo se tienen que agregar a un control compatible. Al intentar asociar un comportamiento a un control
incompatible, se producirá un comportamiento desconocido que depende de la implementación del comportamiento.
Resumen
En este artículo, se explica cómo crear y consumir comportamientos asociados. Los comportamientos asociados
son clases static con una o varias propiedades asociadas.
Vínculos relacionados
Comportamientos asociados (ejemplo)
Creación de comportamientos de Xamarin.Forms
11/07/2019 • 11 minutes to read • Edit Online
Descargar el ejemplo
Los comportamientos de Xamarin.Forms se crean mediante la derivación de la clase Behavior o Behavior<T>. En
este artículo se explica cómo crear y consumir comportamientos de Xamarin.Forms.
Información general
El proceso de creación de un comportamiento de Xamarin.Forms es el siguiente:
1. Cree una clase que herede de la clase Behavior o Behavior<T> , donde T sea el tipo del control al que se debe
aplicar el comportamiento.
2. Invalide el método OnAttachedTo para realizar cualquier configuración necesaria.
3. Invalide el método OnDetachingFrom para realizar cualquier limpieza necesaria.
4. Implemente la funcionalidad básica del comportamiento.
El resultado es la estructura que se muestra en el ejemplo de código siguiente:
// Behavior implementation
}
El método OnAttachedTo se desencadena justo después de que se adjunte el comportamiento a un control. Este
método recibe una referencia al control al que se adjunta, y se puede usar para registrar controladores de eventos
o realizar otra configuración necesaria para admitir la funcionalidad del comportamiento. Por ejemplo, se podría
suscribir a un evento en un control. Después, se implementaría la funcionalidad del comportamiento en el
controlador de eventos para el evento.
El método OnDetachingFrom se desencadena cuando se quita el comportamiento del control. Este método recibe
una referencia al control al que se adjunta y se usa para realizar cualquier limpieza necesaria. Por ejemplo, podría
cancelar la suscripción a un evento en un control para evitar fugas de memoria.
Después, el comportamiento se puede consumir si se adjunta a la colección Behaviors del control adecuado.
NOTE
Xamarin.Forms no establece el elemento BindingContext de un comportamiento, ya que los comportamientos se pueden
compartir y aplicar a varios controles mediante estilos.
En el ejemplo de código siguiente se muestra una propiedad adjunta que controla la adición y eliminación de
NumericValidationBehavior :
public class NumericValidationBehavior : Behavior<Entry>
{
public static readonly BindableProperty AttachBehaviorProperty =
BindableProperty.CreateAttached ("AttachBehavior", typeof(bool), typeof(NumericValidationBehavior),
false, propertyChanged: OnAttachBehaviorChanged);
Style se puede aplicar a un control Entry si se establece su propiedad Style en la instancia de Style
mediante la extensión de marcado StaticResource , como se muestra en el ejemplo de código siguiente:
Como alternativa, se puede borrar la colección Behaviors del control, como se muestra en el ejemplo de código
siguiente:
entry.Behaviors.Clear();
Además, tenga en cuenta que los comportamientos no se quitan de forma implícita de los controles cuando se
extraen páginas de la pila de navegación. En su lugar, se deben quitar explícitamente antes de que las páginas
queden fuera del ámbito.
Resumen
En este artículo se ha explicado cómo crear y consumir comportamientos de Xamarin.Forms. Los
comportamientos de Xamarin.Forms se crean mediante la derivación de la clase Behavior o Behavior<T> .
Vínculos relacionados
Comportamiento de Xamarin.Forms (ejemplo)
Comportamiento de Xamarin.Forms aplicado con un estilo (ejemplo)
Behavior
Behavior
Comportamientos reutilizables
11/07/2019 • 2 minutes to read • Edit Online
Los comportamientos se pueden reutilizar en más de una aplicación. En estos artículos se explica cómo crear
comportamientos útiles para realizar funciones usadas con frecuencia.
EffectBehavior reutilizable
Los comportamientos son una manera útil de agregar un efecto a un control, quitando el código de control de
efecto reutilizable de los archivos de código subyacente. En este artículo se explica cómo crear y consumir un
comportamiento de Xamarin.Forms para agregar un efecto a un control.
EventToCommandBehavior reutilizable
Los comportamientos sirven para asociar comandos a los controles que no se han diseñado para interactuar con
los comandos. En este artículo se explica cómo crear y consumir un comportamiento de Xamarin.Forms para
invocar un comando cuando se desencadena un evento.
EffectBehavior reutilizable
11/07/2019 • 7 minutes to read • Edit Online
Descargar el ejemplo
Los comportamientos son una manera útil de agregar un efecto a un control, quitando el código de control de
efecto reutilizable de los archivos de código subyacente. En este artículo se explica cómo crear y consumir un
comportamiento de Xamarin.Forms para agregar un efecto a un control.
Información general
La clase EffectBehavior es un comportamiento personalizado de Xamarin.Forms reutilizable que agrega una
instancia de Effect a un control cuando el comportamiento se asocia al control, y quita la instancia de Effect
cuando el comportamiento se desasocia del control.
Para usar el comportamiento, se deben establecer las propiedades de comportamiento siguientes:
Group: el valor del atributo ResolutionGroupName para la clase del efecto.
Name: el valor del atributo ExportEffect para la clase del efecto.
Para obtener más información sobre los efectos, vea Efectos.
NOTE
EffectBehavior es una clase personalizada que se puede encontrar en el ejemplo Comportamiento de un efecto, y que no
forma parte de Xamarin.Forms.
Cuando se consume EffectBehavior , la propiedad Group se debe establecer en el valor del atributo
ResolutionGroupName para el efecto. Además, la propiedad Name se debe establecer en el valor del atributo
ExportEffect para la clase de efecto.
Implementación de las invalidaciones
La clase EffectBehavior invalida los métodos OnAttachedTo y OnDetachingFrom de la clase Behavior<T> , como se
muestra en el ejemplo de código siguiente:
El método OnAttachedTo realiza la instalación mediante una llamada al método AddEffect , pasando el control
asociado como un parámetro. El método OnDetachingFrom realiza la limpieza mediante una llamada al método
RemoveEffect , pasando el control asociado como un parámetro.
Effect GetEffect ()
{
if (!string.IsNullOrWhiteSpace (Group) && !string.IsNullOrWhiteSpace (Name)) {
return Effect.Resolve (string.Format ("{0}.{1}", Group, Name));
}
return null;
}
}
La ventaja de usar este comportamiento para agregar y quitar efectos de los controles es que se puede quitar el
código de control de efecto reutilizable de los archivos de código subyacente.
Resumen
En este artículo se ha mostrado el uso de un comportamiento para agregar un efecto a un control. La clase
EffectBehavior es un comportamiento personalizado de Xamarin.Forms reutilizable que agrega una instancia de
Effect a un control cuando el comportamiento se asocia al control, y quita la instancia de Effect cuando el
comportamiento se desasocia del control.
Vínculos relacionados
Efectos
Comportamiento de un efecto (ejemplo)
Comportamiento
Comportamiento<T>
EventToCommandBehavior reutilizable
11/07/2019 • 11 minutes to read • Edit Online
Descargar el ejemplo
Los comportamientos se pueden usar para asociar comandos a los controles que no se han diseñado para
interactuar con los comandos. En este artículo se explica cómo crear y consumir un comportamiento de
Xamarin.Forms para invocar un comando cuando se desencadena un evento.
Información general
La clase EventToCommandBehavior es un comportamiento personalizado de Xamarin.Forms reutilizable que ejecuta
un comando como respuesta al desencadenamiento de cualquier evento. De forma predeterminada, los
argumentos para el evento se pasarán al comando y, opcionalmente, se pueden convertir mediante una
implementación IValueConverter .
Para usar el comportamiento, se deben establecer las propiedades de comportamiento siguientes:
EventName: el nombre del evento que escucha el comportamiento.
Command: el elemento ICommand que se va a ejecutar. El comportamiento espera encontrar la instancia de
ICommand en el elemento BindingContext del control adjunto, que se puede heredar de un elemento primario.
NOTE
EventToCommandBehaviores una clase personalizada que se puede encontrar en el ejemplo de comportamiento
EventToCommand y que no forma parte de Xamarin.Forms.
Cuando se consume la clase EventToCommandBehavior , la propiedad Command debe estar enlazada a datos con una
interfaz ICommand que se ejecutará en respuesta al desencadenamiento de eventos que se define en la propiedad
EventName . El comportamiento espera encontrar la interfaz ICommand en el elemento BindingContext del control
adjunto.
De forma predeterminada, los argumentos de evento para el evento se pasarán al comando. Estos datos se
pueden convertir, opcionalmente, cuando el motor de enlace los pasa entre el origen y el destino, mediante la
especificación de una implementación IValueConverter como valor de la propiedad Converter . Como alternativa,
se puede pasar un parámetro para el comando si se especifica el valor de propiedad CommandParameter .
Implementación de las invalidaciones
La clase EventToCommandBehavior invalida los métodos OnAttachedTo y OnDetachingFrom de la clase
BehaviorBase<T> , como se muestra en el ejemplo de código siguiente:
El método OnAttachedTo realiza la instalación mediante una llamada al método RegisterEvent , pasando el valor
de la propiedad EventName como un parámetro. El método OnDetachingFrom realiza la limpieza mediante una
llamada al método DeregisterEvent , pasando el valor de la propiedad EventName como un parámetro.
Implementación de la funcionalidad del comportamiento
El propósito del comportamiento es ejecutar el comando definido por la propiedad Command en respuesta al
desencadenamiento del evento definido por la propiedad EventName . La funcionalidad básica del comportamiento
se muestra en el ejemplo de código siguiente:
public class EventToCommandBehavior : BehaviorBase<View>
{
...
void RegisterEvent (string name)
{
if (string.IsNullOrWhiteSpace (name)) {
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);
}
}
...
}
La propiedad Command del comportamiento está enlazada a datos a la propiedad OutputAgeCommand del modelo de
vista asociado, mientras que la propiedad Converter se establece en la instancia de SelectedItemConverter , que
devuelve el objeto SelectedItem del control ListView del elemento SelectedItemChangedEventArgs .
En tiempo de ejecución, el comportamiento responderá a la interacción con el control. Cuando se selecciona un
elemento en el control ListView , se desencadena el evento ItemSelected , que ejecutará OutputAgeCommand en el
modelo de vista. A su vez, esto actualiza la propiedad SelectedItemText del modelo de vista a la que se enlaza
Label , como se muestra en las capturas de pantalla siguientes:
La ventaja de usar este comportamiento para ejecutar un comando cuando se desencadena un evento es que se
pueden asociar comandos con controles que no se han diseñado para interactuar con los comandos. Además, esto
quita el código de control de eventos reutilizable de los archivos de código subyacente.
Resumen
En este artículo se ha explicado el uso de un comportamiento de Xamarin.Forms para invocar un comando cuando
se desencadena un evento. Los comportamientos se pueden usar para asociar comandos a los controles que no se
han diseñado para interactuar con los comandos.
Vínculos relacionados
Comportamiento de EventToCommand (ejemplo)
Behavior
Comportamiento<T>
Representadores personalizados de Xamarin.Forms
11/07/2019 • 5 minutes to read • Edit Online
Las interfaces de usuario de Xamarin.Forms se representan mediante los controles nativos de la plataforma de
destino, lo que permite que las aplicaciones de Xamarin.Forms conserven la apariencia adecuada para cada
plataforma. Los representadores personalizados permiten que los desarrolladores reemplacen este proceso
para personalizar la apariencia y el comportamiento de los controles de Xamarin.Forms en cada plataforma.
Personalización de un mapa
Xamarin.Forms.Maps proporciona una abstracción multiplataforma para mostrar mapas que usan la API de
mapa nativo en cada plataforma y proporcionar una experiencia de mapa rápida y familiar para los usuarios.
En este tema se muestra cómo crear representadores personalizados para el control Map , lo que permite que
los desarrolladores reemplacen la representación nativa de forma predeterminada por una personalización
propia específica de la plataforma.
Vínculos relacionados
Efectos
Introducción a los representadores personalizados
11/07/2019 • 9 minutes to read • Edit Online
El control MyEntry es un control de Entry en el que BackgroundColor se establece en gris y al que puede hacerse
referencia en XAML mediante la declaración de un espacio de nombres para su ubicación y el uso del prefijo de
espacio de nombres en el elemento de control. En el siguiente ejemplo de código, se muestra cómo usar el control
personalizado MyEntry en una ContentPage :
<ContentPage
...
xmlns:local="clr-namespace:CustomRenderer;assembly=CustomRenderer"
...>
...
<local:MyEntry Text="In Shared Code" />
...
</ContentPage>
El prefijo de espacio de nombres local puede ser cualquier texto. Pero los valores namespace y assembly tienen
que coincidir con los detalles del control personalizado. Después de declarar el espacio de nombres, el prefijo se
usa para hacer referencia al control personalizado.
NOTE
Definir el elemento xmlns es mucho más fácil en proyectos de biblioteca de .NET Standard que en proyectos compartidos.
Una biblioteca de .NET Standard se compila en un ensamblado, por lo que resulta más sencillo determinar cuál tendría que
ser el valor de assembly=CustomRenderer . Al usar proyectos compartidos, todos los activos compartidos (incluido el código
XAML) se compilan en cada uno de los proyectos a los que se hace referencia, lo que significa que, si los proyectos de iOS,
Android y UWP tienen sus propios nombres de ensamblado, resulta imposible escribir la declaración xmlns , ya que el valor
tiene que ser distinto para cada aplicación. Para usar los controles personalizados en XAML para proyectos compartidos, es
necesario configurar cada proyecto de aplicación con el mismo nombre de ensamblado.
Después, el control personalizado MyEntry se representa en cada plataforma, con un fondo gris, como se muestra
en las capturas de pantalla siguientes:
El cambio del color de fondo del control en cada plataforma se ha obtenido simplemente mediante la creación de
subclases del control. Pero los resultados que pueden obtenerse con esta técnica son limitados, ya que no es
posible aprovechar las mejoras y personalizaciones específicas de cada plataforma. Cuando sea necesario usarlos,
tendrán que implementarse representadores personalizados.
NOTE
Para la mayoría de los elementos de Xamarin.Forms, proporcionar un representador personalizado en cada proyecto de la
plataforma es un paso opcional. Si no se registra un representador personalizado, se usará el representador predeterminado
de la clase base del control. Pero los representadores personalizados son necesarios en cada proyecto de la plataforma al
representar un elemento View o ViewCell.
En los temas de esta serie, se proporcionarán demostraciones y explicaciones de este proceso para distintos
elementos de Xamarin.Forms.
Solución de problemas
Si se incluye un control personalizado en un proyecto de biblioteca de .NET Standard agregado a la solución (es
decir, no la biblioteca de .NET Standard creada por la plantilla de proyecto de aplicación de Xamarin.Forms de
Visual Studio o Visual Studio para Mac), puede producirse una excepción en iOS al intentar acceder al control
personalizado. Si se produce este problema, puede solucionarse mediante la creación de una referencia al control
personalizado desde la clase AppDelegate :
var temp = new ClassInPCL(); // in AppDelegate, but temp not used anywhere
Esto obliga al compilador a reconocer el tipo ClassInPCL y solucionarlo. Como alternativa, el atributo Preserve
puede agregarse a la clase AppDelegate para obtener el mismo resultado:
De esta forma, se crea una referencia al tipo ClassInPCL , lo que indica que se necesita en tiempo de ejecución. Para
obtener más información, vea Conservar código.
Resumen
En este artículo, se proporciona una introducción a los representadores personalizados y se describe el proceso
para crear un representador personalizado. Los representadores personalizados proporcionan un método eficaz
para personalizar la apariencia y el comportamiento de los controles de Xamarin.Forms. Se pueden usar para
realizar pequeños cambios de estilo o para una personalización sofisticada del diseño y el comportamiento
específicos de una plataforma.
Vínculos relacionados
Efectos
Clases base y controles nativos del representador
11/07/2019 • 5 minutes to read • Edit Online
Todos los controles de Xamarin.Forms tienen un representador que los acompaña para cada plataforma y que
crea una instancia de un control nativo. En este artículo se enumeran las clases de representador y control
nativo que implementan cada página, diseño, vista y celda de Xamarin.Forms.
A excepción de la clase MapRenderer , los representadores específicos de la plataforma se pueden encontrar en
los espacios de nombres siguientes:
iOS: Xamarin.Forms.Platform.iOS
Android: Xamarin.Forms.Platform.Android
Android (AppCompat) : Xamarin.Forms.Platform.Android.AppCompat
Plataforma universal de Windows (UWP ) : Xamarin.Forms.Platform.UWP
La clase MapRenderer se puede encontrar en los espacios de nombres siguientes:
iOS: Xamarin.Forms.Maps.iOS
Android: Xamarin.Forms.Maps.Android
Plataforma universal de Windows (UWP ) : Xamarin.Forms.Maps.UWP
NOTE
Para información sobre cómo crear representadores personalizados para aplicaciones de Shell, consulte Representadores
personalizados de Xamarin.Forms Shell.
Páginas
En la tabla siguiente se enumeran las clases de representador y control nativo que implementan cada tipo Page
de Xamarin.Forms:
ANDROID
PÁGINA REPRESENTADOR IOS ANDROID (APPCOMPAT) UWP
Diseños
En la tabla siguiente se enumeran las clases de representador y control nativo que implementan cada tipo
Layout de Xamarin.Forms:
ANDROID
VISTAS REPRESENTADOR IOS ANDROID (APPCOMPAT) UWP
Celdas
En la tabla siguiente se enumeran las clases de representador y control nativo que implementan cada tipo Cell
de Xamarin.Forms:
Resumen
En este artículo se han enumerado las clases de representador y control nativo que implementan cada página,
diseño, vista y celda de Xamarin.Forms. Todos los controles de Xamarin.Forms tienen un representador que lo
acompaña para cada plataforma y que crea una instancia de un control nativo.
Personalización de una entrada
11/07/2019 • 12 minutes to read • Edit Online
Descargar el ejemplo
El control Entry de Xamarin.Forms permite que se edite una sola línea de texto. En este artículo se muestra cómo
crear un representador personalizado para el control Entry, lo que permite que los desarrolladores reemplacen la
representación nativa de forma predeterminada con su propia personalización específica de la plataforma.
Todos los controles de Xamarin.Forms tienen un representador que lo acompaña para cada plataforma y que crea
una instancia de un control nativo. Cuando una aplicación de Xamarin.Forms representa un control Entry , se crea
una instancia de la clase EntryRenderer en iOS que, a su vez, crea una instancia de un control UITextField nativo.
En la plataforma Android, la clase EntryRenderer crea una instancia de un control EditText . En la Plataforma
universal de Windows (UWP ), la clase EntryRenderer crea una instancia de un control TextBox . Para obtener más
información sobre el representador y las clases de control nativo a las que se asignan los controles de
Xamarin.Forms, vea Renderer Base Classes and Native Controls (Clases base y controles nativos del
representador).
El siguiente diagrama muestra la relación entre el control Entry y los controles nativos correspondientes que lo
implementan:
El control MyEntry se crea en el proyecto de biblioteca de .NET Standard y es simplemente un control Entry . La
personalización del control se llevará a cabo en el representador personalizado, por lo que no se requiere ninguna
implementación adicional en el control MyEntry .
<ContentPage ...
xmlns:local="clr-namespace:CustomRenderer;assembly=CustomRenderer"
...>
...
<local:MyEntry Text="In Shared Code" />
...
</ContentPage>
El prefijo de espacio de nombres local puede tener cualquier nombre. Pero los valores clr-namespace y
assembly deben coincidir con los detalles del control personalizado. Una vez que se declara el espacio de
nombres, el prefijo se usa para hacer referencia al control personalizado.
El siguiente ejemplo de código muestra cómo el control personalizado MyEntry puede utilizarse en una página 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,
};
}
}
Este código crea una instancia de un nuevo objeto ContentPage que mostrará un Label y un control MyEntry
centrado tanto vertical como horizontalmente en la página.
Ahora se puede agregar un representador personalizado a cada proyecto de aplicación para personalizar la
apariencia del control en cada plataforma.
NOTE
Proporcionar un representador personalizado en cada proyecto de la plataforma es un paso opcional. Si no hay un
representador personalizado registrado, se usa el representador predeterminado de la clase base del control.
El siguiente diagrama muestra las responsabilidades de cada proyecto de la aplicación de ejemplo, junto con las
relaciones entre ellos:
La clase EntryRenderer expone el método OnElementChanged , al que se llama cuando se crea el control de
Xamarin.Forms para representar el control nativo correspondiente. Este método toma un parámetro
ElementChangedEventArgs que contiene propiedades OldElement y NewElement . Estas propiedades representan al
elemento de Xamarin.Forms al que estaba asociado el representador y al elemento de Xamarin.Forms al que está
asociado el representador, respectivamente. En la aplicación de ejemplo, la propiedad OldElement es null y la
propiedad NewElement contiene una referencia al control de MyEntry .
El lugar para realizar la personalización del control nativo es una versión reemplazada del método
OnElementChanged en la clase MyEntryRenderer . Una referencia con tipo para el control nativo que se usa en la
plataforma puede obtenerse a través de la propiedad Control . Además, se puede obtener una referencia al
control de Xamarin.Forms que se representa mediante la propiedad Element , aunque no se usa en la aplicación de
ejemplo.
Cada clase de representador personalizado se decora con un atributo ExportRenderer que registra el
representador con Xamarin.Forms. El atributo toma dos parámetros: el nombre de tipo del control de
Xamarin.Forms que se va a representar y el nombre de tipo del representador personalizado. El prefijo assembly
para el atributo especifica que el atributo se aplica a todo el ensamblado.
En las secciones siguientes se describe la implementación de cada clase de representador personalizado
MyEntryRenderer específico de plataforma.
using Xamarin.Forms.Platform.iOS;
if (Control != null) {
// do whatever you want to the UITextField here!
Control.BackgroundColor = UIColor.FromRGB (204, 153, 255);
Control.BorderStyle = UITextBorderStyle.Line;
}
}
}
}
La llamada al método OnElementChanged de la clase base crea una instancia de un control UITextField de iOS, con
una referencia al control que se asigna en la propiedad Control del representador. Después se establece el color
de fondo en púrpura claro con el método UIColor.FromRGB .
Creación del representador personalizado en Android
En el ejemplo de código siguiente se muestra el representador personalizado para la plataforma Android:
using Xamarin.Forms.Platform.Android;
if (Control != null)
{
Control.SetBackgroundColor(global::Android.Graphics.Color.LightGreen);
}
}
}
}
La llamada al método OnElementChanged de la clase base crea una instancia de un control EditText de Android,
con una referencia al control que se asigna en la propiedad Control del representador. Después se establece el
color de fondo en verde claro con el método Control.SetBackgroundColor .
Creación del representador personalizado en UWP
En el siguiente ejemplo de código se muestra el representador personalizado para UWP:
if (Control != null)
{
Control.Background = new SolidColorBrush(Colors.Cyan);
}
}
}
}
La llamada al método OnElementChanged de la clase base crea una instancia de un control TextBox , con una
referencia al control que se asigna en la propiedad Control del representador. Después se establece el color de
fondo en cian mediante la creación de una instancia de SolidColorBrush .
Resumen
En este artículo se mostró cómo crear un representador de control personalizado para el control Entry de
Xamarin.Forms, lo que permite que los desarrolladores reemplacen la representación nativa de forma
predeterminada con su propia representación específica de la plataforma. Los representadores personalizados
proporcionan un método eficaz para personalizar la apariencia de los controles de Xamarin.Forms. Se pueden usar
para pequeños cambios de estilo o para una personalización sofisticada del diseño y el comportamiento
específicos de una plataforma.
Vínculos relacionados
CustomRendererEntry (sample) (CustomRendererEntry [ejemplo])
Personalización de una página de contenido
11/07/2019 • 14 minutes to read • Edit Online
Descargar el ejemplo
Un ContentPage es un elemento visual que muestra una vista única y ocupa la mayor parte de la pantalla. En este
artículo se muestra cómo crear un representador personalizado para la página ContentPage, lo que permite que
los desarrolladores reemplacen la representación nativa de forma predeterminada con su propia personalización
específica de la plataforma.
Todos los controles de Xamarin.Forms tienen un representador que lo acompaña para cada plataforma y que crea
una instancia de un control nativo. Cuando una aplicación de Xamarin.Forms representa una ContentPage , en iOS
se crea la instancia de la clase PageRenderer , que a su vez crea una instancia del control UIViewController nativo.
En la plataforma Android, la clase PageRenderer crea una instancia de un control ViewGroup . En la Plataforma
universal de Windows (UWP ), la clase PageRenderer crea una instancia de un control FrameworkElement . Para
obtener más información sobre el representador y las clases de control nativo a las que se asignan los controles de
Xamarin.Forms, vea Renderer Base Classes and Native Controls (Clases base y controles nativos del
representador).
El siguiente diagrama muestra la relación entre la clase ContentPage y los controles nativos correspondientes que
la implementan:
De forma similar, el archivo de código subyacente para el ContentPage también debe permanecer sin
modificaciones, como se muestra en el siguiente ejemplo de código:
Una instancia de la CameraPage se usará para mostrar la fuente de la cámara en directo en cada plataforma. La
personalización del control se llevará a cabo en el representador personalizado, por lo que no se requiere ninguna
implementación adicional en la clase CameraPage .
NOTE
Proporcionar un representador de página en cada proyecto de la plataforma es un paso opcional. Si no hay un representador
de página registrado, se usa el representador predeterminado de la página.
El siguiente diagrama muestra las responsabilidades de cada proyecto de la aplicación de ejemplo, junto con las
relaciones entre ellos:
La clase PageRenderer expone el método OnElementChanged , al que se llama cuando se crea una página de
Xamarin.Forms para representar el control nativo correspondiente. Este método toma un parámetro
ElementChangedEventArgs que contiene propiedades OldElement y NewElement . Estas propiedades representan al
elemento de Xamarin.Forms al que estaba asociado el representador y al elemento de Xamarin.Forms al que está
asociado el representador, respectivamente. En la aplicación de ejemplo, la propiedad OldElement es null y la
propiedad NewElement contiene una referencia a la instancia de CameraPage .
El lugar para realizar la personalización de páginas nativas es una versión reemplazada del método
OnElementChanged en la clase CameraPageRenderer . Se puede obtener una referencia a la instancia de la página de
Xamarin.Forms que se representa mediante la propiedad Element .
Cada clase de representador personalizado se decora con un atributo ExportRenderer que registra el
representador con Xamarin.Forms. El atributo toma dos parámetros: el nombre de tipo de la página de
Xamarin.Forms que se representa y el nombre de tipo del representador personalizado. El prefijo assembly para el
atributo especifica que el atributo se aplica a todo el ensamblado.
En las secciones siguientes se describe la implementación del representador personalizado de CameraPageRenderer
para cada plataforma.
Creación del representador de página en iOS
El siguiente ejemplo de código muestra el representador de página para la plataforma iOS:
try {
SetupUserInterface ();
SetupEventHandlers ();
SetupLiveCameraStream ();
AuthorizeCameraUse ();
} catch (Exception ex) {
System.Diagnostics.Debug.WriteLine (@" ERROR: ", ex.Message);
}
}
...
}
}
La llamada al método OnElementChanged de la clase base crea una instancia de un control UIViewController de
iOS. Solo se procesa la secuencia en directo de cámara si el representador aún no está unido a un elemento
existente de Xamarin.Forms, y siempre que exista una instancia de la página que se representa mediante el
representador personalizado.
Después, se personaliza la página mediante una serie de métodos que usan la API de AVCapture para
proporcionar la secuencia en directo desde la cámara y la capacidad para capturar una foto.
Creación del representador de página en Android
En el ejemplo de código siguiente se muestra el representador de página para la plataforma Android:
[assembly: ExportRenderer(typeof(CameraPage), typeof(CameraPageRenderer))]
namespace CustomRenderer.Droid
{
public class CameraPageRenderer : PageRenderer, TextureView.ISurfaceTextureListener
{
...
public CameraPageRenderer(Context context) : base(context)
{
}
try
{
SetupUserInterface();
SetupEventHandlers();
AddView(view);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(@" ERROR: ", ex.Message);
}
}
...
}
}
La llamada al método de la clase base OnElementChanged crea una instancia de un control ViewGroup de Android,
que es un grupo de vistas. Solo se procesa la secuencia en directo de cámara si el representador aún no está unido
a un elemento existente de Xamarin.Forms, y siempre que exista una instancia de la página que se representa
mediante el representador personalizado.
Después se personaliza la página mediante la invocación de una serie de métodos que usan la API de Camera para
proporcionar la secuencia en directo desde la cámara y la capacidad de capturar una foto, antes de que se invoque
al método AddView para agregar la interfaz de usuario de la transmisión de cámara en vivo al ViewGroup . Tenga
en cuenta que en Android también es necesario reemplazar el método OnLayout para realizar operaciones de
medida y de diseño en la vista. Para obtener más información, vea el ejemplo de representador de ContentPage.
Creación del representador de página en UWP
En el siguiente ejemplo de código se muestra el representador de página para 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);
try
{
...
SetupUserInterface();
SetupBasedOnStateAsync();
this.Children.Add(page);
}
...
}
La llamada al método OnElementChanged de la clase base crea una instancia de un control FrameworkElement , en el
que se representa la página. Solo se procesa la secuencia en directo de cámara si el representador aún no está
unido a un elemento existente de Xamarin.Forms, y siempre que exista una instancia de la página que se
representa mediante el representador personalizado. Después se personaliza la página mediante la invocación de
una serie de métodos que usan la API de MediaCapture para proporcionar la secuencia en directo desde la cámara
y la capacidad de capturar una foto, antes de que se agregue la página personalizada a la colección Children para
mostrarla.
Al implementar un representador personalizado que derive de PageRenderer en UWP, el método ArrangeOverride
también debe implementarse para organizar los controles de página, ya que el representador de base no sabe qué
hacer con ellos. En caso contrario, da como resultado una página en blanco. Por lo tanto, en este ejemplo el
método ArrangeOverride llama al método Arrange en la instancia de Page .
NOTE
Es importante detener y eliminar los objetos que proporcionan acceso a la cámara en una aplicación de UWP. Si no lo hace
puede interferir con otras aplicaciones que intentan acceder a la cámara del dispositivo. Para obtener más información, vea
Display the camera preview (Mostar la vista previa de la cámara).
Resumen
En este artículo se mostró cómo crear un representador personalizado para la página ContentPage , lo que permite
que los desarrolladores reemplacen la representación nativa de forma predeterminada con su propia
personalización específica de la plataforma. Un ContentPage es un elemento visual que muestra una vista única y
ocupa la mayor parte de la pantalla.
Vínculos relacionados
CustomRendererContentPage (sample) (CustomRendererContentPage [ejemplo])
Personalizar un mapa de Xamarin.Forms
11/07/2019 • 2 minutes to read • Edit Online
Xamarin.Forms.Maps proporciona una abstracción multiplataforma para mostrar mapas que usan la API de
mapa nativo en cada plataforma y proporcionar una experiencia de mapa rápida y familiar para los usuarios.
Descargar el ejemplo
En este artículo se explica cómo crear un representador personalizado para el control de mapa, que muestra un
mapa nativo con una marca personalizada y una vista personalizada de los datos de marca en cada plataforma.
Todos las vistas de Xamarin.Forms tienen un representador que lo acompaña para cada plataforma y que crea
una instancia de un control nativo. Cuando una aplicación de Xamarin.Forms representa una Map en iOS se crea
la instancia de la clase MapRenderer , que a su vez crea una instancia del control MKMapView nativo. En la
plataforma Android, la clase MapRenderer crea una instancia del control MapView nativo. En la Plataforma
Universal de Windows (UWP ), la clase MapRenderer crea una instancia de MapControl nativa. Para obtener más
información sobre las clases de control nativo que se asignan a los controles de Xamarin.Forms y el
representador, vea Renderer Base Classes and Native Controls (Controles nativos y clases base del
representador).
El siguiente diagrama ilustra la relación entre la Map y los controles nativos correspondientes que la
implementan:
El proceso de representación puede usarse para implementar las personalizaciones específicas de la plataforma
creando un representador personalizado para una Map en cada plataforma. El proceso para hacer esto es el
siguiente:
1. Cree un mapa personalizado de Xamarin.Forms.
2. Consuma el mapa personalizado de Xamarin.Forms.
3. Cree el representador personalizado para el mapa en cada plataforma.
Se explicará cada elemento uno por uno, para implementar un representador CustomMap que muestra un mapa
nativo con una marca personalizada y una vista personalizada de los datos de marcas en cada plataforma.
NOTE
Xamarin.Forms.Maps debe inicializarse y configurarse antes de su uso. Para obtener más información, vea Maps Control .
El control CustomMap se crea en el proyecto de biblioteca de .NET Standard y define la API para el mapa
personalizado. El mapa personalizado expone la propiedad CustomPins que representa la colección de objetos
CustomPin que va a representar el control de mapa nativo en cada plataforma. La clase CustomPin se muestra en
el siguiente ejemplo de código:
Esta clase define que un CustomPin hereda las propiedades de la clase Pin y agrega una propiedad Url .
<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>
El prefijo del espacio de nombres local puede tener cualquier nombre. Empero, los valores deben
clr-namespace y assembly coincidir con los detalles del mapa personalizado. Una vez que se declare el espacio
de nombres, el prefijo se utiliza para hacer referencia al mapa personalizado.
El siguiente ejemplo de código muestra cómo el control personalizado CustomMap puede utilizarse en una página
C#:
public class MapPageCS : ContentPage
{
public MapPageCS ()
{
var customMap = new CustomMap {
MapType = MapType.Street,
WidthRequest = App.ScreenWidth,
HeightRequest = App.ScreenHeight
};
...
Content = customMap;
}
}
La instancia CustomMap se usará para mostrar el mapa nativo en cada plataforma. La propiedad MapType
establece el estilo de presentación del Map y los valores posibles que se definen en la enumeración MapType .
Para iOS y Android, el ancho y alto del mapa se establece a través de las propiedades de la clase App que se
inicializan en los proyectos específicos de la plataforma.
La ubicación del mapa y las marcas que contiene se inicializan como se muestra en el siguiente ejemplo 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/"
};
Esta inicialización agrega una marca personalizada y coloca la vista del mapa con el método MoveToRegion , que
cambia la posición y el nivel de zoom del mapa mediante la creación de un MapSpan desde un Position y un
Distance .
Ahora se puede agregar un representador personalizado a cada proyecto de aplicación para personalizar los
controles de mapa nativos.
El siguiente diagrama ilustra las responsabilidades de cada proyecto en la aplicación de ejemplo, junto con las
relaciones entre ellos:
Las clases del representador específico de la plataforma, que se derivan de la clase MapRenderer para cada
plataforma, representan el control CustomMap . Esto da como resultado que cada control CustomMap se represente
con controles específicos de la plataforma, como se muestra en las siguientes capturas de pantalla:
La clase MapRenderer expone el método OnElementChanged , al que se llama cuando se crea un mapa personalizado
de Xamarin.Forms para representar el control nativo correspondiente. Este método toma un parámetro
ElementChangedEventArgs que contiene propiedades OldElement y NewElement . Estas propiedades representan al
elemento de Xamarin.Forms al que estaba asociado el representador y al elemento de Xamarin.Forms al que está
asociado el representador, respectivamente. En la aplicación de ejemplo la propiedad OldElement será null y la
propiedad NewElement contendrá una referencia a la instancia CustomMap .
El lugar para realizar la personalización de controles nativos es una versión reemplazada del método
OnElementChanged en cada clase de representador específica de la plataforma. Una referencia con tipo para el
control nativo que se usa en la plataforma puede obtenerse a través de la propiedad Control . Además, se puede
obtener una referencia al control de Xamarin.Forms que se representa mediante la propiedad Element .
Debe tener cuidado al suscribirse a los controladores de eventos en el método OnElementChanged , como se
muestra en el siguiente ejemplo 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
}
}
Solo se debe configurar el control nativo y suscribir los controladores de eventos cuando se adjunta el
presentador personalizado a un nuevo elemento de Xamarin.Forms. De forma similar, solo se debe cancelar la
suscripción de los controladores de eventos que se han suscrito cuando cambia el elemento al que está asociado
el presentador. Adoptar este enfoque facilita crear un presentador personalizado que no sufra pérdidas de
memoria.
Cada clase de presentador personalizado se decora con un atributo ExportRenderer que registra el representador
con Xamarin.Forms. El atributo toma dos parámetros: el nombre de tipo del control personalizado de
Xamarin.Forms que se va a representar y el nombre de tipo del representador personalizado. El prefijo assembly
para el atributo especifica que el atributo se aplica a todo el ensamblado.
En las secciones siguientes se describe la implementación de cada clase de representador personalizado
específico de plataforma.
Creación del representador personalizado en iOS
Las siguientes capturas de pantalla muestran el mapa antes y después de la personalización:
En iOS la marca se denomina anotación y puede ser una imagen personalizada o una marca definida por el
sistema de varios colores. Opcionalmente las anotaciones pueden mostrar una llamada, que se muestra en
respuesta a que el usuario seleccione la anotación. La llamada muestra las propiedades Label y Address de la
instancia Pin , con vistas adicionales a la derecha y a la izquierda. En la captura de pantalla anterior, la vista
adicional izquierda es la imagen de un mono y la vista adicional derecha es el botón Información.
El siguiente ejemplo de código muestra el representador personalizado para la plataforma de iOS:
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace CustomRenderer.iOS
{
public class CustomMapRenderer : MapRenderer
{
UIView customPinView;
List<CustomPin> customPins;
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;
}
}
...
}
}
El método OnElementChanged realiza la siguiente configuración de la instancia MKMapView , siempre que se adjunte
el presentador personalizado a un nuevo elemento de Xamarin.Forms:
La propiedad GetViewForAnnotation se establece en el método GetViewForAnnotation . Se llama a este método
cuando la ubicación de la anotación se vuelve visible en el mapa y se usa para personalizar la anotación antes
de mostrarla.
Los controladores de eventos para los eventos CalloutAccessoryControlTapped , DidSelectAnnotationView y
DidDeselectAnnotationView se registran. Estos eventos se activan cuando el usuario pulsa el accesorio derecho
de la llamada y cuando el usuario selecciona y anula la selección de la anotación, respectivamente. Se cancela
la suscripción de los eventos solo cuando cambia el representador al que está adjunto el elemento.
Mostrar la anotación
Se llama al método GetViewForAnnotation cuando la ubicación de la anotación se vuelve visible en el mapa y se
usa para personalizar la anotación antes de mostrarla. Una anotación tiene dos partes:
MkAnnotation: incluye el título, el subtítulo y la ubicación de la anotación.
MkAnnotationView : contiene la imagen para representar la anotación y, opcionalmente, una llamada que se
muestra cuando el usuario pulsa la anotación.
El método GetViewForAnnotation acepta un IMKAnnotation que contiene los datos de la anotación y devuelve un
MKAnnotationView para su presentación en el mapa. Se muestra en el siguiente ejemplo de código:
protected override MKAnnotationView GetViewForAnnotation(MKMapView mapView, IMKAnnotation annotation)
{
MKAnnotationView annotationView = null;
if (annotation is MKUserLocation)
return null;
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;
}
Este método garantiza que la anotación se muestre como una imagen personalizada, en lugar de como una marca
definida por el sistema y que, cuando se pulsa la anotación, se muestre una llamada que incluye contenido
adicional a la izquierda y a la derecha del título y la dirección de la anotación. Esto se logra de la siguiente manera:
1. Se llama al método GetCustomPin para devolver los datos de marca personalizada para la anotación.
2. Para ahorrar memoria, la vista de la anotación se agrupa para volver a usarla con la llamada a
DequeueReusableAnnotation .
3. La clase CustomMKAnnotationView extiende la clase MKAnnotationView con las propiedades Id y Url que
corresponden a las propiedades idénticas en la instancia CustomPin . Se crea una nueva instancia de la
CustomMKAnnotationView , siempre que la anotación sea null :
La propiedad CustomMKAnnotationView.Image se establece en la imagen que representará la anotación en
el mapa.
La propiedad CustomMKAnnotationView.CalloutOffset se establece en un CGPoint que especifica que la
llamada se centrará por encima de la anotación.
La propiedad CustomMKAnnotationView.LeftCalloutAccessoryView se establece en una imagen de un
mono que aparecerá a la izquierda del título y la dirección de la anotación.
La propiedad CustomMKAnnotationView.RightCalloutAccessoryView se establece en un botón Información
que aparecerá a la derecha del título y la dirección de la anotación.
La propiedad CustomMKAnnotationView.Id se establece en la propiedad CustomPin.Id devuelta por el
método GetCustomPin . Esto permite que la anotación pueda identificarse de forma que su llamada
pueda personalizarse aún más si así lo desea.
La propiedad CustomMKAnnotationView.Url se establece en la propiedad CustomPin.Url devuelta por el
método GetCustomPin . La dirección URL se abrirá cuando el usuario pulse el botón que se muestra en
la vista de accesorios de llamada correcta.
4. La propiedad MKAnnotationView.CanShowCallout se establece en true para que se muestre la llamada cuando
se pulsa la anotación.
5. La anotación se devuelve para su visualización en el mapa.
Seleccionar la anotación
Cuando el usuario pulsa en la anotación, se desencadena el evento DidSelectAnnotationView , que a su vez ejecuta
el método OnDidSelectAnnotationView :
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);
}
}
Este método extiende la llamada existente (que contiene las vistas adicionales izquierdas y derechas) mediante la
adición de una instancia de UIView a ella que contiene una imagen del logotipo de Xamarin, siempre que la
anotación seleccionada tenga su propiedad Id establecida en Xamarin . Esto permite escenarios donde se
pueden mostrar llamadas diferentes para distintas anotaciones. La instancia UIView se mostrará centrada por
encima de la llamada existente.
Pulsar en la vista adicional de llamada derecha
Cuando el usuario pulsa el botón Información en la vista adicional de llamada derecha, se desencadena el evento
CalloutAccessoryControlTapped , que a su vez ejecuta el método OnCalloutAccessoryControlTapped :
Este método garantiza que cuando la llamada existente no está seleccionada, la parte extendida de la llamada (la
imagen del logotipo de Xamarin) también dejará de mostrarse y se liberarán sus recursos.
Para obtener más información sobre cómo personalizar una instancia de MKMapView , vea Maps in Xamarin.iOS
(Mapas en Xamarin.iOS ).
Creación del representador personalizado en Android
Las siguientes capturas de pantalla muestran el mapa antes y después de la personalización:
En Android la marca se denomina marcador y puede ser una imagen personalizada o un marcador definido por
el sistema de varios colores. Los marcadores pueden mostrar una ventana de información, que se muestra en la
respuesta para el usuario que pulsa en el marcador. Muestra la ventana de información de las propiedades Label
y Address de la instancia Pin y se pueden personalizar para incluir otro tipo de contenido. Con todo, solo una
ventana de información puede mostrarse al mismo tiempo.
El siguiente ejemplo de código muestra el representador personalizado para la plataforma de Android:
if (e.OldElement != null)
{
NativeMap.InfoWindowClick -= OnInfoWindowClick;
}
if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
customPins = formsMap.CustomPins;
Control.GetMapAsync(this);
}
}
NativeMap.InfoWindowClick += OnInfoWindowClick;
NativeMap.SetInfoWindowAdapter(this);
}
...
}
}
Siempre que se adjunta el representador personalizado a un nuevo elemento de Xamarin.Forms, el método
OnElementChanged llama al método MapView.GetMapAsync , que obtiene la interfaz GoogleMap que está asociada a la
vista. Una vez que la instancia GoogleMap esté disponible, se invocará la invalidación OnMapReady . Este método
registra un controlador de eventos para el evento InfoWindowClick , que se desencadena cuando se hace clic en la
ventana de información y cuya suscripción solo se cancela cuando cambia el elemento al que está adjunto el
representador. La invalidación OnMapReady también llama al método SetInfoWindowAdapter para especificar que la
instancia de la clase CustomMapRenderer proporcionará los métodos para personalizar la ventana de información.
La clase CustomMapRenderer implementa la interfaz GoogleMap.IInfoWindowAdapter para personalizar la ventana de
información. Esta interfaz especifica que se deben implementar los siguientes métodos:
public Android.Views.View GetInfoWindow(Marker marker) : se llama a este método para devolver una ventana de
información personalizada para un marcador. Si se devuelve null , se usará la representación de la ventana
predeterminada. Si se devuelve un View , View se colocará dentro del marco de la ventana de información.
public Android.Views.View GetInfoContents(Marker marker) : se llama a este método para devolver un View que
contiene el contenido de la ventana de información, y solo se llamará si el método GetInfoWindow devuelve
null . Si devuelve null , se usará la representación predeterminada del contenido de la ventana de
información.
En la aplicación de ejemplo, solo se personaliza el contenido de la ventana de información, de forma que el
método GetInfoWindow devuelve null para habilitar esto.
Personalización del marcador
El icono utilizado para representar un marcador puede personalizarse mediante una llamada al método
MarkerOptions.SetIcon . Esto puede realizarse invalidando el método CreateMarker , que se invoca para cada Pin
que se agrega al mapa:
Este método crea una nueva instancia de MarkerOption para cada instancia de Pin . Después de establecer la
posición, la etiqueta y la dirección del marcador, su icono se establece con el método SetIcon . Este método toma
un objeto BitmapDescriptor que contiene los datos necesarios para representar el icono y la clase
BitmapDescriptorFactory proporciona métodos auxiliares para simplificar la creación de la BitmapDescriptor .
Para obtener más información sobre el uso de la clase BitmapDescriptorFactory para personalizar un marcador,
vea Customizing a Marker (Personalización de un marcador).
NOTE
Si es necesario, el método GetMarkerForPin se puede invocar en el representador de mapa para recuperar un Marker de
una Pin .
if (customPin.Id.ToString() == "Xamarin") {
view = inflater.Inflate (Resource.Layout.XamarinMapInfoWindow, null);
} else {
view = inflater.Inflate (Resource.Layout.MapInfoWindow, null);
}
if (infoTitle != null) {
infoTitle.Text = marker.Title;
}
if (infoSubtitle != null) {
infoSubtitle.Text = marker.Snippet;
}
return view;
}
return null;
}
Este método devuelve un View con el contenido de la ventana de información. Esto se logra de la siguiente
manera:
Se recupera una instancia de LayoutInflater . Esta se usa para crear una instancia de un archivo XML de
diseño en su View correspondiente.
Se llama al método GetCustomPin para devolver los datos de marca personalizada para la ventana de
información.
Se aumenta el diseño de XamarinMapInfoWindow si la propiedad CustomPin.Id es igual a Xamarin . En caso
contrario, se aumenta el diseño de MapInfoWindow . Esto permite escenarios donde se pueden mostrar
diferentes diseños de ventana de información para distintos marcadores.
Se recuperan los recursos InfoWindowTitle y InfoWindowSubtitle desde el diseño aumentado y sus
propiedades Text se establecen en los datos correspondientes de la instancia de Marker , siempre que los
recursos no sean null .
La instancia de View se devuelve para su visualización en el mapa.
NOTE
Una ventana de información no es una View dinámica. En su lugar, Android convertirá la View a mapa de bits estático y
la mostrará como una imagen. Esto significa que, mientras que una ventana de información puede responder a un evento
de clic, no puede responder a los eventos de toque o gestos, y los controles individuales en la ventana de información no
pueden responder a sus propios eventos de clic.
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);
}
}
Este método abre un explorador web y navega a la dirección almacenada en la propiedad Url de la instancia
CustomPin recuperada para el Marker . Tenga en cuenta que la dirección se definió al crear la colección CustomPin
en el proyecto de biblioteca de .NET Standard.
Para obtener más información sobre cómo personalizar una instancia de MapView , vea Using the Google Maps
API in your application (Uso de la API de Google Maps en su aplicación).
Creación de un representador personalizado en la Plataforma universal de Windows
Las siguientes capturas de pantalla muestran el mapa antes y después de la personalización:
En la UWP la marca se denomina icono de mapa y puede ser una imagen personalizada o la imagen
predeterminada definida por el sistema. Un icono de mapa puede mostrar un UserControl , que se muestra en la
respuesta para el usuario que pulsa en el icono de mapa. El UserControl puede mostrar cualquier contenido,
incluyendo las propiedades Label y Address de la instancia Pin .
El siguiente ejemplo de código muestra el representador personalizado de UWP:
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace CustomRenderer.UWP
{
public class CustomMapRenderer : MapRenderer
{
MapControl nativeMap;
List<CustomPin> customPins;
XamarinMapOverlay mapOverlay;
bool xamarinOverlayShown = false;
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;
nativeMap.MapElements.Add(mapIcon);
}
}
}
...
}
}
El método OnElementChanged realiza las siguientes operaciones, siempre que se adjunte el presentador
personalizado a un nuevo elemento de Xamarin.Forms:
Borra la colección de MapControl.Children para quitar los elementos de interfaz de usuario existentes del
mapa y después registra un controlador de eventos para el evento de MapElementClick . Este evento se
desencadena cuando el usuario pulsa o hace clic en un MapElement en el MapControl y solo se cancela su
suscripción cuando cambia el elemento al que está adjunto el representador.
Cada marca en la colección de customPins se muestra en la ubicación geográfica correcta en el mapa como
sigue:
La ubicación para la marca se crea como una instancia de Geopoint .
Una instancia de MapIcon se crea para representar la marca.
La imagen utilizada para representar el MapIcon se especifica estableciendo la propiedad
MapIcon.Image . Con todo, no siempre se puede garantizar que se muestre la imagen del icono de mapa,
ya que puede estar ocultada por otros elementos del mapa. Por lo tanto, la propiedad
CollisionBehaviorDesired del icono del mapa se establece en
MapElementCollisionBehavior.RemainVisible , para asegurarse de que está visible.
La ubicación del MapIcon se especifica configurando la propiedad MapIcon.Location .
La propiedad MapIcon.NormalizedAnchorPoint se establece en la ubicación aproximada del puntero en la
imagen. Si esta propiedad conserva su valor predeterminado de (0,0), que representa la esquina
superior izquierda de la imagen, los cambios en el nivel de zoom del mapa pueden dar lugar a que la
imagen apunte a una ubicación distinta.
La instancia MapIcon se agrega a la colección MapControl.MapElements . Esto da como resultado que el
icono de mapa se muestre en el MapControl .
NOTE
Cuando se usa la misma imagen para varios iconos de mapa, la instancia de RandomAccessStreamReference debe
declararse en el nivel de página o aplicación para mejorar el rendimiento.
Mostrar el UserControl
El método OnMapElementClick se ejecuta cuando un usuario pulsa en el icono de mapa. El siguiente ejemplo de
código muestra este método:
if (customPin.Id.ToString() == "Xamarin")
{
if (mapOverlay == null)
{
mapOverlay = new XamarinMapOverlay(customPin);
}
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;
}
}
}
Este método crea una instancia de UserControl que muestra información sobre la marca. Esto se logra de la
siguiente manera:
Se recupera la instancia de MapIcon .
Se llama al método GetCustomPin para devolver los datos de marca personalizada que se mostrarán.
Se crea una instancia de XamarinMapOverlay para mostrar los datos de marca personalizada. Esta clase es un
control de usuario.
Se crea la ubicación geográfica en la que se mostrará la instancia de XamarinMapOverlay en el MapControl
como una instancia de Geopoint .
La instancia XamarinMapOverlay se agrega a la colección MapControl.Children . Esta colección contiene
elementos de interfaz de usuario de XAML que se mostrarán en el mapa.
La ubicación geográfica de la instancia de XamarinMapOverlay en el mapa se establece mediante una llamada al
método SetLocation .
La ubicación relativa de la instancia de XamarinMapOverlay que corresponde a la ubicación especificada se
establece mediante una llamada al método SetNormalizedAnchorPoint . Esto garantiza que los cambios en el
nivel de zoom del mapa tendrán como resultado que la instancia de XamarinMapOverlay siempre se muestre en
la ubicación correcta.
Como alternativa, si ya se muestra información sobre la marca en el mapa, pulsar en el mapa quita la instancia de
XamarinMapOverlay de la colección de MapControl.Children .
Este método abre un explorador web y navega a la dirección almacenada en la propiedad Url de la instancia de
CustomPin . Tenga en cuenta que la dirección se definió al crear la colección CustomPin en el proyecto de
biblioteca de .NET Standard.
Para obtener más información sobre cómo personalizar una instancia de MapControl , vea Introducción a
ubicación y mapas en MSDN.
Resumen
En este artículo se muestra cómo crear un representador personalizado para el control Map , lo que permite que
los desarrolladores reemplacen la representación nativa de forma predeterminada con su propia personalización
específica de la plataforma. Xamarin.Forms.Maps proporciona una abstracción multiplataforma para mostrar
mapas que usan la API de mapa nativo en cada plataforma y proporcionar una experiencia de mapa rápida y
familiar para los usuarios.
Vínculos relacionados
Xamarin.Forms Map (Mapa de Xamarin.Forms)
Maps in Xamarin.iOS (Mapas en Xamarin.iOS )
API de Maps
Customized Pin (sample) (Marca personalizada [ejemplo])
Resaltado de un área circular en un mapa
11/07/2019 • 10 minutes to read • Edit Online
Descargar el ejemplo
En este artículo se explica cómo agregar una superposición circular a un mapa, para resaltar un área circular del
mapa.
Información general
Una superposición es un gráfico superpuesto en una capa en un mapa. Las superposiciones admiten dibujar
contenido gráfico que se escala con el mapa a medida que se amplía. En las capturas de pantalla siguientes se
muestra el resultado de agregar una superposición circular a un mapa:
Cuando una aplicación de Xamarin.Forms representa un control Map , en iOS se crea la instancia de la clase
MapRenderer , que a su vez crea una instancia del control MKMapView nativo. En la plataforma de Android, la clase
MapRenderer crea una instancia de un control MapView nativo. En la Plataforma universal de Windows ( UWP ), la
clase MapRenderer crea una instancia de un elemento MapControl nativo. El proceso de representación se puede
aprovechar para implementar personalizaciones de mapa específicas de cada plataforma mediante la creación de
un representador personalizado para un elemento Map en cada plataforma. Para hacerlo, siga este procedimiento:
1. Cree un mapa personalizado de Xamarin.Forms.
2. Use el mapa personalizado desde Xamarin.Forms.
3. Personalice el mapa; para hacerlo, cree un representador personalizado para el mapa en cada plataforma.
NOTE
Xamarin.Forms.Maps debe inicializarse y configurarse antes de su uso. Para obtener más información, consulte
Maps Control
Para obtener información sobre cómo personalizar un mapa mediante un representador personalizado, consulte
Personalización de un anclado de mapa.
Creación del mapa personalizado
Cree una clase CustomCircle que tenga las propiedades Position y Radius :
A continuación, cree una subclase de la clase Map que agregue una propiedad de tipo CustomCircle :
<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>
También puede usar el control CustomMap mediante la declaración de una instancia de este en la instancia de la
página de C#:
customMap.Pins.Add (pin);
customMap.MoveToRegion (MapSpan.FromCenterAndRadius (position, Distance.FromMiles (1.0)));
}
}
Esta inicialización agrega instancias de Pin y CustomCircle al mapa personalizado y coloca la vista del mapa con
el método MoveToRegion , que cambia la posición y el nivel de zoom del mapa mediante la creación de un MapSpan
desde una Position y una Distance .
Personalizar el mapa
Ahora debe agregarse un representador personalizado a cada proyecto de aplicación para agregar la
superposición circular al mapa.
Creación del representador personalizado en iOS
Cree una subclase de la clase MapRenderer e invalide su método OnElementChanged para agregar la superposición
circular:
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace MapOverlay.iOS
{
public class CustomMapRenderer : MapRenderer
{
MKCircleRenderer circleRenderer;
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;
Este método realiza la configuración siguiente, siempre que el representador personalizado se adjunte a un
elemento de Xamarin.Forms nuevo:
La propiedad MKMapView.OverlayRenderer se establece en un delegado correspondiente.
Para crear el círculo, se debe establecer un objeto MKCircle estático que especifica el centro del círculo y su
radio en metros.
Para agregar el círculo al mapa, llame al método MKMapView.AddOverlay .
if (e.OldElement != null)
{
// Unsubscribe
}
if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
circle = formsMap.Circle;
Control.GetMapAsync(this);
}
}
NativeMap.AddCircle(circleOptions);
}
}
}
El método OnElementChanged llama al método MapView.GetMapAsync , que obtiene el GoogleMap subyacente asociado
a la vista, siempre que el representador personalizado se adjunte a un nuevo elemento de Xamarin.Forms. Una vez
la instancia de GoogleMap está disponible, se invoca el método OnMapReady , en que el círculo se crea mediante la
instancia de un objeto CircleOptions que especifica el centro del círculo y su radio en metros. A continuación, se
llama al método NativeMap.AddCircle para agregar el círculo al mapa.
Creación de un representador personalizado en la Plataforma universal de Windows
Cree una subclase de la clase MapRenderer e invalide su método OnElementChanged para agregar la superposición
circular:
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace MapOverlay.UWP
{
public class CustomMapRenderer : MapRenderer
{
const int EarthRadiusInMeteres = 6371000;
if (e.OldElement != null)
{
// Unsubscribe
}
if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
var nativeMap = Control as MapControl;
var circle = formsMap.Circle;
Este método realiza las operaciones siguientes, siempre que el representador personalizado se adjunte a un nuevo
elemento de Xamarin.Forms:
La posición del círculo y el radio se recuperan de la propiedad CustomMap.Circle y se pasan al método
GenerateCircleCoordinates , que genera las coordenadas de latitud y longitud para el perímetro del círculo. El
código para este método auxiliar se muestra a continuación.
Las coordenadas del perímetro del círculo se convierten en coordenadas de una List de BasicGeoposition .
El círculo se crea mediante la instancia de un objeto MapPolygon . La clase MapPolygon se utiliza para mostrar
una forma de varios puntos en el mapa; para ello, se establece su propiedad Path en un objeto Geopath que
contiene las coordenadas de la forma.
Para representar el polígono en el mapa, se agrega a la colección 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>();
return positions;
}
Resumen
En este artículo se explica cómo agregar una superposición circular a un mapa, para resaltar un área circular del
mapa.
Vínculos relacionados
Superposición de mapa circular (ejemplo)
Personalización de un anclado de mapa
Xamarin.Forms.Maps
Resaltado de una región en un mapa
11/07/2019 • 10 minutes to read • Edit Online
Descargar el ejemplo
En este artículo se explica cómo agregar una superposición de polígono a un mapa para resaltar una región del
mapa. Los polígonos son una forma cerrada y tienen relleno en su interior.
Información general
Una superposición es un gráfico superpuesto en una capa en un mapa. Las superposiciones permiten dibujar
contenido gráfico que se escala con el mapa al ampliarlo o reducirlo. En las capturas de pantalla siguientes, se
muestra el resultado de agregar una superposición de polígono a un mapa:
Cuando se representa un control Map mediante una aplicación de Xamarin.Forms, se crea una instancia de la clase
MapRenderer en iOS que, a su vez, crea una instancia de un control MKMapView nativo. En la plataforma de Android,
la clase MapRenderer crea una instancia de un control MapView nativo. En la Plataforma universal de Windows
(UWP ), la clase MapRenderer crea una instancia de un elemento MapControl nativo. El proceso de representación
se puede aprovechar para implementar personalizaciones de mapa específicas de cada plataforma mediante la
creación de un representador personalizado para un elemento Map en cada plataforma. Para hacerlo, siga este
procedimiento:
1. Cree un mapa personalizado de Xamarin.Forms.
2. Use el mapa personalizado desde Xamarin.Forms.
3. Personalice el mapa; para hacerlo, cree un representador personalizado para el mapa en cada plataforma.
NOTE
Xamarin.Forms.Maps tiene que inicializarse y configurarse antes de cada uso. Para obtener más información, vea
Maps Control .
Para obtener información sobre cómo personalizar un mapa mediante un representador personalizado, vea
Customizing a Map Pin (Personalizar un marcador de mapa).
Crear un mapa personalizado
Cree una subclase de la clase Map que agregue una propiedad ShapeCoordinates :
public CustomMap ()
{
ShapeCoordinates = new List<Position> ();
}
}
La propiedad ShapeCoordinates almacenará una colección de coordenadas que definen la región que se resaltará.
Usar el mapa personalizado
Para usar el control CustomMap , declare una instancia de este en la instancia de la página de 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>
También puede usar el control CustomMap mediante la declaración de una instancia de este en la instancia de la
página de C#:
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;
int index = 0;
foreach (var position in formsMap.ShapeCoordinates)
{
coords[index] = new CLLocationCoordinate2D(position.Latitude, position.Longitude);
index++;
}
Este método realiza la siguiente configuración, siempre que el representador personalizado esté asociado a un
nuevo elemento de Xamarin.Forms:
La propiedad MKMapView.OverlayRenderer se establece en un delegado correspondiente.
La colección de coordenadas de latitud y longitud se recupera desde la propiedad CustomMap.ShapeCoordinates y
se almacena como una matriz de instancias de CLLocationCoordinate2D .
Para crear el polígono, se realiza una llamada al método MKPolygon.FromCoordinates estático, que especifica la
latitud y longitud de cada punto.
El polígono se agrega al mapa mediante una llamada al método MKMapView.AddOverlay . Este método cierra
automáticamente el polígono dibujando una línea que conecta el primer y el último punto.
Después, se implementa el método GetOverlayRenderer para personalizar la representación de la superposición:
if (e.OldElement != null)
{
// Unsubscribe
}
if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
shapeCoordinates = formsMap.ShapeCoordinates;
Control.GetMapAsync(this);
}
}
if (e.OldElement != null)
{
// Unsubscribe
}
if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
var nativeMap = Control as MapControl;
Este método realiza las operaciones siguientes, siempre que el representador personalizado esté asociado a un
nuevo elemento de Xamarin.Forms:
La colección de coordenadas de latitud y longitud se recupera desde la propiedad CustomMap.ShapeCoordinates y
se convierte a un elemento List de coordenadas de BasicGeoposition .
El polígono se genera mediante la creación de una instancia de un objeto MapPolygon . La clase MapPolygon se
utiliza para mostrar una forma de varios puntos en el mapa; para ello, se establece su propiedad Path en un
objeto Geopath que contiene las coordenadas de la forma.
Para representar el polígono en el mapa, se agrega a la colección MapControl.MapElements . Tenga en cuenta que
el polígono se cerrará automáticamente dibujando una línea que conecta el primer y el último punto.
Resumen
En este artículo se explicó cómo agregar una superposición de polígono a un mapa para resaltar una región del
mapa. Los polígonos son una forma cerrada y tienen relleno en su interior.
Vínculos relacionados
Polygon Map Overlay (sample) (Superposición de mapa de polígono [ejemplo])
Personalización de un anclado de mapa
Xamarin.Forms.Maps
Resaltar una ruta en un mapa
11/07/2019 • 10 minutes to read • Edit Online
Descargar el ejemplo
En este artículo, se explica cómo agregar una superposición de polilínea a un mapa. Una superposición de
polilínea es una serie de segmentos de línea conectados que suelen usarse para mostrar una ruta en un mapa o
para componer cualquier forma necesaria.
Información general
Una superposición es un gráfico superpuesto en una capa en un mapa. Las superposiciones permiten dibujar
contenido gráfico que se escala con el mapa al ampliarlo o reducirlo. En las capturas de pantalla siguientes, se
muestra el resultado de agregar una superposición de polilínea a un mapa:
Cuando se representa un control Map mediante una aplicación de Xamarin.Forms, se crea una instancia de la clase
MapRenderer en iOS que, a su vez, crea una instancia de un control MKMapView nativo. En la plataforma de Android,
la clase MapRenderer crea una instancia de un control MapView nativo. En la Plataforma universal de Windows
(UWP ), la clase MapRenderer crea una instancia de un elemento MapControl nativo. El proceso de representación
se puede aprovechar para implementar personalizaciones de mapa específicas de cada plataforma mediante la
creación de un representador personalizado para un elemento Map en cada plataforma. Para hacerlo, siga este
procedimiento:
1. Cree un mapa personalizado de Xamarin.Forms.
2. Use el mapa personalizado desde Xamarin.Forms.
3. Personalice el mapa; para hacerlo, cree un representador personalizado para el mapa en cada plataforma.
NOTE
Xamarin.Forms.Maps tiene que inicializarse y configurarse antes de cada uso. Para obtener más información, vea
Maps Control .
Para obtener información sobre cómo personalizar un mapa mediante un representador personalizado, vea
Customizing a Map Pin (Personalizar un marcador de mapa).
Crear un mapa personalizado
Cree una subclase de la clase Map que agregue una propiedad RouteCoordinates :
public CustomMap ()
{
RouteCoordinates = new List<Position> ();
}
}
La propiedad RouteCoordinates almacenará una colección de coordenadas que definen la ruta que se resaltará.
Usar el mapa personalizado
Para usar el control CustomMap , declare una instancia de este en la instancia de la página de 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>
También puede usar el control CustomMap mediante la declaración de una instancia de este en la instancia de la
página de C#:
Esta inicialización especifica una serie de coordenadas de latitud y longitud para definir la ruta que se resaltará en
el mapa. Después, coloca la vista del mapa con el método MoveToRegion , que cambia la posición y el nivel de zoom
del mapa mediante la creación de un elemento MapSpan desde los elementos Position y Distance .
Personalizar el mapa
Ahora, es necesario agregar un representador personalizado a cada proyecto de aplicación para agregar la
superposición de polilínea al mapa.
Crear un representador personalizado en iOS
Cree una subclase de la clase MapRenderer y reemplace su método OnElementChanged para agregar la
superposición de polilínea:
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace MapOverlay.iOS
{
public class CustomMapRenderer : MapRenderer
{
MKPolylineRenderer polylineRenderer;
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;
Este método realiza la siguiente configuración, siempre que el representador personalizado esté asociado a un
nuevo elemento de Xamarin.Forms:
La propiedad MKMapView.OverlayRenderer se establece en un delegado correspondiente.
La colección de coordenadas de latitud y longitud se recupera desde la propiedad CustomMap.RouteCoordinates y
se almacena como una matriz de instancias de CLLocationCoordinate2D .
Para crear la polilínea, se realiza una llamada al método MKPolyline.FromCoordinates estático, que especifica la
latitud y longitud de cada punto.
La polilínea se agrega al mapa mediante una llamada al método MKMapView.AddOverlay .
if (e.OldElement != null)
{
// Unsubscribe
}
if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
routeCoordinates = formsMap.RouteCoordinates;
Control.GetMapAsync(this);
}
}
NativeMap.AddPolyline(polylineOptions);
}
}
}
if (e.OldElement != null)
{
// Unsubscribe
}
if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
var nativeMap = Control as MapControl;
Este método realiza las operaciones siguientes, siempre que el representador personalizado esté asociado a un
nuevo elemento de Xamarin.Forms:
La colección de coordenadas de latitud y longitud se recupera desde la propiedad CustomMap.RouteCoordinates y
se convierte a un elemento List de coordenadas de BasicGeoposition .
La polilínea se genera mediante la creación de una instancia de un objeto MapPolyline . La clase MapPolygon se
usa para mostrar una línea en el mapa mediante el ajuste de su propiedad Path en un objeto Geopath que
contiene las coordenadas de línea.
Para representar la polilínea en el mapa, se agrega a la colección MapControl.MapElements .
Resumen
En este artículo, se ha explicado cómo agregar una superposición de polilínea a un mapa para mostrar una ruta en
un mapa o para componer cualquier forma necesaria.
Vínculos relacionados
Superposición de mapa de polilínea (ejemplo)
Personalización de un anclado de mapa
Xamarin.Forms.Maps
Personalización de una ListView
11/07/2019 • 28 minutes to read • Edit Online
Descargar el ejemplo
Una ListView de Xamarin.Forms es una vista que muestra una colección de datos como una lista vertical. En este
artículo se muestra cómo crear un representador personalizado que encapsula los controles de lista específica de
la plataforma y los diseños de celda nativa, lo que permite tener más control sobre el rendimiento del control de
lista nativa.
Todas las vistas de Xamarin.Forms tienen un representador adjunto para cada plataforma que crea una instancia
de un control nativo. Cuando una aplicación de Xamarin.Forms representa una ListView , en iOS se crea la
instancia de la clase ListViewRenderer , que a su vez crea una instancia del control UITableView nativo. En la
plataforma de Android, la clase ListViewRenderer crea una instancia de un control ListView nativo. En
Plataforma universal de Windows (UWP ), la clase ListViewRenderer crea una instancia de un control ListView
nativo. Para obtener más información sobre el representador y las clases de control nativo a las que se asignan los
controles de Xamarin.Forms, vea Renderer Base Classes and Native Controls (Clases base y controles nativos del
representador).
El siguiente diagrama muestra la relación entre el control ListView y los controles nativos correspondientes que
lo implementan:
El NativeListView se crea en el proyecto de biblioteca de .NET Standard y define la API para el control
personalizado. Este control expone una propiedad Items que se usa para rellenar el ListView con los datos y que
puede enlazarse a datos para fines de presentación. También expone un evento ItemSelected que se desencadena
cada vez que se selecciona un elemento en un control de lista nativo específico de la plataforma. Para más
información sobre el enlace de datos, consulte Data Binding Basics (Aspectos básicos del enlace de datos).
<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>
El prefijo de espacio de nombres local puede tener cualquier nombre. Pero los valores clr-namespace y
assembly deben coincidir con los detalles del control personalizado. Una vez que se declara el espacio de
nombres, el prefijo se usa para hacer referencia al control personalizado.
El siguiente ejemplo de código muestra cómo se puede usar el control personalizado NativeListView en una
página 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;
}
NOTE
Dado que el control personalizado NativeListView se representa mediante controles de lista específicos de la plataforma
que incluyen capacidad de desplazamiento, el control personalizado no debe hospedarse en los controles de diseño
desplazable, como ScrollView .
Ahora se puede agregar un representador personalizado a cada proyecto de aplicación para crear controles de
lista específicos de la plataforma y diseños de celda nativos.
NOTE
Proporcionar un representador personalizado en cada proyecto de la plataforma es un paso opcional. Si no hay un
representador personalizado registrado, se usa el representador predeterminado de la clase base de la celda.
El siguiente diagrama muestra las responsabilidades de cada proyecto de la aplicación de ejemplo, junto con las
relaciones entre ellos:
La clase ListViewRenderer expone el método OnElementChanged , al que se llama cuando se crea el control
personalizado de Xamarin.Forms para representar el control nativo correspondiente. Este método toma un
parámetro ElementChangedEventArgs que contiene propiedades OldElement y NewElement . Estas propiedades
representan al elemento de Xamarin.Forms al que estaba asociado el representador y al elemento de
Xamarin.Forms al que está asociado el representador, respectivamente. En la aplicación de ejemplo, la propiedad
OldElement es null y la propiedad NewElement contiene una referencia a la instancia de NativeListView .
El lugar para realizar la personalización de controles nativos es una versión reemplazada del método
OnElementChanged en cada clase de representador específica de la plataforma. Una referencia con tipo para el
control nativo que se usa en la plataforma puede obtenerse a través de la propiedad Control . Además, se puede
obtener una referencia al control de Xamarin.Forms que se representa mediante la propiedad Element .
Debe tener cuidado al suscribirse a los controladores de eventos en el método OnElementChanged , como se
muestra en el siguiente ejemplo de código:
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
}
}
Solo se debe configurar el control nativo y suscribir a los controladores de eventos cuando se adjunta el
representador personalizado a un nuevo elemento de Xamarin.Forms. De forma similar, solo se debe cancelar la
suscripción de los controladores de eventos que se han suscrito cuando cambia el elemento al que está asociado
el representador. Adoptar este enfoque facilita crear un representador personalizado que no sufra pérdidas de
memoria.
Una versión invalidada del método OnElementPropertyChanged , en cada clase de representador específico de la
plataforma, es el lugar para responder a los cambios de propiedad enlazable en el control personalizado de
Xamarin.Forms. Siempre se debe realizar una comprobación de la propiedad que ha modificado, ya que esta
invalidación se puede llamar varias veces.
Cada clase de representador personalizado se decora con un atributo ExportRenderer que registra el
representador con Xamarin.Forms. El atributo toma dos parámetros: el nombre de tipo del control personalizado
de Xamarin.Forms que se va a representar y el nombre de tipo del representador personalizado. El prefijo
assembly para el atributo especifica que el atributo se aplica a todo el ensamblado.
En las secciones siguientes se describe la implementación de cada clase de representador personalizado específico
de plataforma.
Creación del representador personalizado en iOS
El siguiente ejemplo de código muestra el representador personalizado para la 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);
}
}
}
}
El control UITableView se configura creando una instancia de la clase NativeiOSListViewSource , siempre que se
adjunte el representador personalizado a un nuevo elemento de Xamarin.Forms. Esta clase proporciona datos
para el control UITableView invalidando los métodos RowsInSection y GetCell desde la clase UITableViewSource
y exponiendo una propiedad Items que contiene la lista de datos que se mostrarán. La clase también proporciona
una invalidación del método RowSelected que invoca el evento ItemSelected proporcionado por el control
personalizado NativeListView . Para obtener más información sobre las invalidaciones de método, vea
Subclassing UITableViewSource (Creación de subclases de UITableViewSource). El método GetCell devuelve un
UITableCellView que se rellena con datos para cada fila de la lista y se muestra en el siguiente ejemplo de código:
return cell;
}
Este método crea una instancia de NativeiOSListViewCell para cada fila de datos que se mostrará en la pantalla.
La instancia de NativeiOSCell define el diseño de cada celda y los datos de la celda. Cuando una celda
desaparezca de la pantalla debido al desplazamiento, la celda estará disponible para su reutilización. Esto evita
desperdiciar memoria garantizando que solo hay instancias de NativeiOSCell para los datos que se muestran en
la pantalla, en lugar de todos los datos en la lista. Para obtener más información sobre la reutilización de celdas,
vea Cell Reuse (Reutilización de celdas). El método GetCell también lee la propiedad ImageFilename de cada fila
de datos, siempre que exista, y lee la imagen y la almacena como una instancia de UIImage antes de actualizar la
instancia de NativeiOSListViewCell con los datos (nombre, categoría e imagen) de la fila.
La clase NativeiOSListViewCell define el diseño de cada celda y se muestra en el siguiente ejemplo de código:
ContentView.Add (headingLabel);
ContentView.Add (subheadingLabel);
ContentView.Add (imageView);
}
Esta clase define los controles utilizados para representar el contenido de la celda y su diseño. El constructor
NativeiOSListViewCell crea instancias de controles de UILabel y UIImageView e inicializa su apariencia. Estos
controles se usan para mostrar datos de cada fila, y el método UpdateCell se usa para establecer estos datos en
las instancias de UILabel y UIImageView . El método LayoutSubviews invalidado establece la ubicación de estas
instancias especificando sus coordenadas dentro de la celda.
Responde a un cambio de propiedad en el control personalizado
Si la propiedad NativeListView.Items cambia debido a elementos que se agregan o se quitan de la lista, el
representador personalizado debe responder mostrando los cambios. Esto puede realizarse invalidando el método
OnElementPropertyChanged , que se muestra en el siguiente ejemplo de código:
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);
}
}
El método crea una nueva instancia de la clase NativeiOSListViewSource que proporciona datos para el control
UITableView , siempre que la propiedad enlazable NativeListView.Items haya cambiado.
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;
}
}
...
El control nativo ListView se configura siempre que el representador personalizado esté asociado a un nuevo
elemento de Xamarin.Forms. Esta configuración implica la creación de una instancia de la clase
NativeAndroidListViewAdapter que proporciona datos al control ListView nativo y el registro de un controlador
de eventos para procesar el evento ItemClick . A su vez, este controlador invocará el evento ItemSelected
proporcionado por el control personalizado NativeListView . Se cancela la suscripción del evento ItemClick solo
si cambia el representador al que está adjunto el elemento de Xamarin.Forms.
El NativeAndroidListViewAdapter deriva de la clase BaseAdapter y expone una propiedad Items que contiene la
lista de datos que se mostrarán, además de invalidar los métodos Count , GetView , GetItemId y this[int] . Para
obtener más información sobre estas invalidaciones de método, vea Implementing a ListAdapter (Implementación
de un ListAdapter). El método GetView devuelve una vista para cada fila, que se rellena con datos y se muestra en
el siguiente ejemplo de código:
public override View GetView (int position, View convertView, ViewGroup parent)
{
var item = tableItems [position];
return view;
}
Se llama al método GetView para devolver la celda que se va a representar, como una View , para cada fila de
datos en la lista. Crea una instancia de View para cada fila de datos que se mostrará en la pantalla, con la
apariencia de la instancia de View que se define en un archivo de diseño. Cuando una celda desaparezca de la
pantalla debido al desplazamiento, la celda estará disponible para su reutilización. Esto evita desperdiciar memoria
garantizando que solo hay instancias de View para los datos que se muestran en la pantalla, en lugar de todos los
datos en la lista. Para obtener más información sobre la reutilización de vistas, vea Row View Re-use (Reutilización
de vistas de fila).
El método GetView también rellena la instancia View con datos, incluyendo la lectura de los datos de imagen del
nombre de archivo especificado en la propiedad ImageFilename .
El diseño de cada celda mostrada por el ListView nativo se define en el archivo de diseño
NativeAndroidListViewCell.axml , que aumenta el método LayoutInflater.Inflate . En el siguiente ejemplo de
código se muestra la definición del diseño:
<?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>
Este diseño especifica que dos controles de TextView y un control de ImageView se usan para mostrar el
contenido de la celda. Los dos controles de TextView están orientados verticalmente dentro de un control de
LinearLayout , con todos los controles contenidos en un RelativeLayout .
if (e.PropertyName == NativeListView.ItemsProperty.PropertyName) {
Control.Adapter = new NativeAndroidListViewAdapter (_context as Android.App.Activity, Element as
NativeListView);
}
}
El método crea una nueva instancia de la clase NativeAndroidListViewAdapter que proporciona datos para el
control ListView nativo, siempre que el la propiedad enlazable NativeListView.Items haya cambiado.
Creación del representador personalizado en UWP
En el siguiente ejemplo de código se muestra el representador personalizado para UWP:
[assembly: ExportRenderer(typeof(NativeListView), typeof(NativeUWPListViewRenderer))]
namespace CustomRenderer.UWP
{
public class NativeUWPListViewRenderer : ListViewRenderer
{
ListView 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;
}
}
El control nativo ListView se configura siempre que el representador personalizado esté asociado a un nuevo
elemento de Xamarin.Forms. Esta configuración implica configurar el modo en que el control ListView nativo
responderá a los elementos seleccionados, rellenar los datos mostrados por el control, definir la apariencia y el
contenido de cada celda y registrar un controlador de eventos para procesar el evento SelectionChanged . A su vez,
este controlador invocará el evento ItemSelected proporcionado por el control personalizado NativeListView . Se
cancela la suscripción del evento SelectionChanged solo si cambia el representador al que está adjunto el
elemento de Xamarin.Forms.
La apariencia y el contenido de cada celda ListView nativa se definen mediante un DataTemplate denominado
ListViewItemTemplate . Este DataTemplate se almacena en el diccionario de recursos de nivel de aplicación y se
muestra en el siguiente ejemplo de código:
<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>
El DataTemplate especifica los controles utilizados para mostrar el contenido de la celda y su diseño y apariencia.
Dos controles de TextBlock y un control de Image se usan para mostrar el contenido de la celda mediante el
enlace de datos. Además, una instancia de ConcatImageExtensionConverter se utiliza para concatenar la extensión
de archivo .jpg para cada nombre de archivo de imagen. Esto garantiza que el control Image puede cargar y
representar la imagen cuando se establece su propiedad Source .
Responde a un cambio de propiedad en el control personalizado
Si la propiedad NativeListView.Items cambia debido a elementos que se agregan o se quitan de la lista, el
representador personalizado debe responder mostrando los cambios. Esto puede realizarse invalidando el método
OnElementPropertyChanged , que se muestra en el siguiente ejemplo de código:
if (e.PropertyName == NativeListView.ItemsProperty.PropertyName)
{
listView.ItemsSource = ((NativeListView)Element).Items;
}
}
El método rellena el control ListView nativo con los datos modificados, siempre que la propiedad
NativeListView.Items enlazable haya cambiado.
Resumen
En este artículo se mostró cómo crear un representador personalizado que encapsula los controles de lista
específica de la plataforma y los diseños de celda nativa, lo que permite tener más control sobre el rendimiento del
control de lista nativa.
Vínculos relacionados
CustomRendererListView (sample) (CustomRendererListView [ejemplo])
Personalización de ViewCell
11/07/2019 • 26 minutes to read • Edit Online
Descargar el ejemplo
Un ViewCell de Xamarin.Forms es una celda que se puede agregar a ListView o TableView y que contiene una
vista definida por el desarrollador. En este artículo se muestra cómo crear un representador personalizado para
un ViewCell que se hospeda dentro de un control ListView de Xamarin.Forms. Esto impide que se llame varias
veces a los cálculos de diseño de Xamarin.Forms durante el desplazamiento de ListView.
Todos las celdas de Xamarin.Forms tienen un representador que las acompaña para cada plataforma y que crea
una instancia de un control nativo. Cuando una aplicación de Xamarin.Forms representa una ViewCell , en iOS se
crea la instancia de la clase ViewCellRenderer , que a su vez crea una instancia del control UITableViewCell nativo.
En la plataforma Android, la clase ViewCellRenderer crea una instancia del control View nativo. En la Plataforma
Universal de Windows (UWP ), la clase ViewCellRenderer crea una instancia de DataTemplate nativa. Para obtener
más información sobre las clases de control nativo que se asignan a los controles de Xamarin.Forms y el
representador, vea Renderer Base Classes and Native Controls (Controles nativos y clases base del
representador).
El siguiente diagrama ilustra la relación entre la ViewCell y los controles nativos correspondientes que la
implementan:
La clase NativeCell se crea en el proyecto de biblioteca de .NET Standard y define la API para la celda
personalizada. La celda personalizada expone las propiedades Name , Category y ImageFilename que se pueden
mostrar mediante el enlace de datos. Para más información sobre el enlace de datos, consulte Data Binding Basics
(Aspectos básicos del enlace de datos).
<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>
El prefijo del espacio de nombres local puede tener cualquier nombre. Empero, los valores clr-namespace y
assembly deben coincidir con los detalles del control personalizado. Una vez que se declare el espacio de
nombres, el prefijo se utiliza para hacer referencia a la celda personalizada.
El siguiente ejemplo de código muestra cómo una página de C# puede consumir la celda personalizada
NativeCell :
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;
}
Un control ListView de Xamarin.Forms se usa para mostrar una lista de los datos, que se rellena mediante la
propiedad ItemSource . La estrategia de almacenamiento en caché RecycleElement intenta minimizar la velocidad
de ejecución y el consumo de memoria de ListView mediante el reciclaje de las celdas de la lista. Para obtener
más información, vea Estrategia de almacenamiento en caché.
Cada fila de la lista contiene tres elementos de datos: un nombre, una categoría y un nombre de archivo de
imagen. El diseño de cada fila de la lista está definido por el DataTemplate al que se hace referencia mediante la
propiedad enlazable ListView.ItemTemplate . DataTemplate define que cada fila de datos en la lista será una
NativeCell que muestra sus propiedades Name , Category y ImageFilename mediante el enlace de datos. Para
obtener más información sobre el control ListView , vea ListView de Xamarin.Forms.
Ahora se puede agregar un representador personalizado a cada proyecto de aplicación para personalizar el
diseño específico de la plataforma para cada celda.
Creación del representador personalizado en cada plataforma
El proceso de creación de la clase de representador personalizada es el siguiente:
1. Cree una subclase de la clase ViewCellRenderer que represente la celda personalizada.
2. Invalide el método específico de la plataforma que representa la celda personalizada y escriba una lógica para
personalizarla.
3. Agregue un atributo ExportRenderer a la clase de representador personalizada para especificar que se utilizará
para representar la celda personalizada de Xamarin.Forms. Este atributo se usa para registrar al representador
personalizado con Xamarin.Forms.
NOTE
Para la mayoría de los elementos de Xamarin.Forms, proporcionar un representador personalizado en cada proyecto de la
plataforma es un paso opcional. Si no se registra un representador personalizado, se usará el representador predeterminado
de la clase base del control. Con todo, los representadores personalizados son necesarios en cada proyecto de la plataforma
al representar un elemento ViewCell.
El siguiente diagrama ilustra las responsabilidades de cada proyecto en la aplicación de ejemplo, junto con las
relaciones entre ellos:
Las clases del representador específico de la plataforma, que se derivan de la clase ViewCellRenderer para cada
plataforma, representan la celda personalizada NativeCell . Esto da como resultado que cada celda personalizada
NativeCell se represente con diseño específico de la plataforma, como se muestra en las siguientes capturas de
pantalla:
La clase ViewCellRenderer expone métodos específicos de la plataforma para representar la celda personalizada.
Estos son el método GetCell en la plataforma iOS, el método GetCellCore en la plataforma Android y el método
GetTemplate en UWP.
Cada clase de presentador personalizado se decora con un atributo ExportRenderer que registra el representador
con Xamarin.Forms. El atributo toma dos parámetros: el nombre de tipo de la celda de Xamarin.Forms que se
representa y el nombre de tipo del representador personalizado. El prefijo assembly para el atributo especifica
que el atributo se aplica a todo el ensamblado.
En las secciones siguientes se describe la implementación de cada clase de representador personalizado
específico de plataforma.
Creación del representador personalizado en iOS
El siguiente ejemplo de código muestra el representador personalizado para la plataforma de iOS:
nativeCell.PropertyChanged += OnNativeCellPropertyChanged;
cell.UpdateCell(nativeCell);
return cell;
}
...
}
}
Se llama al método GetCell para crear cada celda que se mostrará. Cada celda es una instancia de
NativeiOSCell que define el diseño de la celda y sus datos. La operación del método GetCell depende de la
estrategia de almacenamiento en caché ListView :
Cuando la estrategia de almacenamiento en caché ListView sea RetainElement , se invocará el método
GetCell para cada celda. Se creará una instancia de NativeiOSCell para cada instancia de NativeCell que
se muestre inicialmente en la pantalla. Cuando el usuario se desplace a través de la ListView , se volverán
a usar las instancias de NativeiOSCell . Para obtener más información sobre la reutilización de celdas de
iOS, vea Reutilización de celda.
NOTE
Este código de representador personalizado llevará a cabo cierta reutilización de celda cuando la ListView se
establezca para conservar las celdas.
El método UpdateCell actualizará los datos mostrados por cada instancia de NativeiOSCell , ya sean recién
creados o se vuelvan a utilizar, con los datos de cada instancia de NativeCell .
NOTE
El método OnNativeCellPropertyChanged nunca se invocará cuando la estrategia de almacenamiento en caché
ListView se establezca para conservar las celdas.
El siguiente ejemplo de código muestra el método OnNativeCellPropertyChanged que se invoca cuando se provoca
un evento PropertyChanged :
namespace CustomRenderer.iOS
{
public class NativeiOSCellRenderer : ViewCellRenderer
{
...
Este método actualiza los datos que muestran las instancias de NativeiOSCell reutilizadas. Se realiza una
comprobación para la propiedad que se ha modificado, ya que el método puede llamarse varias veces.
La clase NativeiOSCell define el diseño de cada celda y se muestra en el siguiente ejemplo de código:
internal class NativeiOSCell : UITableViewCell, INativeElementView
{
public UILabel HeadingLabel { get; set; }
public UILabel SubheadingLabel { get; set; }
public UIImageView CellImageView { get; set; }
SelectionStyle = UITableViewCellSelectionStyle.Gray;
ContentView.BackgroundColor = UIColor.FromRGB(255, 255, 224);
CellImageView = new UIImageView();
ContentView.Add(HeadingLabel);
ContentView.Add(SubheadingLabel);
ContentView.Add(CellImageView);
}
Esta clase define los controles utilizados para representar el contenido de la celda y su diseño. La clase
implementa la interfaz INativeElementView , que es necesaria cuando ListView usa estrategia de almacenamiento
en caché RecycleElement . Esta interfaz especifica que la clase debe implementar la propiedad Element , que debe
devolver los datos de celda personalizada para las celdas recicladas.
El constructor NativeiOSCell inicializa la apariencia de las propiedades HeadingLabel , SubheadingLabel y
CellImageView . Estas propiedades se utilizan para mostrar los datos almacenados en la instancia NativeCell ,
siendo llamado el método UpdateCell para establecer el valor de cada propiedad. Además, cuando ListView usa
la estrategia de almacenamiento en caché RecycleElement , el método OnNativeCellPropertyChanged puede
actualizar los datos mostrados por las propiedades HeadingLabel , SubheadingLabel y CellImageView en el
representador personalizado.
El diseño de la celda se realiza mediante la invalidación de LayoutSubviews , que establece las coordenadas de
HeadingLabel , SubheadingLabel y CellImageView dentro de la celda.
nativeCell.PropertyChanged += OnNativeCellPropertyChanged;
cell.UpdateCell(nativeCell);
return cell;
}
...
}
}
Se llama al método para crear cada celda que se mostrará. Cada celda es una instancia de
GetCellCore
NativeAndroidCell que define el diseño de la celda y sus datos. La operación del método GetCellCore depende
de la estrategia de almacenamiento en caché ListView :
Cuando la estrategia de almacenamiento en caché ListView sea RetainElement , se invocará el método
GetCellCore para cada celda. Se creará una NativeAndroidCell para cada instancia de NativeCell que se
muestre inicialmente en la pantalla. Cuando el usuario se desplace a través de la ListView , se volverán a
usar las instancias de NativeAndroidCell . Para obtener más información sobre la reutilización de celdas en
Android, vea Reutilización de vista fila.
NOTE
Tenga en cuenta que este código de representador personalizado llevará a cabo cierta reutilización de celda cuando
la ListView se establezca para conservar las celdas.
El método UpdateCell actualizará los datos mostrados por cada instancia de NativeAndroidCell , ya sean
recién creados o se vuelvan a utilizar, con los datos de cada instancia de NativeCell .
NOTE
Tenga en cuenta que el método OnNativeCellPropertyChanged se invocará cuando ListView se configure para
conservar las celdas, pero no se actualizarán los valores de propiedad de NativeAndroidCell .
namespace CustomRenderer.Droid
{
public class NativeAndroidCellRenderer : ViewCellRenderer
{
...
Este método actualiza los datos que muestran las instancias de NativeAndroidCell reutilizadas. Se realiza una
comprobación para la propiedad que se ha modificado, ya que el método puede llamarse varias veces.
La clase NativeAndroidCell define el diseño de cada celda y se muestra en el siguiente ejemplo de código:
internal class NativeAndroidCell : LinearLayout, INativeElementView
{
public TextView HeadingTextView { get; set; }
public TextView SubheadingTextView { get; set; }
public ImageView ImageView { get; set; }
AddView(view);
}
SetImage(cell.ImageFilename);
}
Este diseño especifica que dos controles de TextView y un control de ImageView se usan para mostrar el
contenido de la celda. Los dos controles de TextView están orientados verticalmente dentro de un control de
LinearLayout , con todos los controles contenidos en un RelativeLayout .
Se llama al método GetTemplate para devolver la celda que se va a representar para cada fila de datos en la lista.
Crea un DataTemplate para cada instancia de NativeCell que se mostrará en la pantalla, con el DataTemplate
definiendo la apariencia y el contenido de la celda.
DataTemplate se almacena en el diccionario de recursos de nivel de aplicación y se muestra en el siguiente
ejemplo de código:
<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>
DataTemplate especifica los controles utilizados para mostrar el contenido de la celda y su diseño y apariencia.
Dos controles de TextBlock y un control de Image se usan para mostrar el contenido de la celda mediante el
enlace de datos. Además, una instancia de ConcatImageExtensionConverter se utiliza para concatenar la extensión
de archivo .jpg para cada nombre de archivo de imagen. Esto garantiza que el control Image puede cargar y
representar la imagen cuando se establece su propiedad Source .
Resumen
En este artículo se mostró cómo crear un representador personalizado para un ViewCell que se hospeda dentro
de un control ListView de Xamarin.Forms. Esto impide que se llame varias veces a los cálculos de diseño de
Xamarin.Forms durante el desplazamiento de ListView .
Vínculos relacionados
Rendimiento de ListView
CustomRendererViewCell (sample) (CustomRendererViewCell [ejemplo])
Implementación de una vista
11/07/2019 • 18 minutes to read • Edit Online
Descargar el ejemplo
Los controles de interfaz de usuario personalizados de Xamarin.Forms deben derivar de la clase View, que se usa
para colocar diseños y controles en la pantalla. En este artículo se muestra cómo crear un representador
personalizado para un control personalizado de Xamarin.Forms que se usa para mostrar una secuencia de vídeo
de vista previa de la cámara del dispositivo.
Todas las vistas de Xamarin.Forms tienen un representador adjunto para cada plataforma que crea una instancia
de un control nativo. Cuando una aplicación de Xamarin.Forms representa una View en iOS se crea la instancia de
la clase ViewRenderer , que a su vez crea una instancia del control UIView nativo. En la plataforma de Android, la
clase ViewRenderer crea una instancia de un control View nativo. En Plataforma universal de Windows (UWP ), la
clase ViewRenderer crea una instancia de un control FrameworkElement nativo. Para obtener más información sobre
el representador y las clases de control nativo a las que se asignan los controles de Xamarin.Forms, vea Renderer
Base Classes and Native Controls (Clases base y controles nativos del representador).
El siguiente diagrama muestra la relación entre la clase View y los controles nativos correspondientes que la
implementan:
El proceso de representación puede usarse para implementar personalizaciones específicas de plataforma al crear
un representador personalizado para una clase View en cada plataforma. Para hacerlo, siga este procedimiento:
1. Cree un control personalizado de Xamarin.Forms.
2. Use el control personalizado de Xamarin.Forms.
3. Cree el representador personalizado para el control en cada plataforma.
Ahora se analizará en detalle cada elemento, para implementar un representador CameraPreview que muestre una
secuencia de vídeo de vista previa de la cámara del dispositivo. Pulsar en la secuencia de vídeo la detendrá e
iniciará.
El control personalizado CameraPreview se crea en el proyecto de biblioteca de .NET Standard y define la API del
control. El control personalizado expone una propiedad Camera que se usa para controlar si se debe mostrar la
secuencia de vídeo desde la cámara delantera o trasera del dispositivo. Si no se especifica un valor para la
propiedad Camera cuando se crea el control, el valor predeterminado es especificar la cámara trasera.
<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>
El prefijo de espacio de nombres local puede tener cualquier nombre. Pero los valores clr-namespace y
assembly deben coincidir con los detalles del control personalizado. Una vez que se declara el espacio de nombres,
el prefijo se usa para hacer referencia al control personalizado.
El siguiente ejemplo de código muestra cómo se puede usar el control personalizado CameraPreview en una página
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
}
}
};
}
}
Se usará una instancia del control personalizado CameraPreview para mostrar la secuencia de vídeo de vista previa
de la cámara del dispositivo. Aparte de especificar opcionalmente un valor para la propiedad Camera , la
personalización del control se llevará a cabo en el representador personalizado.
Ahora se puede agregar un representador personalizado a cada proyecto de aplicación para crear controles de
vista previa de cámara específicos de la plataforma.
NOTE
Para la mayoría de los elementos de Xamarin.Forms, proporcionar un representador personalizado en cada proyecto de la
plataforma es un paso opcional. Si no hay un representador personalizado registrado, se usa el representador
predeterminado de la clase base del control. Pero los representadores personalizados son necesarios en cada proyecto de
plataforma al representar un elemento View.
El siguiente diagrama muestra las responsabilidades de cada proyecto de la aplicación de ejemplo, junto con las
relaciones entre ellos:
El control personalizado CameraPreview se representa mediante clases de representador específicas de la
plataforma, que se derivan de la clase ViewRenderer de cada plataforma. Esto da lugar a que cada control
personalizado CameraPreview se represente con controles específicos de la plataforma, como se muestra en las
capturas de pantalla siguientes:
La clase ViewRenderer expone el método OnElementChanged , al que se llama cuando se crea el control
personalizado de Xamarin.Forms para representar el control nativo correspondiente. Este método toma un
parámetro ElementChangedEventArgs que contiene propiedades OldElement y NewElement . Estas propiedades
representan al elemento de Xamarin.Forms al que estaba asociado el representador y al elemento de
Xamarin.Forms al que está asociado el representador, respectivamente. En la aplicación de ejemplo, la propiedad
OldElement es null y la propiedad NewElement contiene una referencia a la instancia de CameraPreview .
Una versión invalidada del método OnElementChanged , en cada clase de representador específica de la plataforma,
es el lugar en el que realizar la personalización y la creación de instancias del control nativo. Se debe usar el
método SetNativeControl para crear instancias del control nativo; además, este método también asigna la
referencia del control a la propiedad Control . Además, se puede obtener una referencia al control de
Xamarin.Forms que se representa mediante la propiedad Element .
En algunas circunstancias, se puede llamar al método OnElementChanged varias veces. Por lo tanto, para evitar
pérdidas de memoria, se debe tener cuidado a la hora de crear instancias de un nuevo control nativo. El enfoque
que usar al crear instancias de un nuevo control nativo en un presentador personalizado se muestra en el ejemplo
de código siguiente:
protected override void OnElementChanged (ElementChangedEventArgs<NativeListView> e)
{
base.OnElementChanged (e);
if (e.OldElement != null) {
// Unsubscribe from event handlers and cleanup any resources
}
if (e.NewElement != null) {
if (Control == null) {
// Instantiate the native control and assign it to the Control property with
// the SetNativeControl method
}
// Configure the control and subscribe to event handlers
}
}
Solo se debe crear una instancia de un nuevo control nativo una vez, cuando la propiedad Control es null .
Además, solo se debe crear, configurar el control y suscribir los controladores de eventos cuando se adjunta el
presentador personalizado a un nuevo elemento de Xamarin.Forms. De forma similar, solo se debe cancelar la
suscripción de los controladores de eventos que se han suscrito cuando cambia el elemento al que está asociado el
representador. La adopción de este enfoque ayuda a crear un representador personalizado eficaz que no sufra
pérdidas de memoria.
IMPORTANT
El método SetNativeControl solo se debe llamar si e.NewElement no es null .
Cada clase de representador personalizado se decora con un atributo ExportRenderer que registra el
representador con Xamarin.Forms. El atributo toma dos parámetros: el nombre de tipo del control personalizado
de Xamarin.Forms que se va a representar y el nombre de tipo del representador personalizado. El prefijo
assembly para el atributo especifica que el atributo se aplica a todo el ensamblado.
En las secciones siguientes se describe la implementación de cada clase de representador personalizado específico
de plataforma.
Creación del representador personalizado en iOS
El siguiente ejemplo de código muestra el representador personalizado para la plataforma iOS:
[assembly: ExportRenderer (typeof(CameraPreview), typeof(CameraPreviewRenderer))]
namespace CustomRenderer.iOS
{
public class CameraPreviewRenderer : ViewRenderer<CameraPreview, UICameraPreview>
{
UICameraPreview uiCameraPreview;
if (e.OldElement != null) {
// Unsubscribe
uiCameraPreview.Tapped -= OnCameraPreviewTapped;
}
if (e.NewElement != null) {
if (Control == null) {
uiCameraPreview = new UICameraPreview (e.NewElement.Camera);
SetNativeControl (uiCameraPreview);
}
// Subscribe
uiCameraPreview.Tapped += OnCameraPreviewTapped;
}
}
Siempre que la propiedad Control sea null , se llama al método SetNativeControl para crear instancias de un
nuevo control UICameraPreview y asignar una referencia a él para la propiedad Control . El control
UICameraPreview es un control personalizado específico de la plataforma que utiliza las API de AVCapture para
proporcionar la secuencia de vista previa de la cámara. Expone un evento Tapped que controla el método
OnCameraPreviewTapped para detener e iniciar la vista previa de vídeo cuando se pulsa. Se establece una suscripción
al evento Tapped cuando el representador personalizado se adjunta a un nuevo elemento de Xamarin.Forms y
solo se cancela la suscripción cuando el elemento al que está adjunto el representador cambia.
Creación del representador personalizado en Android
En el ejemplo de código siguiente se muestra el representador personalizado para la plataforma Android:
[assembly: ExportRenderer(typeof(CustomRenderer.CameraPreview), typeof(CameraPreviewRenderer))]
namespace CustomRenderer.Droid
{
public class CameraPreviewRenderer : ViewRenderer<CustomRenderer.CameraPreview,
CustomRenderer.Droid.CameraPreview>
{
CameraPreview cameraPreview;
if (e.OldElement != null)
{
// Unsubscribe
cameraPreview.Click -= OnCameraPreviewClicked;
}
if (e.NewElement != null)
{
if (Control == null)
{
cameraPreview = new CameraPreview(Context);
SetNativeControl(cameraPreview);
}
Control.Preview = Camera.Open((int)e.NewElement.Camera);
// Subscribe
cameraPreview.Click += OnCameraPreviewClicked;
}
}
Siempre que la propiedad Control sea null , se llama al método SetNativeControl para crear instancias de un
nuevo control CameraPreview y asignar una referencia a él para la propiedad Control . El control CameraPreview es
un control personalizado específico de la plataforma que utiliza la API de Camera para proporcionar la secuencia
de vista previa de la cámara. Después, el control CameraPreview se configura, siempre que el representador
personalizado esté asociado a un nuevo elemento de Xamarin.Forms. Esta configuración implica la creación de un
nuevo objeto Camera nativo para acceder a una cámara de hardware concreto y registrar un controlador de
eventos para procesar el evento de Click . A su vez este controlador detendrá e iniciará la vista previa de vídeo
cuando se pulse. Se cancela la suscripción del evento Click solo si cambia el representador al que está adjunto el
elemento de Xamarin.Forms.
Creación del representador personalizado en UWP
En el siguiente ejemplo de código se muestra el representador personalizado para UWP:
if (e.OldElement != null)
{
// Unsubscribe
Tapped -= OnCameraPreviewTapped;
...
}
if (e.NewElement != null)
{
if (Control == null)
{
...
_captureElement = new CaptureElement();
_captureElement.Stretch = Stretch.UniformToFill;
SetupCamera();
SetNativeControl(_captureElement);
}
// Subscribe
Tapped += OnCameraPreviewTapped;
}
}
Siempre que la propiedad Control sea null , se crea una instancia de un nuevo CaptureElement y se llama al
método SetupCamera , que usa la API de MediaCapture para proporcionar la secuencia de vista previa de la cámara.
Después se llama al método SetNativeControl para asignar una referencia a la instancia de CaptureElement para la
propiedad Control . El control CaptureElement expone un evento Tapped que controla el método
OnCameraPreviewTapped para detener e iniciar la vista previa de vídeo cuando se pulsa. Se establece una suscripción
al evento Tapped cuando el representador personalizado se adjunta a un nuevo elemento de Xamarin.Forms y
solo se cancela la suscripción cuando el elemento al que está adjunto el representador cambia.
NOTE
Es importante detener y eliminar los objetos que proporcionan acceso a la cámara en una aplicación de UWP. Si no lo hace
puede interferir con otras aplicaciones que intentan acceder a la cámara del dispositivo. Para obtener más información, vea
Display the camera preview (Mostar la vista previa de la cámara).
Resumen
En este artículo se mostró cómo crear un representador personalizado para un control personalizado de
Xamarin.Forms que se usa para mostrar una secuencia de vídeo de vista previa de la cámara del dispositivo. Los
controles de interfaces de usuario personalizadas de Xamarin.Forms deben derivar de la clase View , que se usa
para colocar los diseños y los controles en la pantalla.
Vínculos relacionados
CustomRendererView (sample) (CustomRendererView [ejemplo])
Implementación de HybridWebView
11/07/2019 • 31 minutes to read • Edit Online
Descargar el ejemplo
Los controles de interfaz de usuario personalizados de Xamarin.Forms deben derivar de la clase View, que se usa
para colocar diseños y controles en la pantalla. En este artículo se muestra cómo crear un representador
personalizado para un control personalizado HybridWebView, lo que mejora los controles web específicos de la
plataforma para permitir la invocación de código de C# desde JavaScript.
Todas las vistas de Xamarin.Forms tienen un representador adjunto para cada plataforma que crea una instancia
de un control nativo. Cuando una aplicación de Xamarin.Forms representa una instancia de View en iOS, se crea
una instancia de la clase ViewRenderer , que a su vez crea una instancia del control UIView nativo. En la plataforma
Android, la clase ViewRenderer crea una instancia de un control View . En Plataforma universal de Windows
(UWP ), la clase ViewRenderer crea una instancia de un control FrameworkElement nativo. Para obtener más
información sobre el representador y las clases de control nativo a las que se asignan los controles de
Xamarin.Forms, vea Renderer Base Classes and Native Controls (Clases base y controles nativos del
representador).
El siguiente diagrama muestra la relación entre la clase View y los controles nativos correspondientes que la
implementan:
El proceso de representación puede usarse para implementar personalizaciones específicas de plataforma al crear
un representador personalizado para una clase View en cada plataforma. Para ello, siga este procedimiento:
1. Cree el control HybridWebView personalizado.
2. Use el elemento HybridWebView de Xamarin.Forms.
3. Cree el representador personalizado para el elemento HybridWebView en cada plataforma.
Ahora se va a hablar de cada elemento para implementar un representador de HybridWebView que mejore los
controles web específicos de la plataforma a fin de permitir la invocación de código de C# desde JavaScript. Se usa
la instancia de HybridWebView para mostrar una página HTML que pide al usuario que escriba su nombre. Luego,
cuando el usuario hace clic en un botón HTML, una función de JavaScript invoca a un elemento Action de C# que
muestra una ventana emergente que contiene el nombre de los usuarios.
Para obtener más información sobre el proceso de invocación de C# desde JavaScript, vea Invocación a C# desde
JavaScript. Para obtener más información sobre la página HTML, vea Creación de la página web.
Creación de HybridWebView
Se puede crear el control personalizado HybridWebView mediante la creación de subclases de la clase View , como
se muestra en el siguiente ejemplo de código:
El control HybridWebView personalizado se crea en el proyecto de biblioteca de .NET Standard y define la siguiente
API para el control:
Una propiedad Uri que especifica la dirección de la página web que se va a cargar.
Un método RegisterAction que registra un elemento Action con el control. Se invoca a la acción registrada
desde el código de JavaScript incluido en el archivo HTML al que hace referencia la propiedad Uri .
Un método CleanUp que quita la referencia al elemento registrado Action .
Un método InvokeAction que invoca al elemento registrado Action . Se llama a este método desde un
representador personalizado en cada proyecto específico de plataforma.
Uso de HybridWebView
En XAML, se puede hacer referencia al control personalizado HybridWebView en el proyecto de biblioteca de .NET
Standard al declarar un espacio de nombres para su ubicación y usar el prefijo del espacio de nombres en el
control personalizado. El siguiente ejemplo de código muestra cómo se puede usar el control personalizado
HybridWebView en una 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>
El prefijo de espacio de nombres local puede tener cualquier nombre. Pero los valores clr-namespace y
assembly deben coincidir con los detalles del control personalizado. Una vez que se declara el espacio de nombres,
el prefijo se usa para hacer referencia al control personalizado.
El siguiente ejemplo de código muestra cómo se puede usar el control personalizado HybridWebView en una página
C#:
La instancia de HybridWebView se usa para mostrar un control web nativo en cada plataforma. Su propiedad Uri
se establece en un archivo HTML que se almacena en cada proyecto específico de plataforma y que muestra el
control web nativo. El HTML representado pide al usuario que escriba su nombre, con una función de JavaScript
que invoca a un elemento Action de C# en respuesta a un clic de botón HTML.
HybridWebViewPage registra la acción que se va a invocar desde JavaScript, como se muestra en el ejemplo de
código siguiente:
Esta acción llama al método DisplayAlert para mostrar un elemento emergente modal que presenta el nombre
especificado en la página HTML que muestra la instancia de HybridWebView .
Ahora se puede agregar un representador personalizado a cada proyecto de aplicación para mejorar los controles
web específicos de la plataforma al permitir la invocación de código de C# desde JavaScript.
NOTE
Para la mayoría de los elementos de Xamarin.Forms, proporcionar un representador personalizado en cada proyecto de la
plataforma es un paso opcional. Si no hay un representador personalizado registrado, se usa el representador
predeterminado de la clase base del control. Pero los representadores personalizados son necesarios en cada proyecto de
plataforma al representar un elemento View.
El siguiente diagrama muestra las responsabilidades de cada proyecto de la aplicación de ejemplo, junto con las
relaciones entre ellos:
La clase ViewRenderer expone el método OnElementChanged , al que se llama cuando se crea el control
personalizado de Xamarin.Forms para representar el control web nativo correspondiente. Este método toma un
parámetro ElementChangedEventArgs que contiene propiedades OldElement y NewElement . Estas propiedades
representan al elemento de Xamarin.Forms al que estaba asociado el representador y al elemento de
Xamarin.Forms al que está asociado el representador, respectivamente. En la aplicación de ejemplo, la propiedad
OldElement es null y la propiedad NewElement contiene una referencia a la instancia de HybridWebView .
Una versión invalidada del método OnElementChanged , en cada clase de representador específica de la plataforma,
es el lugar en el que realizar la personalización y la creación de instancias del control web nativo. Se debe usar el
método SetNativeControl para crear instancias del control web nativo; además, este método también asigna la
referencia del control a la propiedad Control . Además, se puede obtener una referencia al control de
Xamarin.Forms que se va a representar mediante la propiedad Element .
En algunas circunstancias, se puede llamar al método OnElementChanged varias veces. Por lo tanto, para evitar
pérdidas de memoria, se debe tener cuidado a la hora de crear instancias de un nuevo control nativo. El enfoque
que usar al crear instancias de un nuevo control nativo en un presentador personalizado se muestra en el ejemplo
de código siguiente:
if (e.OldElement != null) {
// Unsubscribe from event handlers and cleanup any resources
}
if (e.NewElement != null) {
if (Control == null) {
// Instantiate the native control and assign it to the Control property with
// the SetNativeControl method
}
// Configure the control and subscribe to event handlers
}
}
Solo se debe crear una instancia de un nuevo control nativo una vez, cuando la propiedad Control es null .
Además, solo se debe crear, configurar el control y suscribir los controladores de eventos cuando se adjunta el
presentador personalizado a un nuevo elemento de Xamarin.Forms. De forma similar, solo se debe cancelar la
suscripción de los controladores de eventos que se han suscrito cuando cambia el elemento al que está asociado el
presentador. La adopción de este enfoque ayuda a crear un representador personalizado eficaz que no sufra
pérdidas de memoria.
IMPORTANT
El método SetNativeControl solo se debe llamar si e.NewElement no es null .
Cada clase de representador personalizado se decora con un atributo ExportRenderer que registra el
representador con Xamarin.Forms. El atributo toma dos parámetros: el nombre de tipo del control personalizado
de Xamarin.Forms que se va a representar y el nombre de tipo del representador personalizado. El prefijo
assembly del atributo especifica que el atributo se aplica a todo el ensamblado.
En las secciones siguientes se habla de la estructura de la página web cargada por cada control web nativo, el
proceso para invocar a C# desde JavaScript y su implementación en cada clase de representador personalizado
específico de la plataforma.
Creación de la página web
El ejemplo de código siguiente muestra la página web que va a mostrar el control 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>
La página web permite que un usuario escriba su nombre en un elemento input y proporciona un elemento
button que va a invocar a código de C# cuando se haga clic sobre él. El proceso para lograrlo es el siguiente:
Cuando el usuario hace clic en el elemento button , se llama a la función de JavaScript invokeCSCode y el valor
del elemento input se pasa a la función.
La función invokeCSCode llama a la función log para mostrar los datos que está enviando al elemento Action
de C#. Luego llama al método invokeCSharpAction para invocar al elemento Action de C#, pasando el
parámetro recibido desde el elemento input .
La función de JavaScript invokeCSharpAction no está definida en la página web, así que es cada representador
personalizado el que la inserta en ella.
En iOS, este archivo HTML se encuentra en la carpeta de contenido del proyecto de la plataforma e incluye una
acción de compilación de BundleResource. En Android, este archivo HTML se encuentra en la carpeta de
contenido o recursos del proyecto de la plataforma e incluye una acción de compilación de AndroidAsset.
Invocación de C# desde JavaScript
El proceso para invocar a C# desde JavaScript es idéntico en cada plataforma:
El representador personalizado crea un control web nativo y carga el archivo HTML especificado por la
propiedad HybridWebView.Uri .
Una vez que se ha cargado la página web, el representador personalizado inserta la función de JavaScript
invokeCSharpAction en la página web.
Cuando el usuario escribe su nombre y hace clic en el elemento HTML button , se invoca a la función
invokeCSCode , que a su vez invoca a la función invokeCSharpAction .
La función invokeCSharpAction invoca a un método del representador personalizado, que a su vez invoca al
método HybridWebView.InvokeAction .
El método HybridWebView.InvokeAction invoca al elemento registrado Action .
En las secciones siguientes se habla de cómo se implementa este proceso en cada plataforma.
Creación del representador personalizado en iOS
El ejemplo de código siguiente muestra el representador personalizado para la plataforma iOS:
if (e.OldElement != null) {
userController.RemoveAllUserScripts ();
userController.RemoveScriptMessageHandler ("invokeAction");
var hybridWebView = e.OldElement as HybridWebView;
hybridWebView.Cleanup ();
}
if (e.NewElement != null) {
if (Control == null) {
userController = new WKUserContentController ();
var script = new WKUserScript (new NSString (JavaScriptFunction),
WKUserScriptInjectionTime.AtDocumentEnd, false);
userController.AddUserScript (script);
userController.AddScriptMessageHandler (this, "invokeAction");
NOTE
La clase WKWebView solo se admite en iOS 8 y versiones posteriores.
Además, Info.plist debe actualizarse para que incluya los siguientes valores:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
if (e.OldElement != null)
{
Control.RemoveJavascriptInterface("jsBridge");
var hybridWebView = e.OldElement as HybridWebView;
hybridWebView.Cleanup();
}
if (e.NewElement != null)
{
if (Control == null)
{
var webView = new Android.Webkit.WebView(_context);
webView.Settings.JavaScriptEnabled = true;
webView.SetWebViewClient(new JavascriptWebViewClient($"javascript:
{JavascriptFunction}"));
SetNativeControl(webView);
}
Control.AddJavascriptInterface(new JSBridge(this), "jsBridge");
Control.LoadUrl($"file:///android_asset/Content/{Element.Uri}");
}
}
}
}
Una vez que el usuario escribe su nombre y hace clic en el elemento HTML button , se ejecuta la función de
JavaScript invokeCSharpAction . Esta funcionalidad se logra del siguiente modo:
Siempre que el representador personalizado está asociado a un nuevo elemento de Xamarin.Forms:
Siempre que la propiedad Control es null , se efectúan las siguientes operaciones:
Se crea una instancia nativa de WebView , JavaScript se habilita en el control y se establece una
instancia de JavascriptWebViewClient como la implementación de WebViewClient .
Se llama al método SetNativeControl para asignar una referencia al control nativo WebView para
la propiedad Control .
El método WebView.AddJavascriptInterface inserta una nueva instancia de JSBridge en el marco
principal del contexto de JavaScript de WebView y le asigna el nombre jsBridge . Esto permite acceder a
los métodos de la clase JSBridge desde JavaScript.
El método WebView.LoadUrl carga el archivo HTML especificado por la propiedad HybridWebView.Uri . El
código especifica que el archivo se almacena en la carpeta Content del proyecto.
En la clase JavascriptWebViewClient , la función de JavaScript invokeCSharpAction se inserta en la página
web una vez que esta termina de cargarse.
Cuando cambia el elemento al que está asociado el representador:
Se liberan recursos.
Cuando se ejecuta la función de JavaScript invokeCSharpAction , a su vez invoca al método JSBridge.InvokeAction ,
que se muestra en el ejemplo de código siguiente:
[JavascriptInterface]
[Export ("invokeAction")]
public void InvokeAction (string data)
{
HybridWebViewRenderer hybridRenderer;
La clase debe derivar de Java.Lang.Object y los métodos que se exponen a JavaScript deben decorarse con los
atributos [JavascriptInterface] y [Export] . Por lo tanto, cuando se inserta la función de JavaScript
invokeCSharpAction en la página web y se ejecuta, llama al método JSBridge.InvokeAction , puesto que está
decorado con los atributos [JavascriptInterface] y [Export("invokeAction")] . A su vez, el método InvokeAction
invoca al método HybridWebView.InvokeAction , que invoca a la acción registrada para mostrar la ventana
emergente.
NOTE
Los proyectos que usan el atributo [Export] deben incluir una referencia a Mono.Android.Export , o se produce un error
del compilador.
Tenga en cuenta que la clase JSBridge mantiene un elemento WeakReference para la clase HybridWebViewRenderer .
Esto es para evitar la creación de una referencia circular entre las dos clases. Para obtener más información, vea
Referencias débiles en MSDN.
Creación del representador personalizado en UWP
En el ejemplo de código siguiente se muestra el representador personalizado para UWP:
if (e.OldElement != null)
{
Control.NavigationCompleted -= OnWebViewNavigationCompleted;
Control.ScriptNotify -= OnWebViewScriptNotify;
}
if (e.NewElement != null)
{
if (Control == null)
{
SetNativeControl(new Windows.UI.Xaml.Controls.WebView());
}
Control.NavigationCompleted += OnWebViewNavigationCompleted;
Control.ScriptNotify += OnWebViewScriptNotify;
Control.Source = new Uri(string.Format("ms-appx-web:///Content//{0}", Element.Uri));
}
}
Resumen
En este artículo se ha mostrado cómo crear un representador personalizado para un control personalizado
HybridWebView , lo que mejora los controles web específicos de la plataforma para permitir la invocación de código
de C# desde JavaScript.
Vínculos relacionados
CustomRendererHybridWebView (ejemplo)
Call C# from JavaScript (Llamada a C# desde JavaScript)
Implementación de un reproductor de vídeo
11/07/2019 • 5 minutes to read • Edit Online
Descargar el ejemplo
A veces es conveniente reproducir archivos de vídeo en una aplicación de Xamarin.Forms. En esta serie de
artículos se explica cómo escribir representadores personalizados para iOS, Android y la plataforma Universal de
Windows (UWP ) para una clase de Xamarin.Forms denominada VideoPlayer .
En el ejemplo VideoPlayerDemos, todos los archivos que implementan y admiten VideoPlayer están en
carpetas denominadas FormsVideoLibrary y se identifican con el espacio de nombres FormsVideoLibrary o los
espacios de nombres que empiezan por FormsVideoLibrary . Esta organización y nomenclatura debería hacer que
resulte más fácil copiar los archivos del reproductor de vídeo en su propia solución de Xamarin.Forms.
VideoPlayer puede reproducir archivos de vídeo de tres tipos de orígenes:
Internet mediante una dirección URL
Un recurso insertado en la aplicación de plataforma
La biblioteca de vídeos del dispositivo
Los reproductores de vídeo necesitan controles de transporte, que son botones para reproducir y pausar el vídeo,
y una barra de posición que muestra el progreso a través del vídeo y permite al usuario ir rápidamente a una
ubicación diferente. VideoPlayer puede usar los controles de transporte y la barra de posición proporcionados
por la plataforma (como se muestra más adelante), o puede proporcionar controles de transporte personalizados
y una barra de posición. Este es el programa que se ejecuta en iOS, Android y la Plataforma universal de
Windows:
Por supuesto, puede colocar el teléfono en horizontal para tener una vista más grande.
Un reproductor de vídeo más sofisticado tendría algunas características adicionales, como un control de volumen,
un mecanismo para interrumpir el vídeo cuando entra una llamada telefónica y una manera de mantener la
pantalla activa durante la reproducción.
En los siguientes artículos se muestra progresivamente cómo se compilan los representadores de plataforma y las
clases auxiliares:
Creación de reproductores de vídeo de la plataforma
Cada plataforma necesita una clase VideoPlayerRenderer que crea y mantiene un control de reproductor de vídeo
compatible con la plataforma. En este artículo se muestra la estructura de las clases del representador y cómo se
crean los reproductores.
Vínculos relacionados
Demostraciones de reproductor de vídeo (ejemplo)
Creación de reproductores de vídeo de plataforma
11/07/2019 • 13 minutes to read • Edit Online
Descargar el ejemplo
La solución VideoPlayerDemos contiene todo el código necesario para implementar un reproductor de vídeo
para Xamarin.Forms. También incluye una serie de páginas en las que se muestra cómo usar el reproductor de
vídeo dentro de una aplicación. Todo el código VideoPlayer y sus representadores de plataforma residen en
carpetas de proyecto denominadas FormsVideoLibrary que además usan el espacio de nombres
FormsVideoLibrary . Esto debería facilitar la copia de los archivos en la propia aplicación y la referencia a las clases.
Reproductor de vídeo
La clase VideoPlayer forma parte de la biblioteca de .NET Standard VideoPlayerDemos compartida entre las
plataformas. Deriva de View :
using System;
using Xamarin.Forms;
namespace FormsVideoLibrary
{
public class VideoPlayer : View, IVideoPlayerController
{
···
}
}
Los miembros de esta clase (y la interfaz IVideoPlayerController ) se describen en los artículos siguientes.
Cada una de las plataformas contiene una clase denominada VideoPlayerRenderer que contiene el código
específico de la plataforma en la que se va a implementar un reproductor de vídeo. La tarea principal de este
representador es crear un reproductor de vídeo para esa plataforma.
Controlador de vistas del reproductor de iOS
Hay varias clases involucradas en la implementación de un reproductor de vídeo en iOS. La aplicación primero
crea un elemento AVPlayerViewController y luego establece la propiedad Player en un objeto de tipo AVPlayer .
Se necesitan otras clases cuando se asigna un origen de vídeo al reproductor.
Como todos los representadores, el elemento VideoPlayerRenderer de iOS contiene un atributo ExportRenderer
que identifica la vista VideoPlayer con el representador:
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>
{
···
}
}
if (args.NewElement != null)
{
if (Control == null)
{
// Create AVPlayerViewController
_playerViewController = new AVPlayerViewController();
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)
{
}
···
}
}
A partir de Xamarin.Forms 2.5, los representadores de Android deben incluir un constructor con un argumento
Context .
if (args.NewElement != null)
{
if (Control == null)
{
// Save the VideoView for future reference
videoView = new VideoView(Context);
Un controlador del evento Prepared se asocia en este método y se desasocia en el método Dispose . Este evento
se desencadena cuando VideoView tiene suficiente información para empezar a reproducir un archivo de vídeo.
Elemento multimedia de UWP
En Plataforma universal de Windows (UWP ), el reproductor de vídeo más común es MediaElement . La
documentación de MediaElement indica que se debe usar MediaPlayerElement en su lugar cuando solo sea
necesario admitir versiones de Windows 10 a partir de la compilación 1607.
La invalidación OnElementChanged debe crear un elemento MediaElement , establecer un par de controladores de
eventos y pasar el objeto MediaElement a 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;
}
···
}
···
}
base.Dispose(disposing);
}
···
}
}
Aunque esta propiedad tiene descriptores de acceso set y get , el representador solo tiene que controlar los
casos en que la propiedad esté establecida. El descriptor de acceso get simplemente devuelve el valor actual de la
propiedad.
Propiedades como AreTransportControlsEnabled se controlan en los representadores de plataforma de dos
maneras:
La primera es cuando Xamarin.Forms crea un elemento VideoPlayer . Esto se indica en la invalidación
OnElementChanged del representador si la propiedad NewElement no es null . En este momento, el
representador puede establecer su propio reproductor de vídeo de plataforma a partir del valor inicial de la
propiedad, como se ha definido en VideoPlayer .
Si la propiedad de VideoPlayer cambia más adelante, se llama al método OnElementPropertyChanged del
representador. Esto permite al representador actualizar el reproductor de vídeo de plataforma en función del
nuevo valor de la propiedad.
En las secciones siguientes se explica cómo se controla la propiedad AreTransportControlsEnabled en cada
plataforma.
Controles de reproducción de iOS
La propiedad del elemento AVPlayerViewController de iOS que controla la presentación de controles de transporte
es ShowsPlaybackControls . Así es como esa propiedad se establece en el elemento VideoViewRenderer de iOS:
namespace FormsVideoLibrary.iOS
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, UIView>
{
···
AVPlayerViewController _playerViewController; // solely for ViewController property
if (args.PropertyName == VideoPlayer.AreTransportControlsEnabledProperty.PropertyName)
{
SetAreTransportControlsEnabled();
}
···
}
void SetAreTransportControlsEnabled()
{
((AVPlayerViewController)ViewController).ShowsPlaybackControls =
Element.AreTransportControlsEnabled;
}
···
}
}
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;
}
}
}
···
}
}
if (args.PropertyName == VideoPlayer.AreTransportControlsEnabledProperty.PropertyName)
{
SetAreTransportControlsEnabled();
}
···
}
void SetAreTransportControlsEnabled()
{
Control.AreTransportControlsEnabled = Element.AreTransportControlsEnabled;
}
···
}
}
Una propiedad más es necesaria para empezar a reproducir un vídeo: se trata de la propiedad fundamental
Source que hace referencia a un archivo de vídeo. La implementación de la propiedad Source se describe en el
siguiente artículo, Reproducción de un vídeo de web.
Vínculos relacionados
Demostraciones de reproductor de vídeo (ejemplo)
Reproducción de un vídeo web
11/07/2019 • 14 minutes to read • Edit Online
Descargar el ejemplo
La clase VideoPlayer define una propiedad Source que se usa para especificar el origen del archivo de vídeo, así
como una propiedad AutoPlay . El valor predeterminado de AutoPlay es true , lo que significa que el vídeo se
debería comenzar a reproducir de forma automática después de establecer 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);
La propiedad Source es de tipo VideoSource , que se modela a partir de la clase abstracta ImageSource de
Xamarin.Forms y sus tres derivadas UriImageSource , FileImageSource y StreamImageSource . Pero no hay ninguna
opción de hacer streaming disponible para VideoPlayer , porque iOS y Android no admiten la reproducción de un
vídeo desde una secuencia.
Orígenes de vídeo
La clase abstracta VideoSource consta únicamente de tres métodos estáticos que crean las instancias de las tres
clases que se derivan de VideoSource :
namespace FormsVideoLibrary
{
[TypeConverter(typeof(VideoSourceConverter))]
public abstract class VideoSource : Element
{
public static VideoSource FromUri(string uri)
{
return new UriVideoSource() { Uri = uri };
}
La clase UriVideoSource se usa para especificar un archivo de vídeo descargable con un URI. Define una única
propiedad de tipo string :
namespace FormsVideoLibrary
{
public class UriVideoSource : VideoSource
{
public static readonly BindableProperty UriProperty =
BindableProperty.Create(nameof(Uri), typeof(string), typeof(UriVideoSource));
namespace FormsVideoLibrary
{
public class ResourceVideoSource : VideoSource
{
public static readonly BindableProperty PathProperty =
BindableProperty.Create(nameof(Path), typeof(string), typeof(ResourceVideoSource));
El control de los objetos de tipo ResourceVideoSource se describe en el artículo Carga de vídeos de recursos de
aplicación. La clase VideoPlayer no tiene ninguna función para cargar un archivo de vídeo almacenado como un
recurso en la biblioteca de .NET Standard.
La clase FileVideoSource se usa para acceder a los archivos de vídeo desde la biblioteca de vídeos del dispositivo.
La única propiedad también es de tipo string :
namespace FormsVideoLibrary
{
public class FileVideoSource : VideoSource
{
public static readonly BindableProperty FileProperty =
BindableProperty.Create(nameof(File), typeof(string), typeof(FileVideoSource));
El control de los objetos de tipo FileVideoSource se describe en el artículo Acceso a la biblioteca de vídeos del
dispositivo.
La clase VideoSource incluye un atributo TypeConverter que hace referencia a VideoSourceConverter :
namespace FormsVideoLibrary
{
[TypeConverter(typeof(VideoSourceConverter))]
public abstract class VideoSource : Element
{
···
}
}
Este convertidor de tipos se invoca cuando la propiedad Source se establece en una cadena en XAML. Esta es la
clase 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);
}
namespace FormsVideoLibrary.iOS
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, UIView>
{
···
protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)
{
···
if (args.NewElement != null)
{
···
SetSource();
···
}
}
Más adelante, cuando se cambia la propiedad Source , se llama al método OnElementPropertyChanged con una
propiedad PropertyName de "Source" (Origen), y se vuelve a llamar a SetSource .
Para reproducir un archivo de vídeo en iOS, primero se crea un objeto de tipo AVAsset para encapsular el archivo
de vídeo, que se usa para crear un elemento AVPlayerItem , que después se pasa al objeto AVPlayer . Esta es la
forma en la que el método SetSource controla la propiedad Source cuando es de 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);
La propiedad AutoPlay no cuenta con ninguna análoga en las clases de vídeo de iOS, por lo que se examina al
final del método SetSource para llamar al método Play en el objeto AVPlayer .
En algunos casos, los vídeos se siguen reproduciendo después de que la página con el elemento VideoPlayer
haya vuelto a la página principal. Para detener el vídeo, ReplaceCurrentItemWithPlayerItem también se establece en
la invalidación de 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);
}
}
···
}
}
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();
}
···
}
···
}
}
El método SetSource controla los objetos de tipo UriVideoSource mediante una llamada a SetVideoUri en
VideoView con un objeto Uri de Android creado a partir de la cadena de URI. Aquí la clase Uri es completa
para distinguirla de la clase Uri de .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;
}
}
···
El objeto VideoView de Android no tiene una propiedad AutoPlay correspondiente, por lo que se llama al método
Start si se ha establecido un vídeo nuevo.
Hay una diferencia entre el comportamiento de los representadores de iOS y Android si la propiedad Source de
VideoPlayer se establece en null , o bien si la propiedad Uri de UriVideoSource se establece en null o en una
cadena vacía. Si en el reproductor de vídeo de iOS se está reproduciendo un vídeo, y Source está establecido en
null (o la cadena es null o está en blanco), se llama a ReplaceCurrentItemWithPlayerItem con el valor null . Se
reemplaza el vídeo actual y se detiene la reproducción.
Android no admite una función similar. Si la propiedad Source se establece en null , el método SetSource
simplemente la ignora y se sigue reproduciendo el vídeo actual.
Origen de vídeo de UWP
El objeto MediaElement de UWP define una propiedad AutoPlay , que se controla en el representador como
cualquier otra propiedad:
namespace FormsVideoLibrary.UWP
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, MediaElement>
{
protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)
{
···
if (args.NewElement != null)
{
···
SetSource();
SetAutoPlay();
···
}
}
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;
}
···
}
}
<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">
</ContentPage>
<video:VideoPlayer Source="https://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4"
AutoPlay="false" />
<video:VideoPlayer Source="https://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4"
AreTransportControlsEnabled="False" />
Si establece las dos propiedades en false , el vídeo no empezará a reproducirse y no habrá ninguna manera de
iniciarlo. Tendría que llamar a Play desde el archivo de código subyacente, o bien crear controles de transporte
propios como se describe en el artículo Implementación de controles de transporte de vídeo personalizados.
En el archivo App.xaml se incluyen recursos para dos vídeos adicionales:
<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 hacer referencia a una de estas películas, puede reemplazar la dirección URL explícita en el archivo
PlayWebVideo.xaml con una extensión de marcado StaticResource , en cuyo caso no se necesitará
VideoSourceConverter para crear el objeto UriVideoSource :
Como alternativa, puede establecer la propiedad Source de un archivo de vídeo en un elemento ListView , como
se describe en el artículo siguiente, Enlace de orígenes de vídeo al reproductor.
Vínculos relacionados
Demostraciones de reproductor de vídeo (ejemplo)
Enlazar orígenes de vídeo con el reproductor
11/07/2019 • 4 minutes to read • Edit Online
Descargar el ejemplo
Cuando la propiedad Source de la vista VideoPlayer se establece en un nuevo archivo de vídeo, el vídeo existente
deja de reproducirse y se inicia el nuevo vídeo. Esto se demuestra mediante la página Seleccionar vídeo web del
ejemplo VideoPlayerDemos. En esta página, se incluye un elemento ListView con los títulos de los tres vídeos a
los que se hace referencia en el archivo 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>
Al seleccionar un vídeo, se ejecuta el controlador de eventos ItemSelected del archivo de código subyacente. El
controlador elimina los espacios en blanco y los apóstrofos del título y usa el resultado como una clave para
obtener uno de los recursos definidos en el archivo App.xaml. Después, el objeto UriVideoSource se establece en
la propiedad Source del elemento VideoPlayer .
namespace VideoPlayerDemos
{
public partial class SelectWebVideoPage : ContentPage
{
public SelectWebVideoPage()
{
InitializeComponent();
}
Cuando se carga la primera página, no se selecciona ningún elemento en ListView , por lo que tendrá que
seleccionar uno para que el vídeo empiece a reproducirse:
La propiedad Source de VideoPlayer se complementa con una propiedad enlazable, lo que quiere decir que
puede ser el objetivo de un enlace de datos. Esto se demuestra mediante la página Enlazar a VideoPlayer. El
marcado del archivo es compatible con la clase siguiente BindToVideoPlayer.xaml, que encapsula un título para
un vídeo y un objeto correspondiente VideoSource :
namespace VideoPlayerDemos
{
public class VideoInfo
{
public string DisplayName { set; get; }
<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="Sintel"
VideoSource="{StaticResource Sintel}" />
</x:Array>
</ListView.ItemsSource>
</ListView>
</Grid>
</ContentPage>
La propiedad Source del elemento VideoPlayer se enlaza al elemento ListView . El elemento Path del enlace se
especifica como SelectedItem.VideoSource , que es un trazado compuesto formado por dos propiedades:
SelectedItem es una propiedad de ListView . El elemento seleccionado es del tipo VideoInfo , que tiene una
propiedad VideoSource .
Como con la primera página Seleccionar vídeo web, de manera inicial no se selecciona ningún elemento desde
ListView , por lo que necesita seleccionar uno de los vídeos para que empiece a reproducirse.
Vínculos relacionados
Demostraciones de reproductor de vídeo (ejemplo)
Carga de vídeos de recursos de aplicación
11/07/2019 • 7 minutes to read • Edit Online
Descargar el ejemplo
Los representadores personalizados para la vista VideoPlayer son capaces de reproducir archivos de vídeo que se
han insertado en los proyectos de cada plataforma como recursos de la aplicación. Pero la versión actual de
VideoPlayer no puede acceder a los recursos insertados en una biblioteca de .NET Standard.
Para cargar estos recursos, cree una instancia de ResourceVideoSource estableciendo la propiedad Path en el
nombre de archivo (o la carpeta y el nombre de archivo) del recurso. Como alternativa, puede llamar al método
VideoSource.FromResource estático para hacer referencia al recurso. Después, establezca el objeto
ResourceVideoSource en la propiedad Source de VideoPlayer .
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);
}
}
···
}
···
}
}
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;
}
}
···
}
···
}
}
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;
}
}
}
···
}
}
Si el recurso de iOS se almacena en la carpeta Recursos, y si el recurso de UWP se almacena en la carpeta raíz del
proyecto, puede usar el mismo nombre de archivo para cada plataforma. En ese caso, puede establecer ese
nombre directamente en la propiedad Source de VideoPlayer .
Esta es la ejecución de la página:
Ya ha visto cómo cargar vídeos desde un URI web y cómo reproducir recursos insertados. Además, puede cargar
vídeos desde la biblioteca de vídeos del dispositivo.
Vínculos relacionados
Demostraciones de reproductor de vídeo (ejemplo)
Acceder a la biblioteca de vídeos del dispositivo
11/07/2019 • 9 minutes to read • Edit Online
Descargar el ejemplo
Los dispositivos móviles y los equipos de escritorio más modernos tienen la capacidad de grabar vídeos mediante
la cámara que llevan incorporada. Los vídeos que un usuario crea se almacenan como archivos en el dispositivo.
Estos archivos se pueden recuperar de la biblioteca de imágenes, y la clase VideoPlayer puede reproducirlos
igual que cualquier otro vídeo.
namespace FormsVideoLibrary
{
public interface IVideoPicker
{
Task<string> GetVideoFileAsync();
}
}
Cada una de las plataformas contiene una clase denominada VideoPicker que implementa esta interfaz.
El selector de vídeo de iOS
VideoPicker de iOS utiliza UIImagePickerController para acceder a la biblioteca de imágenes y especifica que
dicho acceso debe restringirse a los vídeos (denominados "películas") de la propiedad MediaType de iOS. Tenga
en cuenta que VideoPicker implementa explícitamente la interfaz de IVideoPicker . Tenga en cuenta también el
atributo Dependency que identifica esta clase como un servicio de dependencia. Estos son los dos requisitos que
permiten a Xamarin.Forms encontrar el servicio de dependencia en el proyecto de la 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;
// Present UIImagePickerController;
UIWindow window = UIApplication.SharedApplication.KeyWindow;
var viewController = window.RootViewController;
viewController.PresentModalViewController(imagePicker, true);
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);
}
}
}
}
}
El método OnCreate en MainActivity almacena su propia instancia en la propiedad Current estática. Esto
permite a la implementación de IVideoPicker obtener la instancia de MainActivity para iniciar el selector
Seleccione vídeo:
using System;
using System.Threading.Tasks;
using Android.Content;
using Xamarin.Forms;
[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);
Las adiciones al objeto MainActivity son el único código de la solución VideoPlayerDemos en que el código de
aplicación normal debe modificarse para admitir las clases FormsVideoLibrary .
El selector de vídeo de UWP
La implementación de UWP de la interfaz de IVideoPicker utiliza el FileOpenPicker de UWP. Inicia la búsqueda
de archivos con la biblioteca de imágenes y restringe los tipos de archivo a MP4 y WMV (vídeo de 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");
<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" />
El archivo de código subyacente contiene el controlador de Clicked para el Button . Para invocar el servicio de
dependencia es necesario llamar a DependencyService.Get para obtener la implementación de una interfaz de
IVideoPicker en el proyecto de plataforma. A continuación, se llama al método GetVideoFileAsync en esa
instancia:
namespace VideoPlayerDemos
{
public partial class PlayLibraryVideoPage : ContentPage
{
public PlayLibraryVideoPage()
{
InitializeComponent();
}
if (!String.IsNullOrWhiteSpace(filename))
{
videoPlayer.Source = new FileVideoSource
{
File = filename
};
}
btn.IsEnabled = true;
}
}
}
Posteriormente, el controlador de Clicked utiliza ese nombre de archivo para crear un objeto FileVideoSource y
establecerlo en la propiedad Source del VideoPlayer .
Cada una de las clases VideoPlayerRenderer contiene código en su método SetSource para objetos de tipo
FileVideoSource . Se muestran a continuación:
if (!String.IsNullOrWhiteSpace(uri))
{
asset = AVAsset.FromUrl(new NSUrl(uri));
}
}
···
}
···
}
}
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;
}
}
···
}
···
}
}
if (!String.IsNullOrWhiteSpace(filename))
{
StorageFile storageFile = await StorageFile.GetFileFromPathAsync(filename);
IRandomAccessStreamWithContentType stream = await storageFile.OpenReadAsync();
Control.SetSource(stream, storageFile.ContentType);
hasSetSource = true;
}
}
···
}
···
}
}
En todas las plataformas, el vídeo empieza a reproducirse casi inmediatamente después de establecer el origen de
vídeo porque el archivo se encuentra en el dispositivo y no debe descargarse.
Vínculos relacionados
Demostraciones de reproductor de vídeo (ejemplo)
Seleccionar una foto de la biblioteca de imágenes
Controles de transporte de vídeo personalizados
11/07/2019 • 17 minutes to read • Edit Online
Descargar el ejemplo
Los controles de transporte de un reproductor de vídeo son los botones que realizan las funciones Reproducir,
Pausa y Detener. Estos botones suelen identificarse con iconos conocidos en lugar de texto, y las funciones
Reproducir y Pausa suelen combinarse en un mismo botón.
De forma predeterminada, el elemento VideoPlayer muestra controles de transporte compatibles con cada
plataforma. Al establecer la propiedad AreTransportControlsEnabled en false , se eliminan estos controles.
Después, puede controlar el elemento VideoPlayer mediante programación, o bien puede eliminar sus propios
controles de transporte.
namespace FormsVideoLibrary
{
public class VideoPlayer : View, IVideoPlayerController
{
···
public event EventHandler PlayRequested;
Los controladores de eventos para estos eventos se establecen mediante la clase VideoPlayerRenderer en cada
plataforma, como se muestra a continuación:
Implementaciones de transporte de iOS
La versión de iOS de VideoPlayerRenderer usa el método OnElementChanged para establecer controladores para
estos tres eventos cuando la propiedad NewElement no es null y elimina la asociación de los controladores de
eventos cuando OldElement no es 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();
}
Para implementar los controladores de eventos, se llama a métodos en el objeto AVPlayer . Como no hay ningún
método Stop para AVPlayer , para simularlo, se pausa el vídeo y se mueve la posición al principio.
Implementaciones de transporte de Android
La implementación de Android es similar a la implementación de iOS. Los controladores para las tres funciones
se establecen cuando NewElement no es null y, cuando OldElement no es null , se elimina la asociación:
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();
}
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();
}
La clase VideoPlayer define una propiedad enlazable de solo lectura denominada Status del tipo VideoStatus .
Esta propiedad se define como de solo lectura porque únicamente tiene que establecerse desde el representador
de la 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);
VideoStatus IVideoPlayerController.Status
{
set { SetValue(StatusPropertyKey, value); }
get { return Status; }
}
···
}
}
Normalmente, una propiedad enlazable de solo lectura tendría un descriptor de acceso set privado en la
propiedad Status para permitirle establecerlo en la clase. Pero, para un elemento View derivado admitido por
representadores, la propiedad tiene que establecerse desde fuera de la clase, pero solo por el representador de la
plataforma.
Por este motivo, se define otra propiedad con el nombre IVideoPlayerController.Status . Esta es una
implementación de interfaz explícita y es posible mediante la interfaz IVideoPlayerController que implementa la
clase VideoPlayer :
namespace FormsVideoLibrary
{
public interface IVideoPlayerController
{
VideoStatus Status { set; get; }
Esto es similar a la forma en que el control WebView usa la interfaz IWebViewController para implementar las
propiedades CanGoBack y CanGoForward . (Para obtener más información, vea el código fuente de WebView y sus
representadores).
Esto permite que una clase externa a VideoPlayer pueda establecer la propiedad Status al hacer referencia a la
interfaz IVideoPlayerController . (Verá el código en breve). La propiedad también se puede establecer desde otras
clases, pero es poco probable que se establezca por error. Aún más importante, la propiedad Status no se puede
establecer mediante un enlace de datos.
Para ayudar a los representadores a mantener actualizada la propiedad Status , la clase VideoPlayer define un
evento UpdateStatus que se desencadena cada décima 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;
});
}
···
}
}
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;
···
}
···
}
}
Se debe acceder a dos propiedades de AVPlayer : la propiedad Status de tipo AVPlayerStatus y la propiedad
TimeControlStatus de tipo AVPlayerTimeControlStatus . Tenga en cuenta que la propiedad Element (que es el
objeto VideoPlayer ) tiene que transmitir a IVideoPlayerController para establecer la propiedad Status .
Ajuste de estado de Android
La propiedad IsPlaying del elemento VideoView de Android es un operador booleano que solo indica si el vídeo
está reproduciéndose o en pausa. Para determinar si el elemento VideoView aún no puede reproducir ni pausar el
vídeo, es necesario controlar el evento Prepared de VideoView . Estos dos controladores se establecen en el
método OnElementChanged y se anula la asociación durante el reemplazo Dispose :
namespace FormsVideoLibrary.Droid
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, ARelativeLayout>
{
VideoView videoView;
···
bool isPrepared;
if (args.OldElement != null)
{
args.OldElement.UpdateStatus -= OnUpdateStatus;
···
}
base.Dispose(disposing);
}
···
}
}
if (isPrepared)
{
status = videoView.IsPlaying ? VideoStatus.Playing : VideoStatus.Paused;
}
···
}
···
}
}
if (args.NewElement != null)
{
if (Control == null)
{
···
mediaElement.CurrentStateChanged += OnMediaElementCurrentStateChanged;
};
···
}
···
}
base.Dispose(disposing);
}
···
}
}
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;
}
···
}
}
Botones Reproducir, Pausa y Detener
Usar caracteres Unicode para imágenes simbólicas de Reproducir, Pausar y Detener es problemático. En la
sección Aspectos técnicos varios del estándar Unicode, se definen tres caracteres de símbolos que parecen
apropiados para esta finalidad. Estos son:
0x23F5 (triángulo que apunta hacia la derecha de tamaño medio y color negro) o para Reproducir
0x23F8 (barra doble vertical) o para Pausa
0x23F9 (cuadrado negro) o para Detener
Independientemente de cómo se muestren estos símbolos en el explorador (ya que en cada explorador se
controlan de formas distintas), no se muestran de forma coherente en las plataformas admitidas por
Xamarin.Forms. En dispositivos con iOS y UWP, los caracteres Pausa y Detener tienen una apariencia gráfica,
pero con un fondo 3D azul y un primer plano blanco. Esto no ocurre en Android, donde el símbolo es
simplemente azul. Pero el punto de código 0x23F5 de Reproducir no tiene la misma apariencia en UWP y,
además, ni siquiera se admite en iOS y Android.
Por ese motivo, el punto de código 0x23F5 no se puede usar para Reproducir. Un sustituto adecuado es:
0x25B6 (triángulo que apunta hacia la derecha negro) o ▶ para Reproducir
Esto se admite en todas las plataformas, pero se trata de un triángulo negro sin formato que no tiene la apariencia
3D de Pausa y Detener. Una posibilidad es seguir el punto de código 0x25B6 con un código de variante:
0x25B6 seguido de 0xFE0F (variante 16) o ▶ para Reproducir
Esto es lo que se usa en el marcado que se muestra a continuación. En iOS, proporciona al símbolo de
Reproducir la misma apariencia 3D que los botones Pausa y Detener, pero la variante no funciona en Android
ni en UWP.
La página Transporte personalizado establece la propiedad AreTransportControlsEnabled en false e incluye
un elemento ActivityIndicator mostrado cuando el vídeo está cargándose, además de dos botones. Los objetos
DataTrigger se usan para habilitar y deshabilitar el elemento ActivityIndicator y los botones, así como para
cambiar el primer botón entre Reproducir y Pausa:
<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}">
<DataTrigger TargetType="Button"
Binding="{Binding Status}"
Value="{x:Static video:VideoStatus.NotReady}">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Button.Triggers>
</Button>
Pero, en Android y UWP, el botón Reproducir tiene una apariencia muy distinta cuando el vídeo está pausado:
En una aplicación de producción, es probable que quiera usar sus propias imágenes de mapa de bits para los
botones con el fin de conseguir una uniformidad visual.
Vínculos relacionados
Demostraciones de reproductor de vídeo (ejemplo)
Barra de posición de vídeo personalizada
11/07/2019 • 18 minutes to read • Edit Online
Descargar el ejemplo
Los controles de transporte que cada plataforma implementa incluyen una barra de posición. Esta barra es similar
a un control deslizante o una barra de desplazamiento y muestra la ubicación actual del vídeo dentro de su
duración total. Además, el usuario puede manipular la barra de posición para avanzar o retroceder a una nueva
posición en el vídeo.
En este artículo se muestra cómo puede implementar su propia barra de posición personalizada.
La propiedad Duration
Un elemento de información que VideoPlayer necesita para admitir una barra de posición personalizada es la
duración del vídeo. VideoPlayer define una propiedad Duration de solo lectura de 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());
TimeSpan IVideoPlayerController.Duration
{
set { SetValue(DurationPropertyKey, value); }
get { return Duration; }
}
···
}
}
Al igual que la propiedad Status descrita en el artículo anterior, esta propiedad Duration es de solo lectura. Se
define con una clave BindablePropertyKey privada y solo se puede establecer mediante una referencia a la interfaz
de IVideoPlayerController , que incluye esta propiedad Duration :
namespace FormsVideoLibrary
{
public interface IVideoPlayerController
{
VideoStatus Status { set; get; }
Tenga en cuenta también el controlador de cambio de propiedad que llama a un método denominado
SetTimeToEnd que se describe más adelante en este artículo.
La duración de un vídeo no está disponible inmediatamente después de que se establezca la propiedad Source de
VideoPlayer . El archivo de vídeo debe descargarse parcialmente antes de que el reproductor de vídeo subyacente
pueda determinar su duración.
Aquí le mostramos cómo cada uno de los representadores de la plataforma obtiene la duración del vídeo:
Duración del vídeo en iOS
En iOS, la duración de un vídeo se obtiene a partir de la propiedad Duration de AVPlayerItem , pero no
inmediatamente después de que se haya creado AVPlayerItem . Es posible establecer un observador de iOS para la
propiedad Duration , pero VideoPlayerRenderer obtiene la duración en el método UpdateStatus , al que se llama 10
veces 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);
···
}
}
}
···
}
}
namespace FormsVideoLibrary.UWP
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, MediaElement>
{
···
void OnMediaElementMediaOpened(object sender, RoutedEventArgs args)
{
((IVideoPlayerController)Element).Duration = Control.NaturalDuration.TimeSpan;
}
···
}
}
La propiedad Position
VideoPlayer también necesita una propiedad Position que aumente de cero a Duration mientras se reproduce
el vídeo. VideoPlayer implementa esta propiedad como la propiedad Position del MediaElement de UWP, que es
una propiedad enlazable normal con descriptores de acceso set y get públicos:
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());
El descriptor de acceso get devuelve la posición actual del vídeo mientras se reproduce, pero el descriptor de
acceso set está pensado para responder a la manipulación del usuario de la barra de posición para mover la
posición de vídeo hacia adelante o hacia atrás.
En iOS y Android, la propiedad que obtiene la posición actual solo tiene un descriptor de acceso get , y hay
disponible un método Seek para realizar esta segunda tarea. Si se piensa bien, un método Seek por separado
parece ser un enfoque más sensato que una sola propiedad Position . Una sola propiedad Position tiene un
problema inherente: mientras se reproduce el vídeo, la propiedad Position debe actualizarse continuamente para
reflejar la nueva posición. Pero no es recomendable que la mayoría de los cambios en la propiedad Position
hagan que el reproductor de vídeo se mueva a una nueva posición en el vídeo. Si eso ocurriera, el reproductor de
vídeo, como respuesta, buscaría el último valor de la propiedad Position y el vídeo no avanzaría.
A pesar de las dificultades de la implementación de una propiedad Position con los descriptores de acceso set y
get , se ha elegido este enfoque porque es coherente con UWP MediaElement , y tiene una gran ventaja con el
enlace de datos: La propiedad Position de VideoPlayer pueden estar enlazada al control deslizante que se usa
para mostrar la posición y para buscar una nueva posición. Sin embargo, se deben tomar varias precauciones al
implementar esta propiedad Position para evitar bucles de retroalimentación.
Establecer y obtener la posición en iOS
En iOS, la propiedad CurrentTime del objeto AVPlayerItem indica la posición actual del vídeo en reproducción.
VideoPlayerRenderer de iOS establece la propiedad Position en el controlador UpdateStatus al mismo tiempo
que establece la propiedad 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));
}
}
···
}
}
Tenga en cuenta que cada vez que la propiedad Position en VideoPlayer se establece desde el controlador
OnUpdateStatus , la propiedad Position activa un evento PropertyChanged , que se detecta en la invalidación de
OnElementPropertyChanged . En la mayoría de estos cambios, el método OnElementPropertyChanged no debe hacer
nada. En caso contrario, ante cada cambio en la posición del vídeo, se movería a la misma posición a la que ha
llegado.
Para evitar este bucle de comentarios, el método OnElementPropertyChanged solo llama a Seek cuando la diferencia
entre la propiedad Position y la posición actual del AVPlayer es mayor que un segundo.
Establecer y obtener la posición en Android
Al igual que en el representador de iOS, el VideoPlayerRenderer de Android establece un valor nuevo para la
propiedad Position en el controlador OnUpdateStatus . La propiedad CurrentPosition de VideoView contiene la
posición nueva en unidades de milisegundos:
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);
}
···
}
}
Además, al igual que en el representador de iOS, el representador de Android llama al método SeekTo de
VideoView cuando la propiedad Position ha cambiado, pero solo cuando el cambio y el valor CurrentPosition de
VideoView difieren en más de un segundo:
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);
}
}
}
···
}
}
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);
}
···
}
}
void SetTimeToEnd()
{
TimeToEnd = Duration - Position;
}
···
}
}
El método SetTimeToEnd se llama desde los controladores de cambio de propiedad de Duration y Position .
public PositionSlider()
{
PropertyChanged += (sender, args) =>
{
if (args.PropertyName == "Value")
{
TimeSpan newPosition = TimeSpan.FromSeconds(Value);
El controlador de cambio de propiedad para la propiedad Duration establece la propiedad Maximum del Slider
subyacente en la propiedad TotalSeconds del valor TimeSpan . De forma similar, el controlador de cambio de
propiedad para Position establece la propiedad Value del Slider . De esta manera, el Slider subyacente realiza
un seguimiento de la posición del PositionSlider .
PositionSlider se actualiza desde el Slider subyacente en una única instancia: cuando el usuario manipula el
Slider para indicar que el vídeo debe avanzar o retroceder a una posición nueva. Esto se detecta en el controlador
PropertyChanged en el constructor del PositionSlider . El controlador comprueba si hay algún cambio en la
propiedad Value y, si es diferente de la propiedad Position , la propiedad Position se establece desde la
propiedad Value .
En teoría, la instrucción if interna podría escribirse así:
if (newPosition.Seconds != Position.Seconds)
{
Position = newPosition;
}
Sin embargo, la implementación de Slider en Android solo tiene 1000 pasos discretos, independientemente de la
configuración de Minimum y Maximum . Si la longitud de un vídeo fuera mayor que 1000 segundos, dos valores
Position diferentes se corresponderían a la misma configuración de Value del Slider , y esta instrucción if
desencadenaría un falso positivo de una manipulación de usuario del Slider . En su lugar, es más seguro
comprobar que las posiciones nueva y existente son mayores que una centésima de la duración total.
Utilizar el PositionSlider
La documentación del MediaElement de UWP advierte sobre el enlace a la propiedad Position porque la
propiedad se actualiza con frecuencia. La documentación recomienda que se utilice un temporizador para
consultar la propiedad Position .
Esa es una buena recomendación, pero las tres clases VideoPlayerRenderer ya utilizan indirectamente un
temporizador para actualizar la propiedad Position . La propiedad Position se cambia en un controlador para el
evento UpdateStatus , que se activa solo 10 veces por segundo.
Por tanto, la propiedad Position del VideoPlayer puede enlazarse a la propiedad Position del PositionSlider
sin problemas de rendimiento, como se muestra en la página Barra de posición 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}">
···
<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>
Los primeros puntos suspensivos (···) ocultan el ActivityIndicator ; es el mismo que en la página anterior
Transporte personalizado. Tenga en cuenta los dos elementos Label que muestran las propiedades Position y
TimeToEnd . Los puntos suspensivos entre esos dos elementos Label ocultan los dos elementos Button que
aparecen en la página Transporte personalizado para reproducir, hacer pausa y detener. La lógica de código
subyacente también es la misma que la de la página Transporte personalizado.
Con esto concluye la explicación de VideoPlayer .
Vínculos relacionados
Demostraciones de reproductor de vídeo (ejemplo)
Enlace de datos de Xamarin.Forms
11/07/2019 • 5 minutes to read • Edit Online
Descargar el ejemplo
El enlace de datos es la técnica que consiste en vincular las propiedades de dos objetos para que los cambios
en una propiedad se reflejen automáticamente en la otra propiedad. El enlace de datos es una parte integral
de la arquitectura de aplicación Model-View -ViewModel (MVVM ).
Enlaces básicos
Conozca la diferencia entre el origen y el destino del enlace de datos y vea enlaces de datos sencillos en código
y en XAML.
Modo de enlace
Descubra cómo el modo de enlace puede controlar el flujo de datos entre los dos objetos.
Formato de cadena
Use un enlace de datos para dar formato y mostrar objetos como cadenas.
Interfaz de comandos
Implemente la propiedad Command con los enlaces de datos.
Enlaces compilados
Use enlaces compilados para mejorar el rendimiento del enlace de datos.
Vínculos relacionados
Data Binding Demos (sample) (Demos de enlace de datos [ejemplo])
Capítulo sobre enlace de datos del libro de Xamarin.Forms
Extensiones de marcado XAML
Enlaces básicos de Xamarin.Forms
11/07/2019 • 19 minutes to read • Edit Online
Descargar el ejemplo
Un enlace de datos de Xamarin.Forms enlaza un par de propiedades entre dos objetos, del que al menos uno suele
ser un objeto de interfaz de usuario. Estos dos objetos se denominan el destino y el origen:
El destino es el objeto (y la propiedad) en la que se establece el enlace de datos.
El origen es el objeto (y la propiedad) al que hace referencia el enlace de datos.
Esta distinción a veces puede ser un poco confusa: en el caso más simple, los datos fluyen desde el origen al
destino, lo que significa que el valor de la propiedad de destino se establece en el valor de la propiedad de origen.
Pero en algunos casos, los datos también pueden fluir desde el destino al origen, o en ambas direcciones. Para
evitar confusiones, tenga en cuenta que el destino siempre es el objeto en el que se establece el enlace de datos,
incluso si ofrece datos en lugar de recibirlos.
<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>
El elemento Slider se establece para un intervalo de 0 a 360. El propósito de este programa es girar el elemento
Label mediante la manipulación de Slider .
Sin los enlaces de datos, se establecería el evento ValueChanged del elemento Slider en un controlador de
eventos que accede a la propiedad Value del elemento Slider y establece ese valor en la propiedad Rotation
del elemento Label . El enlace de datos automatiza ese trabajo; el controlador de eventos y el código que contiene
ya no son necesarios.
Puede establecer un enlace en una instancia de cualquier clase que se derive de BindableObject , lo que incluye las
derivadas Element , VisualElement , View y View . El enlace siempre se establece en el objeto de destino. El enlace
hace referencia al objeto de origen. Para establecer el enlace de datos, use los dos miembros siguientes de la clase
de destino:
La propiedad BindingContext especifica el objeto de origen.
El método SetBinding especifica la propiedad de destino y la de origen.
En este ejemplo, Label es el destino de enlace y Slider es el origen de enlace. Los cambios en el origen de
Slider afectan a la rotación del destino de Label . Los datos fluyen del origen al destino.
El método SetBinding definido por BindableObject tiene un argumento de tipo BindingBase del que se deriva la
clase Binding , pero existen otros métodos SetBinding definidos por la clase BindableObjectExtensions . En el
archivo de código subyacente del ejemplo Enlace de código básico se usa un método de extensión SetBinding
más sencillo de esta clase.
label.BindingContext = slider;
label.SetBinding(Label.RotationProperty, "Value");
}
}
El objeto Label es el destino de enlace, por lo que es el objeto en el que se establece esta propiedad y en el que se
llama al método. La propiedad BindingContext indica el origen de enlace, que es el elemento Slider .
El método SetBinding se llama en el destino de enlace, pero especifica tanto la propiedad de destino como la de
origen. La propiedad de destino se especifica como un objeto BindableProperty : Label.RotationProperty . La
propiedad de origen se especifica como una cadena e indica la propiedad Value de Slider .
El método SetBinding revela una de las reglas de enlaces de datos más importantes:
La propiedad de destino debe estar respaldada por una propiedad enlazable.
Esta regla implica que el objeto de destino debe ser una instancia de una clase que se derive de BindableObject .
Vea el artículo Propiedades enlazables para obtener información general sobre los objetos y las propiedades
enlazables.
No hay ninguna regla de este tipo para la propiedad de origen, que se especifica como una cadena. De forma
interna, se usa la reflexión para acceder a la propiedad real. Pero en este caso concreto, la propiedad Value
también está respaldada por una propiedad enlazable.
El código se puede simplificar ligeramente: la propiedad enlazable RotationProperty se define mediante
VisualElement , y también la heredan Label y ContentPage , por lo que no es necesario el nombre de clase en la
llamada a SetBinding :
label.SetBinding(RotationProperty, "Value");
Pero la inclusión del nombre de clase es un buen recordatorio del objeto de destino.
Al manipular el elemento Slider , el elemento Label gira según corresponda:
La página Enlace Xaml básico es idéntica a la página Enlace de código básico, con la excepción de que define
el enlace de datos completo en 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>
Al igual que en el código, el enlace de datos se establece en el objeto de destino, que es el elemento Label .
Intervienen dos extensiones de marcado XAML. Son reconocibles al instante por los delimitadores de llave:
La extensión de marcado x:Reference es necesaria para hacer referencia al objeto de origen, que es el
elemento Slider denominado slider .
La extensión de marcado Binding enlaza la propiedad Rotation de Label a la propiedad Value de Slider .
Vea el artículo Extensiones de marcado XAML para obtener más información sobre las extensiones de marcado
XAML. La extensión de marcado x:Reference es compatible con la clase ReferenceExtension ; Binding es
compatible con la clase BindingExtension . Como indican los prefijos de espacio de nombres XML, x:Reference
forma parte de la especificación 2009 de XAML, mientras que Binding forma parte de Xamarin.Forms. Observe
que no aparecen comillas entre las llaves.
Es fácil olvidar la extensión de marcado x:Reference cuando se establece el valor BindingContext . Un error
habitual es establecer la propiedad directamente en el nombre del origen de enlace, como en este caso:
BindingContext="slider"
Pero eso no es correcto. Ese marcado establece la propiedad BindingContext en un objeto string cuyos
caracteres deletrean "slider".
Observe que la propiedad de origen se especifica con la propiedad Path de BindingExtension , que se
corresponde con la propiedad Path de la clase Binding .
El marcado que se muestra en la página Basic XAML Binding (Enlace XAML básico) se puede simplificar: en las
extensiones de marcado XAML como x:Reference y Binding se pueden definir atributos de propiedad de
contenido, lo que para las extensiones de marcado XAML significa que no es necesario que aparezca el nombre de
propiedad. La propiedad Name es la propiedad de contenido de x:Reference y la propiedad Path es la propiedad
de contenido de Binding , lo que significa que se pueden eliminar de las expresiones:
<Label Text="TEXT"
FontSize="80"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
BindingContext="{x:Reference slider}"
Rotation="{Binding Value}" />
<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>
El archivo de código subyacente establece el enlace con el método SetBinding definido por el objeto
BindableObject . El argumento es un constructor para la clase Binding :
public partial class AlternativeCodeBindingPage : ContentPage
{
public AlternativeCodeBindingPage()
{
InitializeComponent();
El constructor Binding tiene seis parámetros, por lo que el parámetro source se especifica con un argumento con
nombre. El argumento es el objeto slider .
La ejecución de este programa podría ser un poco sorprendente:
En la pantalla de iOS de la izquierda se muestra el aspecto de la pantalla cuando aparece la página por primera
vez. ¿Dónde está el elemento Label ?
El problema es que el elemento Slider tiene un valor inicial de 0. Esto hace que la propiedad Scale de Label
también se establezca en 0, y se reemplace su valor predeterminado de 1. Como resultado, el elemento Label es
invisible inicialmente. Como se muestra en las capturas de pantalla de Android y Plataforma Universal de
Windows (UWP ), el elemento Slider se puede manipular para que Label aparezca de nuevo, pero su
desaparición inicial es desconcertante.
En el artículo siguiente verá cómo evitar este problema si inicializa el elemento Slider a partir del valor
predeterminado de la propiedad Scale .
NOTE
La clase VisualElement también define las propiedades ScaleX y ScaleY , que pueden escalar el elemento
VisualElement de forma diferente en dirección horizontal y vertical.
<Slider x:Name="slider"
Minimum="-2"
Maximum="2"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
Ahora la extensión de marcado Binding tiene dos propiedades establecidas, Source y Path , separadas por una
coma. Si lo prefiere, pueden aparecer en la misma línea:
La propiedad Source se establece en una extensión de marcado x:Reference insertada que, en caso contrario,
tiene la misma sintaxis que la configuración de BindingContext . Observe que no aparecen comillas dentro de las
llaves, y que las dos propiedades se deben separar por una coma.
La propiedad de contenido de la extensión de marcado Binding es Path , pero la parte Path= de la extensión de
marcado solo se puede eliminar si es la primera propiedad en la expresión. Para eliminar la parte Path= , es
necesario intercambiar las dos propiedades:
Aunque las extensiones de marcado XAML suelen estar delimitadas por llaves, también se pueden expresar 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>
Ahora las propiedades Source y Path son atributos XAML normales: los valores aparecen entre comillas y los
atributos no están separados por una coma. La extensión de marcado x:Reference también se puede convertir en
un 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>
Esta sintaxis no es común, pero a veces es necesaria cuando hay objetos complejos implicados.
En los ejemplos mostrados hasta ahora se establecen las propiedades BindingContext y Source de Binding en
una extensión de marcado x:Reference para hacer referencia a otra vista en la página. Estas dos propiedades son
de tipo Object , y se pueden establecer en cualquier objeto que incluya propiedades adecuadas para los orígenes
de enlace.
En los artículos siguientes, descubrirá que puede establecer la propiedad BindingContext o Source en una
extensión de marcado x:Static para hacer referencia al valor de una propiedad estática o un campo, o bien en
una extensión de marcado StaticResource para hacer referencia a un objeto almacenado en un diccionario de
recursos, o directamente en un objeto, que suele ser (pero no siempre) una instancia de una clase ViewModel.
La propiedad BindingContext se puede establecer en un objeto Binding para que las propiedades Source y
Path de Binding definan el contexto de enlace.
<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>
La propiedad BindingContext de StackLayout se establece en el objeto slider . Label y BoxView heredan este
contexto de enlace, y en los dos sus propiedades Rotation se establecen en la propiedad Value del elemento
Slider :
En el artículo siguiente, verá cómo el modo de enlace puede cambiar el flujo de datos entre los objetos de origen y
destino.
Vínculos relacionados
Data Binding Demos (sample) (Demos de enlace de datos [ejemplo])
Capítulo sobre enlace de datos del libro de Xamarin.Forms
Vídeo relacionado
Encuentre más vídeos de Xamarin en Channel 9 y YouTube.
Modo de enlace de Xamarin.Forms
11/07/2019 • 28 minutes to read • Edit Online
Descargar el ejemplo
En el artículo anterior, las páginas Enlace de código alternativo y Enlace XAML alternativo contenían un
objeto Label con su propiedad Scale enlazada a la propiedad Value de un elemento Slider . Como el valor
inicial de Slider es 0, la propiedad Scale de Label se establece en 0 en lugar de 1, y el elemento Label
desaparece.
En el ejemplo DataBindingDemos, la página Enlace inverso es similar a los programas del artículo anterior,
salvo que el enlace de datos se define en Slider en lugar de 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 primera vista, esto podría parecer al contrario: ahora Label es el origen de enlace de datos y Slider es el
destino. El enlace hace referencia a la propiedad Opacity de Label , que tiene un valor predeterminado de 1.
Como cabría esperar, Slider se inicializa en el valor 1 a partir del valor Opacity inicial de Label . Esto se
muestra en la captura de pantalla de iOS de la izquierda:
Pero es posible que le sorprenda que Slider siga funcionando, como se muestra en las capturas de pantalla de
Android y UWP. Esto parece sugerir que el enlace de datos funciona mejor cuando Slider es el destino de
enlace en lugar de Label , porque la inicialización funciona de la forma esperada.
La diferencia entre el ejemplo Enlace inverso y los ejemplos anteriores implica el modo de enlace.
Estas propiedades concretas se definen como TwoWay por una muy buena razón:
Cuando los enlaces de datos se usan con la arquitectura de aplicación Model-View -ViewModel (MVVM ), la clase
ViewModel es el origen del enlace de datos y la vista, que consta de vistas como Slider , son destinos de enlace
de datos. Los enlaces de MVVM son más similares al ejemplo Enlace inverso que los enlaces de los ejemplos
anteriores. Es muy probable que quiera que cada vista de la página se inicialice con el valor de la propiedad
correspondiente en el modelo de vista, pero los cambios en la vista también deberían afectar a la propiedad
ViewModel.
Las propiedades con modos de enlace predeterminados de TwoWay son las que probablemente se usen más en
escenarios de MVVM.
Enlaces unidireccionales al origen
Las propiedades enlazables de solo lectura tienen un modo de enlace predeterminado de OneWayToSource . Solo
hay una propiedad enlazable de lectura y escritura que tiene un modo de enlace predeterminado de
OneWayToSource :
La razón es que el resultado de un enlace en la propiedad SelectedItem debe ser el establecimiento del origen de
enlace. En un ejemplo posterior de este artículo se invalida este comportamiento.
Enlaces de un solo uso
Varias propiedades enlazables tienen un modo de enlace predeterminado de OneTime , que incluye la propiedad
IsTextPredictionEnabled de Entry .
Las propiedades de destino con un modo de enlace de OneTime solo se actualizan cuando cambia el contexto de
enlace. Para los enlaces en estas propiedades de destino, esto simplifica la infraestructura de enlace ya que no es
necesario supervisar los cambios en las propiedades de origen.
Name = NamedColor.GetNearestColorName(color);
}
}
get
{
return color;
}
}
Cuando cambia la propiedad Color , el método estático GetNearestColorName de la clase NamedColor (incluido
también en la solución DataBindingDemos)obtiene el color con nombre más cercano y establece la propiedad
Name . Esta propiedad Name tiene un descriptor de acceso set privado, por lo que no se puede establecer desde
fuera de la clase.
Cuando se establece una clase ViewModel como un origen de enlace, la infraestructura de enlace adjunta un
controlador al evento PropertyChanged . De esta manera, el enlace puede recibir una notificación de cambios en
las propiedades y, después, puede establecer las propiedades de destino a partir de los valores cambiados.
Pero cuando una propiedad de destino (o la definición Binding en una propiedad de destino) tiene un elemento
BindingMode de tipo OneTime , no es necesario que la infraestructura de enlace adjunte un controlador al evento
PropertyChanged . La propiedad de destino solo se actualiza cuando cambia BindingContext y no cuando cambia
la propiedad de origen.
El archivo XAML Selector de colores simple crea una instancia de HslColorViewModel en el diccionario de
recursos de la página e inicializa la propiedad Color . La propiedad BindingContext de Grid se establece en una
extensión de enlace StaticResource para hacer referencia a ese 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>
<StackLayout Grid.Row="1"
Margin="10, 0">
Los elementos BoxView , Label y tres vistas Slider heredan el contexto de enlace del elemento Grid . Todas
estas vistas son destinos de enlace que hacen referencia a las propiedades de origen en el modelo de vista. Para
la propiedad Color de BoxView y la propiedad Text de Label , los enlaces de datos son OneWay : Las
propiedades de la vista se establecen de las propiedades de ViewModel.
Pero la propiedad Value de Slider es TwoWay . Esto permite que cada elemento Slider se establezca a partir
del modelo de vista, y también que el modelo de vista se establezca a partir de cada elemento Slider .
Cuando se ejecuta por primera vez el programa, BoxView , Label y los tres elementos Slider están establecidos
a partir del modelo de vista en función de la propiedad Color inicial establecida cuando se creó la instancia del
modelo de vista. Esto se muestra en la captura de pantalla de iOS de la izquierda:
Al manipular los controles deslizantes, se actualizan BoxView y Label en consecuencia, como se muestra en las
capturas de pantalla de Android y UWP.
Un enfoque común consiste en crear instancias de ViewModel en el diccionario de recursos. También se pueden
crear instancias de ViewModel dentro de etiquetas de elemento de propiedad para la propiedad BindingContext .
En el archivo XAML Selector de colores simple, intente quitar HslColorViewModel del diccionario de recursos y
establézcalo en la propiedad BindingContext de Grid de esta forma:
<Grid>
<Grid.BindingContext>
<local:HslColorViewModel Color="MediumTurquoise" />
</Grid.BindingContext>
···
</Grid>
El contexto de enlace se puede establecer de varias formas. En ocasiones, el archivo de código subyacente crea
una instancia de ViewModel y la establece en la propiedad BindingContext de la página. Todos estos enfoques
son válidos.
<Label Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Scale="{Binding Source={x:Reference slider},
Path=Value,
Mode=TwoWay}" />
Se podría esperar que Slider se inicializara en el valor inicial de la propiedad Scale , que es 1, pero no es lo que
sucede. Cuando se inicializa un enlace TwoWay , primero se establece el destino a partir del origen, lo que significa
que la propiedad Scale se establece en el valor predeterminado de Slider de 0. Cuando se configura el enlace
TwoWay en el elemento Slider , el elemento Slider se establece inicialmente a partir del origen.
<Label Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Scale="{Binding Source={x:Reference slider},
Path=Value,
Mode=OneWayToSource}" />
Ahora se inicializa Slider en 1 (el valor predeterminado de Scale ) pero la manipulación de Slider no afecta a
la propiedad Scale , por lo que esto no es muy útil.
NOTE
La clase VisualElement también define las propiedades ScaleX y ScaleY , que pueden escalar el elemento
VisualElement de forma diferente en dirección horizontal y vertical.
Una aplicación muy útil de la invalidación del modo de enlace predeterminado con TwoWay implica la propiedad
SelectedItem de ListView . El modo de enlace predeterminado es OneWayToSource . Cuando se establece un
enlace de datos en la propiedad SelectedItem para hacer referencia a una propiedad de origen en un modelo de
vista, esa propiedad de origen se establece a partir de la selección ListView . Pero en algunas circunstancias, es
posible que le interese que también se inicialice ListView a partir del modelo de vista.
En la página Configuración de ejemplo se muestra esta técnica. Esta página representa una implementación
simple de la configuración de la aplicación, que a menudo se define en un modelo de vista, como en este archivo
SampleSettingsViewModel :
storage = value;
OnPropertyChanged(propertyName);
return true;
}
// Static members
static NamedColor()
{
List<NamedColor> all = new List<NamedColor>();
StringBuilder stringBuilder = new StringBuilder();
En la clase del proyecto DataBindingDemos se define una propiedad denominada Settings de tipo
App
SampleSettingsViewModel . Esta propiedad se inicializa cuando se crea una instancia de la clase App y el método
SaveState se llama cuando se llama al método OnSleep :
public partial class App : Application
{
public App()
{
InitializeComponent();
Para obtener más información sobre los métodos de ciclo de vida de aplicación, vea el artículo Ciclo de vida de
aplicación.
Prácticamente todo lo demás se controla en el archivo SampleSettingsPage.xaml. El elemento BindingContext
de la página se establece mediante una extensión de marcado Binding : el origen de enlace es la propiedad
estática Application.Current , que es la instancia de la clase App del proyecto, y Path se establece en la
propiedad Settings , que es el 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 Orientation="Horizontal">
<Label Text="Name: "
VerticalOptions="Center" />
<StackLayout Orientation="Horizontal">
<Label Text="Birth Date: "
VerticalOptions="Center" />
<StackLayout Orientation="Horizontal">
<Label Text="Do you code in C#? "
VerticalOptions="Center" />
<StackLayout Orientation="Horizontal">
<Label Text="Number of Copies: "
VerticalOptions="Center" />
<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" />
Todos los elementos secundarios de la página heredan el contexto de enlace. La mayoría de los demás enlaces de
esta página son para las propiedades de SampleSettingsViewModel . La propiedad BackgroundColor se usa para
establecer la propiedad BackgroundColor de StackLayout , y las propiedades Entry , DatePicker , Switch y
Stepper se enlazan a otras propiedades del modelo de vista.
if (colorListView.SelectedItem != null)
{
colorListView.ScrollTo(colorListView.SelectedItem,
ScrollToPosition.MakeVisible,
false);
}
}
}
En la captura de pantalla de iOS de la izquierda se muestra el programa al ejecutarlo por primera vez. El
constructor de SampleSettingsViewModel inicializa el color de fondo en blanco, y eso es lo que está seleccionado
en ListView :
La otra captura de pantalla muestra la configuración modificada. Al experimentar con esta página, recuerde
colocar el programa en modo de suspensión o finalícelo en el dispositivo o emulador que se está ejecutando. La
finalización del programa desde el depurador de Visual Studio no provocará que se llame a la invalidación de
OnSleep en la clase App .
En el artículo siguiente verá cómo especificar los formatos de cadena de los enlaces de datos que se establecen
en la propiedad Text de Label .
Vínculos relacionados
Data Binding Demos (sample) (Demos de enlace de datos [ejemplo])
Capítulo sobre enlace de datos del libro de Xamarin.Forms
Formato de cadena de Xamarin.Forms
11/07/2019 • 8 minutes to read • Edit Online
Descargar el ejemplo
A veces es conveniente usar enlaces de datos para mostrar la representación de cadena de un objeto o valor. Por
ejemplo, es posible que quiera utilizar una Label para mostrar el valor actual de un Slider . En este enlace de
datos, Slider es el origen y el destino es la propiedad Text de Label .
Cuando se muestran las cadenas en el código, la herramienta más eficaz es el método String.Format estático. La
cadena de formato incluye códigos específicos para distintos tipos de objetos de formato, y puede incluir otros
textos junto con los valores a los que se va a aplicar formato. Para obtener más información sobre el formato de
cadena, vea Aplicar formato a tipos en .NET.
La propiedad StringFormat
Este recurso se transmite a los enlaces de datos: usted establece la propiedad StringFormat de Binding (o la
propiedad StringFormat de la extensión de marcado Binding ) a una cadena de formato .NET estándar con un
marcador de posición:
Tenga en cuenta que la cadena de formato está delimitada por caracteres de comillas simples (apóstrofo) para
ayudar al analizador XAML a evitar que trate las llaves como otra extensión de marcado XAML. En caso contrario,
esa cadena sin el carácter de comillas simples es la misma cadena que utilizaría para mostrar un valor de punto
flotante en una llamada a String.Format . Una especificación de formato de F2 hace que el valor se muestre con
dos posiciones decimales.
La propiedad StringFormat sólo tiene sentido cuando la propiedad de destino es de tipo string , y el modo de
enlace es OneWay o TwoWay . Para los enlaces bidireccionales, el StringFormat solo es aplicable para los valores
que se pasan desde el origen al destino.
Como verá en el artículo Xamarin.Forms Binding Path (Ruta de acceso de Xamarin.Forms), los enlaces de datos
pueden llegar a ser bastante complejos y enrevesados. Al depurar estos enlaces de datos, puede agregar una
Label en el archivo XAML con un StringFormat para mostrar algunos resultados intermedios. Puede resultar
útil incluso si se usa solo para mostrar un tipo de objeto.
La página Formato de cadena muestra varios usos de la propiedad 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 />
<BoxView />
<BoxView />
<BoxView />
Los enlaces en el Slider y el TimePicker muestran el uso de las especificaciones de formato específicas de los
tipos de datos double y TimeSpan . El StringFormat que muestra el texto de la vista Entry muestra cómo
especificar las comillas dobles en la cadena de formato con el uso de la entidad HTML " .
La siguiente sección en el archivo XAML es un StackLayout con un BindingContext establecido en una extensión
de marcado de x:Static que hace referencia a la propiedad DateTime.Now estática. El primer enlace no tiene
propiedades:
Esto muestra simplemente el valor DateTime de BindingContext con el formato predeterminado. El segundo
enlace muestra la propiedad Ticks de DateTime , mientras que los otros dos enlaces muestran el propio
DateTime con un formato específico. Observe este StringFormat :
Si necesita mostrar llaves a la izquierda o la derecha en la cadena de formato, simplemente use un par de ellas.
Los conjuntos de la última sección establecen el BindingContext al valor de Math.PI y lo muestran con formato
de forma predeterminada y dos tipos diferentes de formato numérico.
Esta es la ejecución del programa:
<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>
Ahora hay tres pares de elementos Slider y Label que están enlazados a la misma propiedad de origen en el
objeto HslColorViewModel . La única diferencia es que Label tiene una propiedad StringFormat para mostrar
cada valor Slider .
Tal vez se pregunte cómo podría mostrar sus valores RGB (rojos, verdes y azules) en formato hexadecimal de dos
dígitos tradicional. Los valores enteros no están directamente disponibles desde la estructura de Color . Una
solución sería calcular valores enteros de los componentes de color dentro de ViewModel y exponerlos como
propiedades. Después puede aplicarles formato utilizando la especificación de formato X2 .
Otro enfoque es más general: puede escribir un convertidor de valores de enlace como se describe en el siguiente
artículo, Convertidor de valores de enlace de Xamarin.Forms.
Empero, el siguiente artículo explora la Ruta de enlace con más detalle y muestra cómo se puede utilizar para
hacer referencia a elementos de las colecciones y subpropiedades.
Vínculos relacionados
Data Binding Demos (sample) (Demos de enlace de datos [ejemplo])
Capítulo sobre enlace de datos del libro de Xamarin.Forms
Ruta de acceso de enlace de Xamarin.Forms
11/07/2019 • 7 minutes to read • Edit Online
Descargar el ejemplo
En todos los ejemplos de enlace de datos anteriores, la propiedad Path de la clase Binding (o la propiedad
Path de la extensión de marcado Binding ) se había establecido en una sola propiedad. En realidad es posible
establecer Path en una subpropiedad (una propiedad de una propiedad), o bien en un miembro de una
colección.
Por ejemplo, suponga que la página contiene un control TimePicker :
<TimePicker x:Name="timePicker">
La propiedad Time de TimePicker es de tipo TimeSpan , pero es posible que quiera crear un enlace de datos que
haga referencia a la propiedad TotalSeconds de ese valor TimeSpan . Este es el enlace de datos:
La propiedad Time es de tipo TimeSpan , que tiene una propiedad TotalSeconds . Las propiedades Time y
TotalSeconds se conectan simplemente con un punto. Los elementos de la cadena Path siempre hacen
referencia a propiedades y no a los tipos de estas propiedades.
Ese y otros muchos ejemplos se muestran en la página Variaciones de la ruta de acceso:
<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>
<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>
En el segundo control Label , el origen de enlace es la propia página. La propiedad Content es de tipo
StackLayout , que tiene una propiedad Children de tipo IList<View> , que a su vez tiene una propiedad Count
que indica el número de elementos secundarios.
<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>
Vea Pasar argumentos de constructor para obtener más información sobre cómo especificar argumentos de
constructor en XAML.
El último ejemplo es similar al segundo, salvo que hace referencia a uno de los elementos secundarios del
elemento StackLayout :
Ese elemento secundario es un control Label , que tiene una propiedad Text de tipo String , que a su vez tiene
una propiedad Length . El primer objeto Label notifica el valor TimeSpan establecido en el elemento TimePicker ,
de modo que cuando se cambia el texto, el último objeto Label también cambia.
Esta es la ejecución del programa:
Depuración de rutas de acceso complejas
Las definiciones de ruta de acceso complejas pueden ser difíciles de construir: necesita saber el tipo de cada
subpropiedad o el tipo de los elementos de la colección para agregar correctamente la subpropiedad siguiente,
pero los propios tipos no aparecen en la ruta de acceso. Una técnica adecuada consiste en crear la ruta de acceso
de forma incremental y observar los resultados intermedios. Para ese último ejemplo, se podría empezar sin
ninguna definición de Path :
Eso muestra el tipo del origen de enlace, o DataBindingDemos.PathVariationsPage . Ya sabe que PathVariationsPage
se deriva de ContentPage , por lo que tiene una propiedad Content :
A medida que Xamarin.Forms procesa la ruta de acceso de enlace, instala un controlador PropertyChanged en
todos los objetos de la ruta de acceso que implementen la interfaz INotifyPropertyChanged . Por ejemplo, el enlace
final reacciona ante un cambio en el primer objeto Label porque cambia la propiedad Text .
Si una propiedad en la ruta de acceso de enlace no implementa INotifyPropertyChanged , se omitirán todos los
cambios a esa propiedad. Algunos cambios podrían invalidar completamente la ruta de acceso de enlace, por lo
que solo debe usar esta técnica cuando la cadena de propiedades y subpropiedades nunca sea no válida.
Vínculos relacionados
Data Binding Demos (sample) (Demos de enlace de datos [ejemplo])
Capítulo sobre enlace de datos del libro de Xamarin.Forms
Convertidor de valores de enlace de Xamarin.Forms
11/07/2019 • 18 minutes to read • Edit Online
Descargar el ejemplo
Los enlaces de datos normalmente transfieren datos desde una propiedad de origen a una propiedad de destino y,
en algunos casos, desde la propiedad de destino a la propiedad de origen. Esta transferencia es sencilla cuando las
propiedades de origen y destino son del mismo tipo, o cuando un tipo se puede convertir al otro mediante una
conversión implícita. Cuando no es así, debe realizarse una conversión de tipos.
En el artículo String Formatting (Formato de cadena), vio cómo puede usar la propiedad StringFormat de un
enlace de datos para convertir cualquier tipo en una cadena. Para otros tipos de conversiones, deberá escribir
código especializado en una clase que implementa la interfaz de IValueConverter . (La Plataforma universal de
Windows contiene una clase similar denominada IValueConverter en el espacio de nombres
Windows.UI.Xaml.Data , pero este IValueConverter está en el espacio de nombres Xamarin.Forms .) Las clases que
implementan IValueConverter se denominan convertidores de valores, pero también se denominan a menudo
convertidores de enlaces o convertidores de valores de enlace.
La interfaz de IValueConverter
Suponga que desea definir un enlace de datos cuya propiedad de origen es del tipo int pero la propiedad de
destino es un bool . Desea que este enlace de datos genere un valor false cuando el origen del entero es igual a
0 y true en caso contrario.
Puede hacerlo con una clase que implementa la interfaz IValueConverter :
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return (bool)value ? 1 : 0;
}
}
Establezca una instancia de esta clase en la propiedad Converter de la clase Binding o en la propiedad
Converter de la extensión de marcado Binding . Esta clase se convierte en parte del enlace de datos.
Se llama al método Convert cuando los datos se mueven desde el origen al destino en los enlaces OneWay o
TwoWay . El parámetro value es el objeto o el valor del origen de enlace de datos. El método debe devolver un
valor del tipo del destino de enlace de datos. El método que se muestra aquí convierte el parámetro value a un
int y después lo compara con 0 para un valor devuelto bool .
Se llama al método ConvertBack cuando los datos se mueven desde el destino al origen en los enlaces TwoWay o
OneWayToSource . ConvertBack realiza la conversión opuesta: supone que el parámetro value es un bool desde el
destino y lo convierte en un valor devuelto int para el origen.
Si el enlace de datos también incluye una configuración StringFormat , se invoca el convertidor de valores antes
de que se le dé formato de cadena al resultado.
La página Enable Buttons (Habilitar botones) en el ejemplo de Data Binding Demos (Demostraciones de
enlace de datos) muestra cómo utilizar este convertidor de valores en un enlace de datos. Se crea una instancia de
IntToBoolConverter en el diccionario de recursos de la página. Después se le hace referencia con una extensión de
marcado StaticResource para establecer la propiedad Converter en dos enlaces de datos. Es muy común
compartir los convertidores de tipos de datos entre varios enlaces de datos en la 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>
<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>
Si se usa un convertidor de valores en varias páginas de la aplicación, puede crear una instancia de él en el
diccionario de recursos en el archivo App.xaml.
La página Enable Buttons (Habilitar botones) muestra una necesidad común cuando un Button realiza una
operación basada en texto que el usuario escribe en un vista Entry . Si no se ha escrito nada en el Entry , el
Button debe deshabilitarse. Cada Button contiene un enlace de datos en su propiedad IsEnabled . El origen de
enlace de datos es la propiedad Length de la propiedad Text de la Entry correspondiente. Si esa propiedad
Length no es 0, el convertidor de valores devuelve true y se habilita el Button :
Tenga en cuenta que la propiedad Text en cada Entry se inicializa en una cadena vacía. La propiedad Text es
null de forma predeterminada, y los datos de enlace no funcionarán en ese caso.
Algunos convertidores de valores se escriben específicamente para determinadas aplicaciones, mientras que otros
están generalizados. Si sabe que un convertidor de valores solo se usará en los enlaces OneWay , el método
ConvertBack puede devolver simplemente null .
El método Convert mostrado anteriormente supone implícitamente que el argumento value es de tipo int y el
valor devuelto debe ser de tipo bool . De forma similar, el método ConvertBack supone que el argumento value
es de tipo bool y el valor devuelto es int . Si no es así, se producirá una excepción en tiempo de ejecución.
Puede escribir los convertidores de valores para que sean más generalizados y acepten diferentes tipos de datos.
Los métodos Convert y ConvertBack pueden usar los operadores as o is con el parámetro value , o pueden
llamar a GetType en ese parámetro para determinar su tipo y después realizar algo adecuado. El tipo esperado del
valor devuelto de cada método viene dado por el parámetro targetType . A veces, los convertidores de valores se
utilizan con los enlaces de datos de diferentes tipos de destino; el convertidor de valores puede usar el argumento
targetType para realizar una conversión del tipo correcto.
Si la conversión que se realiza es diferente para distintas referencias culturales, utilice el parámetro culture para
este propósito. El argumento parameter para Convert y ConvertBack se explica más adelante en este artículo.
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);
}
}
La página Switch Indicators (Indicadores de conmutador) muestra cómo puede usarse para mostrar el valor de
una vista Switch . Aunque es común crear instancias de los convertidores de valores como recursos en un
diccionario de recursos, esta página muestra una alternativa: se crea una instancia de cada convertidor de valores
entre etiquetas de elemento de propiedad Binding.Converter . El x:TypeArguments indica el argumento genérico, y
TrueObject y FalseObject se establecen en objetos de ese 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 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>
En el último de los tres pares Switch y Label , el argumento genérico se establece en Style y se proporcionan
objetos Style completos para los valores de TrueObject y FalseObject . Esto ignora el estilo implícito para
Label que se establece en el diccionario de recursos, por lo que las propiedades de ese estilo están asignadas
explícitamente a la Label . Activar o desactivar el Switch hace que el correspondiente Label refleje el cambio:
También es posible usar Triggers para implementar cambios similares en la interfaz de usuario en función de
otras vistas.
Name = NamedColor.GetNearestColorName(color);
}
}
get
{
return color;
}
}
Las propiedades Red , Green y Blue oscilan entre 0 y 1. Con todo, es preferible que los componentes se
muestren como valores hexadecimales de dos dígitos.
Para mostrar estos elementos como valores hexadecimales en XAML, deben multiplicarse por 255, convertirse en
un entero y después debe aplicárseles formato con la especificación de "X2" en la propiedad StringFormat . Las
dos primeras tareas (multiplicar por 255 y convertir en un entero) pueden controlarse mediante el convertidor de
valores. Para hacer el convertidor de valores tan generalizado como sea posible, puede especificarse el factor de
multiplicación con la propiedad ConverterParameter , lo que significa que introduce los métodos Convert y
ConvertBack como el argumento parameter :
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return (int)value / GetParameter(parameter);
}
return 1;
}
}
El Convert convierte de un double a int al multiplicar por el valor parameter ; el ConvertBack divide el
argumento value entero entre parameter y devuelve un resultado double . (En el programa que se muestra
debajo, el convertidor de valores se usa solo en relación con el formato de cadenas, por lo que ConvertBack no se
usa.)
Es probable que el tipo del argumento parameter sea diferente en función de si se ha definido el enlace de datos
en el código o en XAML. Si la propiedad ConverterParameter de Binding se establece en código, es probable que
se establezca en un valor numérico:
binding.ConverterParameter = 255;
La propiedad ConverterParameter es de tipo Object , por lo que el compilador C# interpreta el literal 255 como un
entero y establece la propiedad en ese valor.
Pero en XAML es probable que el ConverterParameter se establezca de este modo:
El 255 parece un número, pero dado que ConverterParameter es de tipo Object , el analizador XAML trata el 255
como una cadena.
Por ese motivo, el convertidor de valores mostrado anteriormente incluye un método GetParameter
independiente que controla los casos para parameter de tipo double , int o string .
La página RGB Color Selector (Selector de colores RGB ) crea una instancia de la página DoubleToIntConverter
en su diccionario de recursos siguiendo la definición de dos 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>
<StackLayout>
<StackLayout.BindingContext>
<local:RgbColorViewModel Color="Gray" />
</StackLayout.BindingContext>
Los valores de las propiedades Red y Green se muestran con una extensión de marcado Binding . Empero, la
propiedad Blue crea una instancia de la clase Binding para demostrar cómo un valor double explícito puede
establecerse en la propiedad ConverterParameter .
Este es el resultado:
Vínculos relacionados
Data Binding Demos (sample) (Demos de enlace de datos [ejemplo])
Capítulo sobre enlace de datos del libro de Xamarin.Forms
Reservas de enlace de Xamarin.Forms
11/07/2019 • 7 minutes to read • Edit Online
Descargar el ejemplo
En ocasiones, los enlaces de datos producen errores, porque no se puede resolver el origen de enlace o porque el
enlace se realiza correctamente pero devuelve un valor null . Si bien estos escenarios se pueden controlar con los
convertidores de valor, u otro código adicional, los enlaces de datos pueden hacerse más sólidos mediante la
definición de valores de reserva para su uso si se produce un error en el proceso de enlace. Esto puede realizarse
mediante la definición de las propiedades FallbackValue y TargetNullValue en una expresión de enlace. Dado que
estas propiedades residen en la clase BindingBase , pueden usarse con enlaces, con enlaces compilados y con la
extensión de marcado Binding .
NOTE
El uso de las propiedades FallbackValue y TargetNullValue en una expresión de enlace es opcional.
El enlace en Label define un valor de FallbackValue que se establecerá en el destino si no se puede resolver el
origen del enlace. Por lo tanto, el valor definido por la propiedad FallbackValue se mostrará si la propiedad
Population no existe en el objeto enlazado. Tenga en cuenta que aquí, el valor de la propiedad FallbackValue está
delimitado por caracteres de comillas simples (apóstrofo).
En lugar de definir los valores de la propiedad FallbackValue en línea, se recomienda definirlos como recursos en
ResourceDictionary . La ventaja de este enfoque es que estos valores se definen una vez en una sola ubicación y
son localizables más fácilmente. Posteriormente, se pueden recuperar los recursos mediante la extensión de
marcado StaticResource :
NOTE
No es posible establecer la propiedad FallbackValue con una expresión de enlace.
IMPORTANT
Un convertidor de valores definido no se ejecuta en una expresión de enlace cuando la propiedad FallbackValue está
establecida.
Los enlaces en Image y Label definen valores TargetNullValue que se aplicará si la ruta de acceso de enlace
devuelve null . Por lo tanto, los valores definidos por las propiedades TargetNullValue se mostrarán para los
objetos de la colección donde las propiedades ImageUrl y Location no estén definidas. Tenga en cuenta que aquí,
los valores de la propiedad TargetNullValue están delimitados por caracteres de comillas simples (apóstrofo).
En lugar de definir los valores de la propiedad TargetNullValue en línea, se recomienda definirlos como recursos
en ResourceDictionary . La ventaja de este enfoque es que estos valores se definen una vez en una sola ubicación y
son localizables más fácilmente. Posteriormente, se pueden recuperar los recursos mediante la extensión de
marcado StaticResource :
<Image Source="{Binding ImageUrl, TargetNullValue={StaticResource fallbackImageUrl}}"
... />
<Label Text="{Binding Location, TargetNullValue={StaticResource locationUnknown}}"
... />
NOTE
No es posible establecer la propiedad TargetNullValue con una expresión de enlace.
Cuando la propiedad TargetNullValue no está establecida en una expresión de enlace, un valor de origen de null
se convertirá si se define un convertidor de valores, se le aplicará formato si se define StringFormat y, a
continuación, se establecerá el resultado en el destino. Sin embargo, cuando la propiedad TargetNullValue está
establecida, un valor de origen de null se convertirá si se ha definido un convertidor de valores, y si sigue siendo
null después de la conversión, el valor de la propiedad TargetNullValue está establecido en el destino.
IMPORTANT
No se aplicará formato a la cadena en una expresión de enlace cuando la propiedad TargetNullValue esté establecida.
Vínculos relacionados
Demos de enlace de datos (ejemplo)
La interfaz de comandos de Xamarin.Forms
11/07/2019 • 31 minutes to read • Edit Online
Descargar el ejemplo
En la arquitectura Model-View -ViewModel (MVVM ), los enlaces de datos se definen entre las propiedades de
ViewModel, que suele ser una clase que se deriva de INotifyPropertyChanged , y las propiedades en la vista, que
suele ser el archivo XAML. A veces, una aplicación tiene necesidades que van más allá de estos enlaces de
propiedad y solicita al usuario que inicie comandos que influyen en el modelo de vista. Por lo general, estos
comandos se señalizan mediante clics de botón o pulsaciones con el dedo, y tradicionalmente se procesan en el
archivo de código subyacente en un controlador para el evento Clicked del elemento Button o el evento
Tapped de un elemento TapGestureRecognizer .
La interfaz de comandos proporciona un enfoque alternativo para implementar comandos que se adapta mucho
mejor a la arquitectura MVVM. El propio modelo de vista puede contener comandos, que son métodos que se
ejecutan en respuesta a una actividad específica en la vista como un clic de Button . Los enlaces de datos se
definen entre estos comandos y el objeto Button .
Para permitir un enlace de datos entre un objeto Button y un ViewModel, el objeto Button define dos
propiedades:
Command de tipo System.Windows.Input.ICommand
CommandParameter de tipo Object
Para usar la interfaz de comandos, defina un enlace de datos que tenga como destino la propiedad Command del
objeto Button donde el origen sea una propiedad en el modelo de vista de tipo ICommand . El modelo de vista
contiene código asociado con la propiedad ICommand que se ejecuta cuando se hace clic en el botón. Puede
establecer CommandParameter en datos arbitrarios para distinguir entre varios botones si todos se enlazan a la
misma propiedad ICommand en el modelo de vista.
Las propiedades Command y CommandParameter también se definen mediante las clases siguientes:
MenuItem y, por tanto, ToolbarItem , que se deriva de MenuItem
TextCell y, por tanto, ImageCell , que se deriva de TextCell
TapGestureRecognizer
SearchBar define una propiedad SearchCommand de tipo ICommand y una propiedad SearchCommandParameter . La
propiedad RefreshCommand de ListView también es de tipo ICommand .
Todos estos comandos se pueden controlar en un modelo de vista de forma que no dependa del objeto de
interfaz de usuario concreto de la vista.
La interfaz ICommand
La interfaz System.Windows.Input.ICommand no forma parte de Xamarin.Forms. En su lugar, se define en el espacio
de nombres System.Windows.Input y consta de dos métodos y un evento:
public interface ICommand
{
public void Execute (Object parameter);
Para usar la interfaz de comandos, el modelo de vista contiene propiedades de tipo ICommand :
El modelo de vista también debe hacer referencia a una clase que implemente la interfaz ICommand . Esta clase se
describirá en breve. En la vista, la propiedad Command de un objeto Button está enlazada a esa propiedad:
Cuando el usuario presiona el elemento Button , Button llama al método Execute del objeto ICommand
enlazado a su propiedad Command . Es la parte más sencilla de la interfaz de comandos.
El método CanExecute es más complejo. Cuando se define por primera vez el enlace en la propiedad Command del
objeto Button , y cuando cambia de algún modo el enlace de datos, el objeto Button llama al método
CanExecute del objeto ICommand . Si CanExecute devuelve false , el objeto Button se deshabilita a sí mismo.
Esto indica que el comando concreto no está disponible actualmente o no es válido.
El objeto Button también adjunta un controlador al evento CanExecuteChanged de ICommand . El evento se
desencadena desde dentro del modelo de vista. Cuando se desencadena ese evento, el objeto Button vuelve a
llamar a CanExecute . El objeto Button se habilita a sí mismo si CanExecute devuelve true y se deshabilita si
CanExecute devuelve false .
IMPORTANT
No use la propiedad IsEnabled de Button si usa la interfaz de comandos.
La clase Command
Cuando en el modelo de vista se define una propiedad de tipo ICommand , el modelo de vista también debe
contener o hacer referencia a una clase que implemente la interfaz ICommand . Esta clase debe contener o hacer
referencia a los métodos Execute y CanExecute , y desencadenar el evento CanExecuteChanged cada vez que el
método CanExecute pueda devolver otro valor.
Puede escribir este tipo de clase, o bien puede usar una escrita por otra persona. Como ICommand forma parte de
Microsoft Windows, se ha usado durante años con las aplicaciones MVVM de Windows. El uso de una clase de
Windows que implementa ICommand permite compartir los modelos de vista entre las aplicaciones de Windows y
las de Xamarin.Forms.
Si el uso compartido de modelos de vista entre Windows y Xamarin.Forms no constituye un problema, puede
usar la clase Command o Command<T> incluida en Xamarin.Forms para implementar la interfaz ICommand . Estas
clases permiten especificar los cuerpos de los métodos Execute y CanExecute en los constructores de clase. Use
Command<T> cuando use la propiedad CommandParameter para distinguir entre varias vistas enlazadas a la misma
propiedad ICommand , y la clase Command más sencilla cuando no sea un requisito.
Comandos básicos
En la página Entrada de personas del programa Demostraciones de enlace de datos se muestran algunos
comandos sencillos implementados en un modelo de vista.
PersonViewModel define tres propiedades denominadas Name , Age y Skills que definen una persona. Esta clase
no contiene ninguna propiedad ICommand :
storage = value;
OnPropertyChanged(propertyName);
return true;
}
···
storage = value;
OnPropertyChanged(propertyName);
return true;
}
Esta lista abreviada no incluye el constructor de la clase, que es donde se definen las tres propiedades de tipo
ICommand , que se mostrará en breve. Tenga en cuenta que los cambios en las tres propiedades de tipo ICommand y
la propiedad Persons no hacen que se desencadenen eventos PropertyChanged . Estas propiedades se establecen
al crear la clase por primera vez y no cambian a partir de entonces.
Antes de examinar el constructor de la clase PersonCollectionViewModel , veremos los archivos XAML para el
programa Entrada de personas. Este archivo contiene un elemento Grid con su propiedad BindingContext
establecida en el elemento PersonCollectionViewModel . El objeto Grid contiene un objeto Button con el texto
New con su propiedad Command enlazada a la propiedad NewCommand del modelo de vista, un formulario de
entrada con propiedades enlazadas a la propiedad IsEditing , así como las propiedades de PersonViewModel , y
dos botones más enlazados a las propiedades SubmitCommand y CancelCommand de la clase ViewModel. El objeto
ListView final muestra la colección de las personas que ya se han introducido:
<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>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid>
</Grid>
<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>
Este es el funcionamiento: el usuario presiona primero el botón New (Nuevo). Esto habilita el formulario de
entrada, pero deshabilita el botón New. Después, el usuario escribe un nombre, la edad y las habilidades. En
cualquier momento durante la edición, el usuario puede presionar el botón Cancel (Cancelar) para volver a
empezar. El botón Submit (Enviar) solo se habilita cuando se ha escrito un nombre y una edad válida. Al
presionar este botón Submit, se transfiere a la persona a la colección mostrada por ListView . Después de
presionar el botón Cancel o Submit, se borra el formulario de entrada y se vuelve a habilitar el botón New.
En la pantalla de iOS de la izquierda se muestra el diseño antes de escribir una vigencia válida. En las pantallas de
Android y UWP se muestra el botón Submit habilitado después de haber establecido una edad:
El programa no tiene ninguna función para editar las entradas existentes y no guarda las entradas al salir de la
página.
Toda la lógica para los botones New, Submit y Cancel se controla en PersonCollectionViewModel a través de
definiciones de las propiedades NewCommand , SubmitCommand y CancelCommand . El constructor de
PersonCollectionViewModel establece estas tres propiedades en objetos de tipo Command .
Un constructor de la clase Command permite pasar argumentos de tipo Action y Func<bool> correspondientes a
los métodos Execute y CanExecute . Es más fácil definir estas acciones y funciones como funciones lambda
directamente en el constructor de Command . Esta es la definición del objeto Command para la propiedad
NewCommand :
public class PersonCollectionViewModel : INotifyPropertyChanged
{
···
public PersonCollectionViewModel()
{
NewCommand = new Command(
execute: () =>
{
PersonEdit = new PersonViewModel();
PersonEdit.PropertyChanged += OnPersonEditPropertyChanged;
IsEditing = true;
RefreshCanExecutes();
},
canExecute: () =>
{
return !IsEditing;
});
···
void RefreshCanExecutes()
{
(NewCommand as Command).ChangeCanExecute();
(SubmitCommand as Command).ChangeCanExecute();
(CancelCommand as Command).ChangeCanExecute();
}
···
Cuando el usuario hace clic en el botón New, se ejecuta la función execute pasada al constructor de Command .
Esto crea un objeto PersonViewModel , establece un controlador en el evento PropertyChanged de ese objeto,
establece IsEditing en true , y llama al método RefreshCanExecutes definido después del constructor.
Además de implementar la interfaz ICommand , la clase Command también define un método denominado
ChangeCanExecute . El modelo de vista debe llamar a ChangeCanExecute para una propiedad ICommand cada vez
que suceda algo que pueda cambiar el valor devuelto del método CanExecute . Una llamada a ChangeCanExecute
hace que la clase Command desencadene el método CanExecuteChanged . El objeto Button ha adjuntado un
controlador para ese evento y responde mediante una nueva llamada a CanExecute y, después, se habilita a sí
mismo en función del valor devuelto de ese método.
Cuando el método execute de NewCommand llama a RefreshCanExecutes , la propiedad NewCommand recibe una
llamada a ChangeCanExecute , y Button llama al método canExecute , que ahora devuelve false porque la
propiedad IsEditing es true .
El controlador para el nuevo objeto PersonViewModel llama al método
PropertyChanged ChangeCanExecute de
SubmitCommand . Aquí se muestra la implementación de esa propiedad de comando:
public class PersonCollectionViewModel : INotifyPropertyChanged
{
···
public PersonCollectionViewModel()
{
···
···
}
···
La función canExecute para SubmitCommand se llama cada vez que cambia una propiedad en el objeto
PersonViewModel que se está editando. Solo devuelve true cuando la propiedad Name tiene al menos un
carácter de longitud, y Age es mayor que 0. En ese momento, se habilita el botón Submit.
La función execute para Submit quita el controlador de cambio de propiedad de PersonViewModel , agrega el
objeto a la colección Persons y devuelve todo a las condiciones iniciales.
La función execute para el botón Cancel hace lo mismo que el botón Submit excepto agregar el objeto a la
colección:
public class PersonCollectionViewModel : INotifyPropertyChanged
{
···
public PersonCollectionViewModel()
{
···
···
El método canExecute devuelve true en cualquier momento que se modifique un elemento PersonViewModel .
Estas técnicas se podrían adaptar para escenarios más complejos: una propiedad de PersonCollectionViewModel
se podría enlazar a la propiedad SelectedItem del objeto ListView para editar los elementos existentes, y se
podría agregar un botón Delete (Eliminar) para eliminar esos elementos.
No es necesario definir los métodos execute y canExecute como funciones lambda. Puede escribirlos como
métodos privados estándar en el modelo de vista y hacer referencia a ellos en constructores de Command . Pero
este enfoque tiende a crear una gran cantidad de métodos a los que solo se hace referencia una vez en el modelo
de vista.
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
<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.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>
<Button Text="CLEAR"
Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"
Command="{Binding ClearCommand}" />
<Button Text="⇦"
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" />
<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="·"
Grid.Row="5" Grid.Column="2"
Command="{Binding DigitCommand}"
CommandParameter="." />
</Grid>
</ContentPage>
Los 11 botones para los 10 dígitos y el separador decimal comparten un enlace a DigitCommand .
CommandParameter distingue entre estos botones. El valor establecido en CommandParameter suele ser el mismo que
el texto que se muestra en el botón, excepto por el separador decimal que, para una mayor claridad, se muestra
con un carácter de punto central.
Este es el programa en acción:
Observe que el botón para el separador decimal en las tres capturas de pantalla está deshabilitado porque el
número introducido ya contiene un separador decimal.
DecimalKeypadViewModel define una propiedad Entry de tipo string (que es la única que desencadena un
evento PropertyChanged ) y tres propiedades de tipo ICommand :
public class DecimalKeypadViewModel : INotifyPropertyChanged
{
string entry = "0";
···
El botón correspondiente a ClearCommand siempre está habilitado y simplemente establece la entrada en "0":
···
public DecimalKeypadViewModel()
{
ClearCommand = new Command(
execute: () =>
{
Entry = "0";
RefreshCanExecutes();
});
···
void RefreshCanExecutes()
{
((Command)BackspaceCommand).ChangeCanExecute();
((Command)DigitCommand).ChangeCanExecute();
}
···
Como el botón siempre está habilitado, no es necesario especificar un argumento canExecute en el constructor
de Command .
La lógica para escribir números y el retroceso es un poco complicada, porque si no se ha especificado ningún
dígito, la propiedad Entry es la cadena "0". Si el usuario escribe más ceros, Entry todavía contiene un solo cero.
Si el usuario escribe cualquier otro dígito, ese dígito reemplaza al cero. Pero si el usuario escribe un separador
decimal antes de cualquier otro dígito, Entry es la cadena "0.".
El botón Backspace (Retroceso) solo se habilita cuando la longitud de la entrada es mayor que 1, o bien si Entry
no es igual a la cadena "0":
···
public DecimalKeypadViewModel()
{
···
···
···
La lógica para la función execute para el botón Backspace garantiza que Entry es al menos una cadena de "0".
La propiedad está enlazada a 11 botones, que se identifican a sí mismos con la propiedad
DigitCommand
CommandParameter de forma individual. Se podría establecer DigitCommand en una instancia de la clase Command
normal, pero es más fácil usar la clase Command<T> genérica. Cuando se usa la interfaz de comandos con XAML,
las propiedades CommandParameter suelen ser cadenas, y ese es el tipo del argumento genérico. Las funciones
execute y canExecute tienen argumentos de tipo string :
public class DecimalKeypadViewModel : INotifyPropertyChanged
{
···
public DecimalKeypadViewModel()
{
···
···
El método execute anexa el argumento de cadena a la propiedad Entry . Pero si el resultado comienza con un
cero (pero no un cero y un separador decimal), ese cero inicial se debe quitar mediante la función Substring .
El método canExecute devuelve false solo si el argumento es el separador decimal (lo que indica que se
presiona el separador decimal) y Entry ya contiene un separador decimal.
Todos los métodos execute llaman a RefreshCanExecutes , que llama a ChangeCanExecute para DigitCommand y
ClearCommand . Esto garantiza que los botones de retroceso y separador decimal se habilitan o deshabilitan en
función de la secuencia actual de dígitos especificados.
···
</TableSection>
</TableRoot>
</TableView>
</ContentPage>
Al usar comandos con XAML, las propiedades CommandParameter normalmente se establecen en cadenas. Pero en
este caso, se usa una extensión de marcado XAML para que CommandParameter sea de tipo System.Type .
Cada propiedad Command se enlaza a una propiedad denominada NavigateCommand . Esa propiedad se define en el
archivo de código subyacente, MainPage.xaml.cs:
BindingContext = this;
}
El constructor establece la propiedad NavigateCommand en un método execute que crea una instancia del
parámetro System.Type y, después, navega hasta ella. Como la llamada a PushAsync requiere un operador await
, el método execute debe estar marcado como asincrónico. Esto se consigue con la palabra clave async por
delante de la lista de parámetros.
El constructor establece también el elemento BindingContext de la página en sí mismo para que los enlaces
hagan referencia a NavigateCommand en esta clase.
El orden del código de este constructor establece una diferencia: la llamada a InitializeComponent hace que se
analice el código XAML, pero en ese momento, el enlace a una propiedad denominada NavigateCommand no se
puede resolver porque BindingContext está establecido en null . Si se establece BindingContext en el
constructor antes de establecer NavigateCommand , el enlace se puede resolver cuando se establezca
BindingContext , pero en ese momento, NavigateCommand sigue siendo null . Establecer NavigateCommand
después de BindingContext no tendrá ningún efecto en el enlace porque un cambio en NavigateCommand no
desencadena un evento PropertyChanged y el enlace no sabe que NavigateCommand ahora es válido.
El establecimiento de y BindingContext (en cualquier orden) antes de llamar a
NavigateCommand
InitializeComponent funcionará porque los dos componentes del enlace se establecen cuando el analizador
XAML encuentra la definición de enlace.
En ocasiones, los enlaces de datos pueden resultar complicados, pero como ha visto en esta serie de artículos, son
eficaces y versátiles, y ayudan considerablemente a organizar el código mediante la separación de la lógica
subyacente de la interfaz de usuario.
Vínculos relacionados
Data Binding Demos (sample) (Demos de enlace de datos [ejemplo])
Capítulo sobre enlace de datos del libro de Xamarin.Forms
Enlaces compilados de Xamarin.Forms
11/07/2019 • 14 minutes to read • Edit Online
Descargar el ejemplo
Los enlaces compilados se resuelven más rápidamente que los enlaces clásicos, lo cual mejora el rendimiento del
enlace de datos en las aplicaciones de Xamarin.Forms.
Los enlaces de datos tienen dos problemas principales:
1. No hay ninguna validación de las expresiones de enlace en tiempo de compilación. Alternativamente, los
enlaces se resuelven en tiempo de ejecución. Por lo tanto, los enlaces no válidos no se detectan hasta el tiempo
de ejecución, cuando la aplicación no se comporta según lo esperado o aparecen mensajes de error.
2. No son rentables. Los enlaces se resuelven en tiempo de ejecución mediante la inspección de objetos de uso
general (reflejo); el trabajo adicional que supone llevarlo a cabo varía en función de la plataforma.
Los enlaces compilados mejoran el rendimiento de enlace de datos en las aplicaciones de Xamarin.Forms
mediante la resolución de expresiones de enlace en tiempo de compilación en lugar de en tiempo de ejecución.
Además, esta validación en tiempo de compilación de expresiones de enlace permite una mejor experiencia de
solución de problemas, porque los enlaces no válidos se notifican como errores de compilación.
El proceso para usar enlaces compilados es el siguiente:
1. Habilite la compilación XAML. Para obtener más información acerca de la compilación XAML, consulte XAML
Compilation (Compilación XAML ).
2. Establezca un atributo x:DataType de un elemento VisualElement para el tipo del objeto al cual
VisualElement y sus elementos secundarios se enlazará. Tenga en cuenta que este atributo puede volver a
definirse en cualquier ubicación en una jerarquía de vistas.
NOTE
Se recomienda establecer el atributo x:DataType en el mismo nivel de la jerarquía de vistas en que está establecido
BindingContext .
En tiempo de compilación XAML, las expresiones de enlace no válidas se notificarán como errores de
compilación. Sin embargo, el compilador XAML solo notificará un error de compilación para la primera expresión
de enlace no válida que encuentre. Las expresiones de enlace válidas que se definen en VisualElement o en sus
elementos secundarios se compilarán, independientemente de si BindingContext está establecido en XAML o en
código. La compilación de una expresión de enlace genera un código compilado que obtendrá un valor de una
propiedad en el origen y lo establecerá en la propiedad en el destino que se especifica en el marcado. Además,
dependiendo de la expresión de enlace, el código generado puede observar cambios en el valor de la propiedad
de origen y actualizar la propiedad de destino, y puede insertar los cambios desde el destino de nuevo al origen.
IMPORTANT
Los enlaces compilados actualmente están deshabilitados para las expresiones de enlace que definen la propiedad Source .
Esto es así porque la propiedad Source siempre se establece mediante la extensión de marcado x:Reference , que no se
puede resolver en tiempo de compilación.
Uso de enlaces compilados
En la página Compiled Color Selector (Selector de colores compilados) se muestra el uso de enlaces
compilados entre las vistas de Xamarin.Forms y las propiedades 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>
El elemento StackLayout raíz crea una instancia de HslColorViewModel e inicializa la propiedad Color dentro de
las etiquetas de elemento de propiedad para la propiedad BindingContext . El elemento StackLayout raíz también
define el atributo x:DataType como el tipo ViewModel, lo cual indica que todas las expresiones de enlace en la
jerarquía de vistas StackLayout raíz se compilarán. Esto se puede comprobar cambiando cualquiera de las
expresiones de enlace para enlazar a una propiedad ViewModel inexistente, lo cual generará a un error de
compilación.
IMPORTANT
El atributo x:DataType puede volver a definirse en cualquier punto de una jerarquía de vistas.
Los elementos BoxView , Label y las vistas Slider heredan el contexto de enlace del elemento StackLayout .
Todas estas vistas son destinos de enlace que hacen referencia a las propiedades de origen en ViewModel. Para la
propiedad BoxView.Color y la propiedad Label.Text , los enlaces de datos son OneWay ; las propiedades de las
vista se establecen a partir de las propiedades en ViewModel. Sin embargo, la propiedad Slider.Value utiliza un
enlace TwoWay . Esto permite que cada Slider se establezca a partir de ViewModel, y que ViewModel se
establezca a partir de cada Slider .
Cuando la aplicación se ejecuta por primera vez, los elementos BoxView , Label , y los elementos Slider están
establecidos a partir de ViewModel en base a la propiedad Color inicial establecida cuando se creó una instancia
de ViewModel. Esto se muestra en la captura de pantalla siguiente:
A medida que se manipulan los controles deslizantes, los elementos BoxView y Label se actualizan del modo
correspondiente.
Para obtener más información acerca de este selector de colores, consulte ViewModels and Property-Change
Notifications (ViewModels y las notificaciones de cambio de propiedad).
<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>
La propiedad ListView.ItemsSource está establecida en la propiedad NamedColor.All estática. La clase
NamedColor usa la fijación de .NET para enumerar todos los campos públicos estáticos en la estructura de Color
y almacenarlos con sus nombres en una colección que sea accesible desde la propiedad All estática. Por lo
tanto, ListView se rellena con todas las instancias de NamedColor . Para cada elemento de ListView , el contexto
de enlace para el elemento está establecido en un objeto NamedColor . Los elementos BoxView y Label de
ViewCell están enlazados a propiedades NamedColor .
Tenga en cuenta que x:DataType``NamedColor define el atributo DataTemplate para ser del tipo DataTemplate , lo
cual indica que todas las expresiones de enlace en la jerarquía de vistas se compilarán. Esto se puede comprobar
cambiando cualquiera de las expresiones de enlace para enlazar a una propiedad NamedColor inexistente, lo cual
generará a un error de compilación.
Cuando la aplicación se ejecuta por primera vez, ListView se rellena con instancias de NamedColor . Cuando un
elemento de ListView está seleccionado, la propiedad BoxView.Color se establece en el color del elemento
seleccionado en ListView :
El elemento StackLayout raíz establece el atributo x:DataType para ser del tipo HslColorViewModel , lo cual indica
que todas las expresiones de enlace en la jerarquía de vistas StackLayout se compilarán. Sin embargo, el
StackLayout interno redefine el atributo x:DataType en null con la expresión de marcado x:Null . Por lo tanto,
las expresiones de enlace dentro del StackLayout interno usan enlaces clásicos. Solo BoxView , dentro de la
jerarquía de vistas StackLayout raíz, utiliza enlaces compilados.
Para obtener más información acerca de la expresión de marcado x:Null , consulte x:Null Markup Extension
(Extensión de marcado x:Null).
Rendimiento
Los enlaces compilados mejoran el rendimiento del enlace de datos, con unas ventajas de rendimiento variables.
Las pruebas de unidades muestran lo siguiente:
Un enlace compilado que utiliza la notificación de cambio de propiedad (es decir, un enlace OneWay ,
OneWayToSource o TwoWay ) se resuelve aproximadamente 8 veces más rápidamente que un enlace clásico.
Un enlace compilado que no utiliza la notificación de cambio de propiedad (es decir, un enlace OneTime ) se
resuelve aproximadamente 20 veces más rápidamente que un enlace clásico.
El establecimiento de BindingContext en un enlace compilado que utiliza la notificación de cambio de
propiedad (es decir, un enlace OneWay , OneWayToSource o TwoWay ) se resuelve aproximadamente 5 veces más
rápidamente que el establecimiento de BindingContext en un enlace clásico.
El establecimiento de BindingContext en un enlace compilado que no utiliza la notificación de cambio de
propiedad (es decir, un enlace OneTime ) se resuelve aproximadamente 7 veces más rápidamente que el
establecimiento de BindingContext en un enlace clásico.
Estas diferencias de rendimiento se pueden ampliar en dispositivos móviles, dependiendo de la plataforma que se
utilice, la versión del sistema operativo que se utilice y el dispositivo en el que se ejecute la aplicación.
Vínculos relacionados
Demos de enlace de datos (ejemplo)
Xamarin.Forms DependencyService
17/07/2019 • 2 minutes to read • Edit Online
Introducción
La clase DependencyService es un localizador de servicios que habilita las aplicaciones de Xamarin.Forms para
invocar la funcionalidad nativa de la plataforma desde código compartido.
Registro y resolución
Las implementaciones de la plataforma deben registrarse con DependencyService y, después, deben resolverse
desde código compartido para poder invocarse.
Descargar el ejemplo
La clase DependencyService es un localizador de servicios que habilita las aplicaciones de Xamarin.Forms para
invocar la funcionalidad nativa de la plataforma desde código compartido.
El proceso para usar DependencyService para invocar la funcionalidad nativa de la plataforma es el siguiente:
1. Cree una interfaz para la funcionalidad de la plataforma nativa en el código compartido. Para más información,
vea Creación de una interfaz.
2. Implemente la interfaz en los proyectos de la plataforma requeridos. Para obtener más información, vea
Implementación de la interfaz en cada plataforma.
3. Registro de las implementaciones de la plataforma con DependencyService . Esto permite que Xamarin.Forms
localice las implementaciones de la plataforma en tiempo de ejecución. Para obtener más información, vea
Registro de las implementaciones de la plataforma.
4. Resuelva las implementaciones de la plataforma desde el código compartido e invóquelas. Para obtener más
información, vea Resolución de las implementaciones de la plataforma.
En el siguiente diagrama, se muestra cómo se invoca la funcionalidad nativa de la plataforma en una aplicación de
Xamarin.Forms:
namespace DependencyServiceDemos.iOS
{
public class DeviceOrientationService : IDeviceOrientationService
{
public DeviceOrientation GetOrientation()
{
UIInterfaceOrientation orientation = UIApplication.SharedApplication.StatusBarOrientation;
Android
En el siguiente ejemplo de código, se muestra la implementación de la interfaz de IDeviceOrientationService en
Android:
namespace DependencyServiceDemos.Droid
{
public class DeviceOrientationService : IDeviceOrientationService
{
public DeviceOrientation GetOrientation()
{
IWindowManager windowManager =
Android.App.Application.Context.GetSystemService(Context.WindowService).JavaCast<IWindowManager>();
namespace DependencyServiceDemos.UWP
{
public class DeviceOrientationService : IDeviceOrientationService
{
public DeviceOrientation GetOrientation()
{
ApplicationViewOrientation orientation = ApplicationView.GetForCurrentView().Orientation;
return orientation == ApplicationViewOrientation.Landscape ? DeviceOrientation.Landscape :
DeviceOrientation.Portrait;
}
}
}
Registro de las implementaciones de la plataforma
Después de implementar la interfaz en cada proyecto de la plataforma, las implementaciones de la plataforma
deberán registrarse con DependencyService para que Xamarin.Forms pueda ubicarlas en tiempo de ejecución.
Normalmente, esto se realiza con DependencyAttribute , lo que indica que el tipo especificado proporciona una
implementación de la interfaz.
En el siguiente ejemplo se muestra el uso de DependencyAttribute para registrar la implementación en iOS de la
interfaz de IDeviceOrientationService :
using Xamarin.Forms;
[assembly: Dependency(typeof(DeviceOrientationService))]
namespace DependencyServiceDemos.iOS
{
public class DeviceOrientationService : IDeviceOrientationService
{
public DeviceOrientation GetOrientation()
{
...
}
}
}
Para obtener más información sobre el registro de implementaciones de plataforma con DependencyService , vea
Registro y resolución de DependencyService de Xamarin.Forms.
En el código siguiente, se muestra un ejemplo de llamada al método Get<T> para resolver la interfaz de
IDeviceOrientationService y, después, invocar su método GetOrientation :
Para obtener más información sobre la resolución de las implementaciones de la plataforma con
DependencyService , vea Registro y resolución de DependencyService de Xamarin.Forms.
Vínculos relacionados
Demostraciones de DependencyService (ejemplo)
Registro y resolución de DependencyService de Xamarin.Forms
Registro y resolución de DependencyService de
Xamarin.Forms
17/07/2019 • 11 minutes to read • Edit Online
Descargar el ejemplo
Al usar DependencyService de Xamarin.Forms para invocar la funcionalidad de la plataforma nativa, las
implementaciones de la plataforma deben estar registradas con DependencyService y, a continuación, resolverse
desde código compartido para poder invocarse.
IMPORTANT
Las compilaciones de versión de los proyectos de UWP que usan la compilación nativa de .NET deben registrar las
implementaciones de plataforma con los métodos Register .
using Xamarin.Forms;
[assembly: Dependency(typeof(DeviceOrientationService))]
namespace DependencyServiceDemos.iOS
{
public class DeviceOrientationService : IDeviceOrientationService
{
public DeviceOrientation GetOrientation()
{
...
}
}
}
[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());
DependencyService.Register<IDeviceOrientationService, DeviceOrientationService>();
return base.FinishedLaunching(app, options);
}
}
DependencyService.Register<DeviceOrientationService>();
En este ejemplo, el método Register registra DeviceOrientationService con DependencyService . Esto da como
resultado el tipo concreto que se va a registrar en la interfaz que implementará.
De forma similar, las implementaciones de la interfaz IDeviceOrientationService en otras plataformas se puede
registrar con los métodos Register .
IMPORTANT
El registro con los métodos Register se debe realizar en los proyectos de la plataforma antes de que se invoque la
funcionalidad que ha proporcionado la implementación de la plataforma mediante el código compartido.
NOTE
El método Get<T> crea una instancia de la implementación de la plataforma de la interfaz de T como singleton de forma
predeterminada. No obstante, este comportamiento se puede modificar. Para obtener más información, vea Administración
de la vigencia de los objetos resueltos.
En este ejemplo, DependencyService crea una instancia de la implementación de la plataforma para la interfaz de
ITextToSpeechService . Las llamadas subsiguientes para resolver ITextToSpeechService también crearán nuevas
instancias.
La consecuencia de crear siempre una nueva instancia de una implementación de la plataforma es que la
aplicación adquiere la responsabilidad de administrar la vigencia de las instancias. Esto significa que, si se
suscribe a un evento definido en una implementación de la plataforma, deberá cancelar la suscripción al evento
cuando ya no se requiera la implementación de la plataforma. Además, significa que puede ser necesario que las
implementaciones de la plataforma implementen IDisposable y realicen una limpieza de sus recursos en los
métodos Dispose . La aplicación de ejemplo muestra este escenario en sus implementaciones de la plataforma de
TextToSpeechService .
Cuando una aplicación termina de utilizar una implementación de la plataforma que implementa IDisposable ,
debe llamar a la implementación del objeto Dispose . Una manera de realizar esta acción es usar una instrucción
using :
En este ejemplo, una vez que se ha invocado el método SpeakAsync , la instrucción using desecha
automáticamente el objeto de la implementación de la plataforma. Esto da como resultado la invocación del
método Dispose del objeto, que realiza la limpieza requerida.
Para obtener más información sobre cómo llamar al método Dispose de un objeto, vea Uso de objetos que
implementan IDisposable.
Vínculos relacionados
Demostraciones de DependencyService (ejemplo)
Resolución de dependencias en Xamarin.Forms
Seleccionar una foto de la biblioteca de imágenes
17/07/2019 • 10 minutes to read • Edit Online
Descargar el ejemplo
En este artículo, se explica cómo crear una aplicación que permita al usuario seleccionar una foto de la biblioteca
de imágenes del teléfono. Como en Xamarin.Forms no se incluye esta función, es necesario usar
DependencyService para acceder a las API nativas en cada plataforma.
Creación de la interfaz
Primero, cree una interfaz en el código compartido que exprese la función deseada. En el caso de una aplicación
de selección de fotos, solo se necesita un método. Esto se define en la interfaz IPicturePicker de la biblioteca de
.NET Standard del código de ejemplo:
namespace DependencyServiceSample
{
public interface IPicturePicker
{
Task<Stream> GetImageStreamAsync();
}
}
El método GetImageStreamAsync se define como asincrónico porque tiene que devolver resultados rápidamente,
pero no puede devolver un objeto Stream para la foto seleccionada hasta que el usuario haya abierto la
biblioteca de imágenes y haya seleccionado una.
Esta interfaz se implementa en todas las plataformas que usan código específico de plataforma.
Implementación en iOS
La implementación de iOS de la interfaz IPicturePicker usa el objeto UIImagePickerController , como se
describe en la receta Seleccionar una foto de la galería y en el código de ejemplo.
La implementación de iOS se contiene en la clase PicturePickerImplementation del proyecto de iOS del código de
ejemplo. Para que el administrador DependencyService pueda ver esta clase, tiene que identificarse con un
atributo [ assembly ] del tipo Dependency y, además, tiene que ser pública e implementar explícitamente la interfaz
IPicturePicker :
[assembly: Dependency (typeof (PicturePickerImplementation))]
namespace DependencyServiceSample.iOS
{
public class PicturePickerImplementation : IPicturePicker
{
TaskCompletionSource<Stream> taskCompletionSource;
UIImagePickerController imagePicker;
// Present UIImagePickerController;
UIWindow window = UIApplication.SharedApplication.KeyWindow;
var viewController = window.RootViewController;
viewController.PresentModalViewController(imagePicker, true);
En este momento, el método GetImageStreamAsync tiene que devolver un objeto Task<Stream> al código que
realiza la llamada. Esta tarea solo se completa cuando el usuario termina de interactuar con la biblioteca de fotos
y se llama a uno de los controladores de eventos. Para situaciones como esta, la clase TaskCompletionSource es
esencial. La clase proporciona un objeto Task al tipo genérico adecuado para devolver desde el método
GetImageStreamAsync y, después, se puede enviar una señal a la clase cuando se complete la tarea.
Se llama al controlador de eventos FinishedPickingMedia cuando el usuario ha seleccionado una imagen. Pero el
controlador proporciona un objeto UIImage y el elemento Task tiene que devolver un objeto Stream de .NET.
Esto se realiza en dos pasos: primero, el objeto UIImage se convierte a un archivo JPEG en memoria almacenado
en un objeto NSData y, después, el objeto NSData se convierte a un objeto Stream de .NET. Una llamada al
método SetResult del objeto TaskCompletionSource completa la tarea al proporcionar el 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();
void UnregisterEventHandlers()
{
imagePicker.FinishedPickingMedia -= OnImagePickerFinishedPickingMedia;
imagePicker.Canceled -= OnImagePickerCancelled;
}
}
}
Una aplicación de iOS necesita el permiso del usuario para acceder a la biblioteca de fotos del teléfono. Agregue
el código siguiente a la sección dict del archivo Info.plist:
<key>NSPhotoLibraryUsageDescription</key>
<string>Picture Picker uses photo library</string>
Implementación en Android
La implementación de Android usa la técnica descrita en la receta Seleccionar una imagen y en el código de
ejemplo. Pero el método al que se llama cuando el usuario ha seleccionado una imagen desde la biblioteca de
imágenes es un reemplazo de OnActivityResult en una clase derivada de Activity . Por este motivo, la clase
MainActivity normal del proyecto de Android se ha complementado con un campo, una propiedad y un
reemplazo del método OnActivityResult :
public class MainActivity : FormsAppCompatActivity
{
...
// Field, property, and method for Picture Picker
public static readonly int PickImageId = 1000;
if (requestCode == PickImageId)
{
if ((resultCode == Result.Ok) && (intent != null))
{
Android.Net.Uri uri = intent.Data;
Stream stream = ContentResolver.OpenInputStream(uri);
El reemplazo OnActivityResult indica el archivo de imagen seleccionado con un objeto Uri de Android, pero
esto se puede convertir a un objeto Stream de .NET si se llama al método OpenInputStream del objeto
ContentResolver obtenido desde la propiedad ContentResolver de la actividad.
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);
Este método accede a la clase MainActivity por varios motivos: para la propiedad Instance , para el campo
PickImageId , para la propiedad TaskCompletionSource y para llamar a StartActivityForResult . Este método se
define mediante la clase FormsAppCompatActivity , que es la clase base de MainActivity .
Implementación en UWP
Al contrario que en las implementaciones de iOS y Android, la implementación del selector de fotos para la
Plataforma universal de Windows no necesita la clase TaskCompletionSource . La clase
PicturePickerImplementation usa la clase FileOpenPicker para acceder a la biblioteca de fotos. Como el método
PickSingleFileAsync de FileOpenPicker es en sí asincrónico, el método GetImageStreamAsync puede simplemente
usar await con ese método (y otros métodos asincrónicos) y devolver un 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");
if (storageFile == null)
{
return null;
}
El controlador Clicked usa la clase DependencyService para llamar a GetImageStreamAsync . Como resultado, se
produce una llamada en el proyecto de la plataforma. Si el método devuelve un objeto Stream , el controlador
crea un elemento Image para esa imagen con un elemento TapGestureRecognizer y reemplaza el elemento
StackLayout en la página por ese elemento 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
};
Vínculos relacionados
Seleccionar una foto de la galería (iOS )
Seleccionar una imagen (Android)
DependencyService (ejemplo)
Efectos de Xamarin.Forms
11/07/2019 • 2 minutes to read • Edit Online
Las interfaces de usuario de Xamarin.Forms se representan mediante los controles nativos de la plataforma de
destino, lo que permite que las aplicaciones de Xamarin.Forms conserven la apariencia adecuada para cada
plataforma. Con los efectos se pueden personalizar los controles nativos de cada plataforma sin tener que
recurrir a la implementación de un representador personalizado.
Crear un efecto
Los efectos simplifican la personalización de un control. En este artículo se muestra cómo crear un efecto que
cambia el color de fondo del control Entry cuando el control recibe el foco.
Con los efectos se pueden personalizar los controles nativos de cada plataforma y normalmente se usan para
pequeños cambios de estilo. En este artículo se proporciona una introducción a los efectos, se describe el límite
entre los efectos y los representadores personalizados, y se describe la clase PlatformEffect.
En Páginas, diseños y controles de Xamarin.Forms se presenta una API común para describir interfaces de usuario
móviles multiplataforma. Cada página, diseño y control se representan de forma diferente en cada plataforma
mediante una clase Renderer que, a su vez, crea un control nativo (correspondiente a la representación de
Xamarin.Forms), lo organiza en la pantalla y agrega el comportamiento especificado en el código compartido.
Los desarrolladores pueden implementar sus propias clases Renderer personalizadas para personalizar la
apariencia o el comportamiento de un control. Pero la implementación de una clase de representador
personalizado para llevar a cabo una personalización de controles simples suele ser una respuesta compleja. Los
efectos simplifican este proceso y permiten que los controles nativos de cada plataforma se puedan personalizar
más fácilmente.
Los efectos se crean en proyectos específicos de la plataforma mediante la creación de subclases del control
PlatformEffect , y después se consumen adjuntándolos a un control adecuado en una biblioteca de .NET Standard
de Xamarin.Forms o un proyecto de biblioteca compartida.
Cada una de las clases PlatformEffect específicas de la plataforma expone las propiedades siguientes:
Container : hace referencia al control específico de la plataforma que se usa para implementar el diseño.
Control : hace referencia al control específico de la plataforma que se usa para implementar el control de
Xamarin.Forms.
Element : hace referencia al control de Xamarin.Forms que se va a representar.
Los efectos no tienen información de tipo sobre el contenedor, el control o el elemento al que se adjuntan, ya que
se pueden adjuntar a cualquier elemento. Por tanto, cuando se adjunta un efecto a un elemento que no es
compatible, se debe degradar correctamente o iniciar una excepción. Pero las propiedades Container , Control y
Element se pueden convertir a su tipo de implementación. Para obtener más información sobre estos tipos, vea
Clases base y controles nativos del representador.
Cada clase PlatformEffect específica de la plataforma expone los métodos siguientes, que se deben invalidar para
implementar un efecto:
OnAttached : se llama cuando se adjunta un efecto a un control de Xamarin.Forms. Una versión invalidada de
este método, en cada clase de efecto específica de la plataforma, es el lugar para realizar la personalización del
control, junto con el control de excepciones en caso de que no se pueda aplicar el efecto al control de
Xamarin.Forms especificado.
OnDetached : se llama cuando se desasocia un efecto de un control de Xamarin.Forms. Una versión invalidada
de este método, en cada clase de efecto específica de la plataforma, es el lugar para realizar cualquier limpieza
de efectos, como anular el registro de un controlador de eventos.
Además, PlatformEffect expone el método OnElementPropertyChanged , que también se puede invalidar. Este
método se llama cuando ha cambiado una propiedad del elemento. Una versión invalidada de este método, en
cada clase de efecto específica de la plataforma, es el lugar para responder a los cambios de propiedad enlazable
en el control de Xamarin.Forms. Siempre se debe realizar una comprobación de la propiedad que ha modificado,
ya que esta invalidación se puede llamar varias veces.
Vínculos relacionados
Representadores personalizados
Creación de un efecto
11/07/2019 • 12 minutes to read • Edit Online
Descargar el ejemplo
Los efectos simplifican la personalización de un control. En este artículo se muestra cómo crear un efecto que
cambia el color de fondo del control Entry cuando recibe el foco.
El proceso para crear un efecto de cada proyecto específico de la plataforma es el siguiente:
1. Se crea una subclase de la clase PlatformEffect .
2. Se invalida el método OnAttached y se escribe lógica para personalizar el control.
3. Se invalida el método OnDetached y se escribe lógica para limpiar la personalización del control, si es
necesario.
4. Se agrega un atributo ResolutionGroupName a la clase de efecto. Este atributo establece un espacio de nombres
para los efectos para toda la empresa, lo que evita conflictos con otros efectos con el mismo nombre. Tenga en
cuenta que este atributo solo se puede aplicar una vez por proyecto.
5. Agregue un atributo ExportEffect a la clase de efecto. Este atributo registra el efecto con un identificador
único que Xamarin.Forms usa junto con el nombre del grupo para buscar el efecto antes de aplicarlo a un
control. El atributo toma dos parámetros: el nombre de tipo del efecto y una cadena única que se usará para
buscar el efecto antes de aplicarlo a un control.
Después, el efecto se puede consumir si se adjunta al control adecuado.
NOTE
Proporcionar un efecto en cada proyecto de la plataforma es un paso opcional. Al intentar usar un efecto cuando no se ha
registrado uno, se devolverá un valor distinto de NULL que no hace nada.
En la aplicación de ejemplo se muestra un elemento FocusEffect que cambia el color de fondo de un control
cuando recibe el foco. En el diagrama siguiente se ilustran las responsabilidades de cada proyecto en la aplicación
de ejemplo, junto con las relaciones entre ellos:
La clase FocusEffect personaliza un control Entry en el elemento HomePage en cada proyecto específico de la
plataforma. Cada clase FocusEffect se deriva de la clase PlatformEffect para cada plataforma. Como resultado,
se representa el control Entry con un color de fondo específico de la plataforma, que cambia cuando el control
recibe el foco, como se muestra en las capturas de pantalla siguientes:
Creación del efecto en cada plataforma
En las secciones siguientes se describe la implementación específica de la plataforma de la clase FocusEffect .
Proyecto de iOS
En el ejemplo de código siguiente se muestra la implementación FocusEffect para el proyecto de 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;
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);
}
}
}
}
El método establece la propiedad BackgroundColor del control en color morado claro con el método
OnAttached
UIColor.FromRGB y también almacena este color en un campo. Esta funcionalidad se encapsula en un bloque try /
catch en caso de que el control al que está asociado el efecto no tenga una propiedad BackgroundColor . El
método OnDetached no proporciona ninguna implementación porque no se necesita limpieza.
La invalidación de OnElementPropertyChanged responde a los cambios de propiedad enlazable en el control de
Xamarin.Forms. Cuando cambia la propiedad IsFocused , la propiedad BackgroundColor del control se cambia a
color blanco si el control tiene el foco; en caso contrario, se cambia a color morado claro. Esta funcionalidad se
encapsula en un bloque try / catch en caso de que el control al que está asociado el efecto no tenga una
propiedad BackgroundColor .
Proyecto de Android
En el ejemplo de código siguiente se muestra la implementación FocusEffect para el proyecto de 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;
El método OnAttached llama al método SetBackgroundColor para establecer el color de fondo del control en verde
claro y también almacena este color en un campo. Esta funcionalidad se encapsula en un bloque try / catch en
caso de que el control al que está asociado el efecto no tenga una propiedad SetBackgroundColor . El método
OnDetached no proporciona ninguna implementación porque no se necesita limpieza.
[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);
}
}
NOTE
Una instancia de efecto solo se puede adjuntar a un único control. Por tanto, un efecto se debe resolver dos veces para
usarlo en dos controles.
La clase FocusEffect de la biblioteca de .NET Standard admite el consumo de efectos en XAML, y se muestra en
el ejemplo de código siguiente:
La clase FocusEffect crea subclases de la clase RoutingEffect , que representa un efecto independiente de la
plataforma que encapsula un efecto interno que suele ser específico de la plataforma. La clase FocusEffect llama
al constructor de clase base, y se pasa un parámetro que consiste en la concatenación del nombre del grupo de
resolución (que se especifica con el atributo ResolutionGroupName en la clase de efecto), y el identificador único
que se ha especificado con el atributo ExportEffect en la clase de efecto. Por tanto, cuando se inicializa Entry en
tiempo de ejecución, se agrega una nueva instancia de MyCompany.FocusEffect a la colección Effects del control.
Los efectos también se pueden adjuntar a los controles mediante un comportamiento, o bien mediante
propiedades adjuntas. Para obtener más información sobre cómo adjuntar un efecto a un control mediante un
comportamiento, vea EffectBehavior reutilizable. Para obtener más información sobre cómo adjuntar un efecto a
un control mediante propiedades adjuntas, vea Pasar parámetros a un efecto.
FocusEffectse adjunta a la instancia de Entry mediante la adición del efecto a la colección Effects del control,
como se muestra en el ejemplo de código siguiente:
public HomePageCS ()
{
...
entry.Effects.Add (Effect.Resolve ($"MyCompany.{nameof(FocusEffect)}"));
...
}
Effect.Resolve devuelve un elemento Effect para el nombre especificado, que es una concatenación del
nombre del grupo de resolución (que se especifica con el atributo ResolutionGroupName en la clase de efecto), y el
identificador único que se ha especificado con el atributo ExportEffect en la clase de efecto. Si una plataforma no
proporciona el efecto, el método Effect.Resolve devolverá un valor que no es null .
Resumen
En este artículo se ha mostrado cómo crear un efecto que cambia el color de fondo del control Entry cuando el
control recibe el foco.
Vínculos relacionados
Representadores personalizados
Efecto
PlatformEffect
Efecto de color de fondo (ejemplo)
Efecto de enfoque (ejemplo)
Pasar parámetros a un efecto
11/07/2019 • 2 minutes to read • Edit Online
Parámetros de efecto pueden definirse mediante propiedades, habilitar el efecto reutilizar. Parámetros, a
continuación, pueden pasarse al efecto especificando valores para cada propiedad al crear una instancia del
efecto.
Descargar el ejemplo
Las propiedades de Common Language Runtime (CLR ) se pueden usar para definir parámetros de efecto que no
responden a los cambios de propiedades en tiempo de ejecución. En este artículo se muestra cómo usar
propiedades CLR para pasar parámetros a un efecto.
El proceso para crear parámetros de efecto que no respondan a los cambios de propiedades en tiempo de
ejecución es el siguiente:
1. Cree una clase public que genere subclases de la clase RoutingEffect . La clase RoutingEffect representa un
efecto independiente de la plataforma que encapsula un efecto interno, que suele ser específico de la
plataforma.
2. Cree un constructor que llame al constructor de clase base, y pase una concatenación del nombre del grupo de
resolución y el identificador único que se ha especificado en cada clase de efecto específica de la plataforma.
3. Agregue propiedades a la clase para cada parámetro que se va a pasar al efecto.
Después, se pueden pasar parámetros al efecto mediante la especificación de valores para cada propiedad al crear
una instancia del efecto.
En la aplicación de ejemplo se muestra un elemento ShadowEffect que agrega una sombra al texto mostrado por
un control Label . En el diagrama siguiente se ilustran las responsabilidades de cada proyecto en la aplicación de
ejemplo, junto con las relaciones entre ellos:
El elemento ShadowEffect contiene cuatro propiedades que representan los parámetros que se van a pasar a cada
elemento LabelShadowEffect específico de la plataforma. El constructor de la clase llama al constructor de clase
base, y se pasa un parámetro que consiste en la concatenación del nombre del grupo de resolución y el
identificador único que se ha especificado en cada clase de efecto específica de la plataforma. Por tanto, cuando se
crea una instancia de ShadowEffect , se agrega una nueva instancia de MyCompany.LabelShadowEffect a la colección
Effects de un control.
En ambos ejemplos de código, se crea una instancia de la clase ShadowEffect con valores especificados para cada
propiedad, antes de agregarse a la colección Effects del control. Observe que la propiedad ShadowEffect.Color
usa valores de color específicos de la plataforma. Para obtener más información, vea Clase Device.
Proyecto de iOS
En el ejemplo de código siguiente se muestra la implementación LabelShadowEffect para el proyecto de 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);
}
}
El método OnAttached recupera la instancia de ShadowEffect y, después, establece las propiedades Control.Layer
en los valores de propiedad especificados para crear la sombra. Esta funcionalidad se encapsula en un bloque try
/ catch en caso de que el control al que está asociado el efecto no tenga las propiedades Control.Layer . El
método OnDetached no proporciona ninguna implementación porque no se necesita limpieza.
Proyecto de Android
En el ejemplo de código siguiente se muestra la implementación LabelShadowEffect para el proyecto de 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);
}
}
Resumen
En este artículo se ha mostrado cómo usar propiedades CLR para pasar parámetros a un efecto. Las propiedades
CLR se pueden usar para definir parámetros de efecto que no responden a los cambios de propiedades en tiempo
de ejecución.
Vínculos relacionados
Representadores personalizados
Efecto
PlatformEffect
RoutingEffect
Efecto de sombra (ejemplo)
Pasar parámetros de efecto como propiedades
adjuntas
11/07/2019 • 19 minutes to read • Edit Online
Descargar el ejemplo
Las propiedades adjuntas se pueden usar para definir los parámetros de efecto que responden a los cambios de
propiedades en tiempo de ejecución. En este artículo se muestra cómo usar las propiedades adjuntas para pasar
parámetros a un efecto y cambiar un parámetro en tiempo de ejecución.
El proceso para crear parámetros de efecto que respondan a los cambios de propiedades en tiempo de ejecución
es el siguiente:
1. Se crea una clase static que contiene una propiedad adjunta para cada parámetro que se va a pasar al efecto.
2. Se agrega una propiedad adjunta adicional a la clase que se va a usar para controlar la adición o eliminación
del efecto del control al que se va a conectar la clase. Se asegura que esta propiedad adjunta registra un
delegado propertyChanged que se ejecutará cuando cambie el valor de la propiedad.
3. Se crean captadores y establecedores static para cada propiedad adjunta.
4. Se implementa la lógica en el delegado propertyChanged para agregar y quitar el efecto.
5. Se implementa una clase anidada dentro de la clase static , con el nombre del efecto, que crea subclases de la
clase RoutingEffect . Para el constructor, se llama al constructor de clase base, y se pasa una concatenación del
nombre del grupo de resolución y el identificador único que se ha especificado en cada clase de efecto
específica de la plataforma.
Después, se pueden pasar parámetros al efecto mediante la adición de las propiedades adjuntas y los valores de
propiedad al control adecuado. Además, los parámetros se pueden cambiar en tiempo de ejecución mediante la
especificación de un nuevo valor de propiedad adjunta.
NOTE
Una propiedad adjunta es un tipo especial de propiedad enlazable, definida en una clase, pero adjunta a otros objetos, y
reconocible en XAML como atributos que contienen una clase y un nombre de propiedad separados por un punto. Para
obtener más información, vea Propiedades adjuntas.
En la aplicación de ejemplo se muestra un elemento ShadowEffect que agrega una sombra al texto mostrado por
un control Label . Además, el color de la sombra se puede cambiar en tiempo de ejecución. En el diagrama
siguiente se ilustran las responsabilidades de cada proyecto en la aplicación de ejemplo, junto con las relaciones
entre ellos:
LabelShadowEffect personaliza un control Label en el elemento HomePage en cada proyecto específico de la
plataforma. Los parámetros se pasan a cada elemento LabelShadowEffect a través de las propiedades adjuntas de
la clase ShadowEffect . Cada clase LabelShadowEffect se deriva de la clase PlatformEffect para cada plataforma.
Como resultado, se agrega una sombra al texto mostrado por el control Label , como se muestra en las capturas
de pantalla siguientes:
ShadowEffect contiene cinco propiedades adjuntas, con captadores y establecedores static para cada propiedad
adjunta. Cuatro de estas propiedades representan los parámetros que se van a pasar a cada elemento
LabelShadowEffect específico de la plataforma. La clase ShadowEffect también define una propiedad adjunta
HasShadow que se usa para controlar la adición o eliminación del efecto del control al que se conecta la clase
ShadowEffect . Esta propiedad adjunta registra el método OnHasShadowChanged que se ejecutará cuando cambie el
valor de la propiedad. Este método agrega o quita el efecto en función del valor de la propiedad adjunta
HasShadow .
La clase LabelShadowEffect anidada, que crea subclases de la clase RoutingEffect , admite la adición y eliminación
de efectos. La clase RoutingEffect representa un efecto independiente de la plataforma que encapsula un efecto
interno, que suele ser específico de la plataforma. Esto simplifica el proceso de eliminación del efecto, ya que no
hay ningún acceso en tiempo de compilación a la información de tipo para un efecto específico de la plataforma. El
constructor LabelShadowEffect llama al constructor de clase base, y se pasa un parámetro que consiste en la
concatenación del nombre del grupo de resolución y el identificador único que se ha especificado en cada clase de
efecto específica de la plataforma. Esto habilita la adición y eliminación del efecto en el método
OnHasShadowChanged , como se indica a continuación:
Adición de efectos: se agrega una nueva instancia de LabelShadowEffect a la colección Effects del control.
Esto reemplaza al uso del método Effect.Resolve para agregar el efecto.
Eliminación de efectos: se recupera y se quita la primera instancia de LabelShadowEffect en la colección
Effects del control.
Style se puede aplicar a un control Label si se establece su propiedad Style en la instancia de Style mediante
la extensión de marcado StaticResource , como se muestra en el ejemplo de código siguiente:
Proyecto de iOS
En el ejemplo de código siguiente se muestra la implementación LabelShadowEffect para el proyecto de 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);
}
}
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));
}
}
El método OnAttached llama a métodos que recuperan los valores de propiedad adjunta mediante los captadores
ShadowEffect , y que establecen propiedades Control.Layer en los valores de propiedad para crear la sombra. Esta
funcionalidad se encapsula en un bloque try / catch en caso de que el control al que está asociado el efecto no
tenga las propiedades Control.Layer . El método OnDetached no proporciona ninguna implementación porque no
se necesita limpieza.
Respuesta a los cambios de propiedad
Si alguno de los valores de las propiedades adjuntas ShadowEffect cambia en tiempo de ejecución, el efecto debe
responder mostrando los cambios. Una versión invalidada del método OnElementPropertyChanged en la clase de
efecto específica de la plataforma es el lugar para responder a los cambios de propiedad enlazable, como se
muestra en el ejemplo de código siguiente:
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 ();
}
}
...
}
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);
}
}
El método OnAttached llama a métodos que recuperan los valores de propiedad adjunta mediante los captadores
ShadowEffect , y llama a un método que llama al método TextView.SetShadowLayer para crear una sombra con los
valores de propiedad. Esta funcionalidad se encapsula en un bloque try / catch en caso de que el control al que
está asociado el efecto no tenga las propiedades Control.Layer . El método OnDetached no proporciona ninguna
implementación porque no se necesita limpieza.
Respuesta a los cambios de propiedad
Si alguno de los valores de las propiedades adjuntas ShadowEffect cambia en tiempo de ejecución, el efecto debe
responder mostrando los cambios. Una versión invalidada del método OnElementPropertyChanged en la clase de
efecto específica de la plataforma es el lugar para responder a los cambios de propiedad enlazable, como se
muestra en el ejemplo de código siguiente:
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 ();
}
}
...
}
UpdateColor ();
UpdateOffset ();
void UpdateColor ()
{
shadowLabel.TextColor = ShadowEffect.GetColor (Element);
}
void UpdateOffset ()
{
shadowLabel.TranslationX = ShadowEffect.GetDistanceX (Element);
shadowLabel.TranslationY = ShadowEffect.GetDistanceY (Element);
}
}
}
Resumen
En este artículo se ha mostrado cómo usar propiedades adjuntas para pasar parámetros a un efecto y cambiar un
parámetro en tiempo de ejecución. Las propiedades adjuntas se pueden usar para definir los parámetros de efecto
que responden a los cambios de propiedades en tiempo de ejecución.
Vínculos relacionados
Representadores personalizados
Efecto
PlatformEffect
RoutingEffect
Efecto de sombra (ejemplo)
Invocación de eventos desde efectos
11/07/2019 • 38 minutes to read • Edit Online
Descargar el ejemplo
Un efecto puede definir e invocar un evento, señalando cambios en la vista nativa subyacente. En este artículo se
muestra cómo implementar seguimiento multitáctil de bajo nivel y cómo se generan eventos que indican
actividad táctil.
El efecto que se describe en este artículo proporciona acceso a eventos de función táctil de bajo nivel. Estos
eventos de bajo nivel no están disponibles a través de las clases GestureRecognizer existentes, pero son vitales
para algunos tipos de aplicaciones. Por ejemplo, una aplicación de dibujo táctil necesita realizar un seguimiento de
los dedos individuales cuando se mueven en la pantalla. Un teclado musical debe detectar cuándo se pulsan y
sueltan teclas individuales, así como un deslizamiento de dedos de una clave a otra en un glissando.
Un efecto es ideal para el seguimiento multitáctil, ya que puede asociarse a cualquier elemento de Xamarin.Forms.
En Android, la clase View define un método reemplazable denominado OnTouchEvent para procesar toda la
actividad táctil. El tipo de la actividad táctil se define por miembros de la enumeración Down , PointerDown , Move ,
Up y PointerUp tal como se describe en el artículo Multi-Touch Finger Tracking ( Seguimiento multitáctil). View
de Android también define un evento denominado Touch que permite que un controlador de eventos se adjunte
a cualquier objeto View .
En la Plataforma universal de Windows (UWP ), la clase UIElement define eventos denominados PointerPressed ,
PointerMoved y PointerReleased . Estos se describen en el artículo Handle pointer input ( Controlar la entrada del
puntero) de MSDN y en la documentación de API para la clase UIElement .
La API Pointer en la Plataforma universal de Windows está diseñada para unificar la entrada de mouse, táctil y
manuscrita. Por ese motivo, el evento PointerMoved se invoca cuando el mouse se mueve a través de un elemento,
incluso cuando no se presionó un botón del mouse. El objeto PointerRoutedEventArgs que acompaña a estos
eventos tiene una propiedad denominada Pointer , que tiene una propiedad denominada IsInContact , que indica
si se presiona un botón del mouse o un dedo está en contacto con la pantalla.
Además, la UWP define dos eventos más denominados PointerEntered y PointerExited . Estos indican si un dedo
o el mouse se mueven de un elemento a otro. Por ejemplo, imagine dos elementos adyacentes denominados A y
B. Ambos elementos tienen controladores instalados para los eventos de puntero. Cuando se presiona un dedo en
A, el evento PointerPressed se invoca. Cuando se mueve el dedo, A invoca eventos PointerMoved . Si el dedo se
mueve de A a B, A invoca un evento PointerExited y B invoca un evento PointerEntered . Si después se suelta el
dedo, B invoca un evento PointerReleased .
Las plataformas iOS y Android son diferentes de UWP: la vista que obtiene primero la llamada a TouchesBegan o
OnTouchEvent cuando un dedo toca la vista continúa obteniendo toda la actividad de interacción, incluso si se
mueve el dedo a distintas vistas. UWP puede comportarse de forma similar si la aplicación captura el puntero: en
el controlador de eventos PointerEntered , el elemento llama a CapturePointer y después obtiene toda la actividad
táctil de ese dedo.
El enfoque de UWP resulta muy útil para algunos tipos de aplicaciones, por ejemplo, un teclado musical. Cada
clave puede controlar los eventos táctiles para esa clave y detectar cuando un dedo se deslizó de una tecla a otra
mediante los eventos PointerEntered y PointerExited .
Por ese motivo, el efecto de seguimiento táctil que se describe en este artículo implementa el enfoque de UWP.
Todas las plataformas incluyen también un evento que indica que se ha cancelado el evento táctil.
La clase TouchEffect de la biblioteca .NET Standard deriva de RoutingEffect y define un evento denominado
TouchAction y un método denominado OnTouchAction que invoca al evento TouchAction :
Observe también la propiedad Capture . Para capturar eventos táctiles, una aplicación debe establecer esta
propiedad en true antes de un evento Pressed . En caso contrario, los eventos táctiles se comportan como los de
la Plataforma universal de Windows.
La clase TouchActionEventArgs en la biblioteca de .NET Standard contiene toda la información que acompaña a
cada evento:
Una aplicación puede utilizar la propiedad Id para el seguimiento de dedos individuales. Observe la propiedad
IsInContact . Esta propiedad es siempre true para eventos Pressed y false para eventos Released . También
es siempre true para eventos Moved en iOS y Android. La propiedad IsInContact podría ser false para Moved
eventos en la Plataforma universal de Windows cuando se ejecuta el programa en el escritorio y se mueve el
puntero del mouse sin un botón presionado.
Puede usar la clase TouchEffect en sus propias aplicaciones mediante la inclusión del archivo en el proyecto de
biblioteca de .NET Standard de la solución y mediante la adición de una instancia a la colección de Effects de
cualquier elemento de Xamarin.Forms. Adjunte un controlador al evento TouchAction para obtener los eventos
táctiles.
Para usar TouchEffect en su propia aplicación, también necesitará las implementaciones de plataforma incluidas
en la solución TouchTrackingEffectDemos.
namespace TouchTracking.UWP
{
public class TouchEffect : PlatformEffect
{
...
}
}
La invalidación OnAttached guarda información, como los campos, y adjunta los controladores a todos los eventos
de puntero:
OnPointerPressed también comprueba el valor de la propiedad Capture en la clase efecto en la biblioteca de .NET
Standard y llama a CapturePointer si es true .
Los otros controladores de eventos de UWP son incluso más sencillos:
La implementación de Android
Las implementaciones de Android y iOS son necesariamente más complejas porque deben implementar los
eventos Exited y Entered cuando un dedo se mueve de un elemento a otro. Ambas implementaciones tienen
una estructura similar.
La clase TouchEffect de Android instala un controlador para el evento Touch :
viewDictionary obtiene una nueva entrada cada vez que se llama a la invalidación OnAttached :
viewDictionary.Add(view, this);
La entrada se quita del diccionario en OnDetached . Todas las instancias de TouchEffect están asociadas a una vista
concreta a la que está conectada el efecto. El diccionario estático permite cualquier instancia de TouchEffect para
enumerar todas las demás vistas y sus correspondientes instancias de TouchEffect . Esto es necesario para
permitir la transferencia de los eventos de una vista a otra.
Android asigna un código de identificador a los eventos táctiles que permite que una aplicación realice un
seguimiento de los dedos individuales. El idToEffectDictionary asocia este código de identificador con una
instancia de TouchEffect . Se agrega un elemento a este diccionario cuando se llama al controlador Touch para
una pulsación de dedo:
idToEffectDictionary.Add(id, this);
capture = libTouchEffect.Capture;
break;
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;
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;
}
}
La implementación de iOS
La implementación de iOS es similar a la implementación de Android, salvo que la clase TouchEffect de iOS debe
crear una instancia de un derivado de UIGestureRecognizer . Se trata de una clase en el proyecto de iOS
denominado TouchRecognizer . Esta clase mantiene dos diccionarios estáticos que almacenan instancias de
TouchRecognizer :
static Dictionary<UIView, TouchRecognizer> viewDictionary =
new Dictionary<UIView, TouchRecognizer>();
Gran parte de la estructura de esta clase TouchRecognizer es similar a la de la clase TouchEffect de Android.
IMPORTANT
Muchas de las vistas de UIKit no tienen la funcionalidad táctil habilitada de forma predeterminada. La funcionalidad táctil
se puede habilitar agregando view.UserInteractionEnabled = true; a la invalidación OnAttached en la clase
TouchEffect en el proyecto de iOS. Esto debe ocurrir después obtener UIView , que se corresponde con el elemento al
que está asociado el efecto.
El método en el archivo de código subyacente que agrega un nuevo BoxView a AbsoluteLayout también agrega
un objeto TouchEffect para BoxView y adjunta un controlador de eventos para el efecto:
void AddBoxViewToLayout()
{
BoxView boxView = new BoxView
{
WidthRequest = 100,
HeightRequest = 100,
Color = new Color(random.NextDouble(),
random.NextDouble(),
random.NextDouble())
};
El controlador de eventos TouchAction procesa todos los eventos táctiles para todos los elementos de BoxView ,
pero debe usarse con cuidado: no puede permitir dos dedos en una sola BoxView porque el programa solo
implementa el arrastre y los dos dedos podrían interferir entre sí. Por este motivo, la página define una clase
incrustada para cada dedo del que está realizando el seguimiento:
class DragInfo
{
public DragInfo(long id, Point pressPoint)
{
Id = id;
PressPoint = pressPoint;
}
El dragDictionary contiene una entrada para cada BoxView que se arrastra actualmente.
La acción táctil Pressed agrega un elemento a este diccionario y la acción Released lo quita. La lógica Pressed
debe comprobar si ya hay un elemento en el diccionario para esa BoxView . Si es así, BoxView ya se está
arrastrando y el nuevo evento es un segundo dedo en esa misma BoxView . Para las acciones Moved y Released ,
el controlador de eventos debe comprobar si el diccionario tiene una entrada para esa BoxView y que la propiedad
Id táctil para la BoxView arrastrada coincide con el que aparece en la entrada del diccionario:
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));
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;
}
}
La lógica Pressed establece la propiedad Capture del objeto TouchEffect en true . Esto tiene el efecto de
entregar todos los eventos subsiguientes para ese dedo en el mismo controlador de eventos.
La lógica Moved mueve la BoxView modificando la propiedad adjunta LayoutBounds . La propiedad Location de
los argumentos de evento siempre es relativa a la BoxView que se está arrastrando y si el BoxView se está
arrastrando a una velocidad constante, las propiedades Location de los eventos consecutivos serán
aproximadamente las mismas. Por ejemplo, si un dedo presiona el BoxView en su centro, la acción Pressed
almacena una propiedad PressPoint de (50, 50), que sigue siendo la misma para los eventos posteriores. Si la
BoxView se arrastra en diagonal a una velocidad constante, las propiedades Location subsiguientes durante la
acción Moved podrían ser valores de (55, 55), en cuyo caso la lógica Moved agrega 5 a la posición horizontal y
vertical de la BoxView . Esto mueve la BoxView de forma que su centro está de nuevo directamente bajo el dedo.
Puede mover varios elementos BoxView al mismo tiempo usando diferentes dedos.
public DraggableBoxView()
{
TouchEffect touchEffect = new TouchEffect
{
Capture = true
};
touchEffect.TouchAction += OnTouchEffectAction;
Effects.Add(touchEffect);
}
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;
}
}
}
El constructor crea y adjunta el TouchEffect y establece la propiedad Capture cuando se crea una instancia de ese
objeto por primera vez. No se necesita ningún diccionario porque la propia clase almacena valores
isBeingDragged , pressPoint y touchId asociados con cada dedo. El control Moved modifica las propiedades
TranslationX y TranslationY , por lo que la lógica funcionará incluso si el elemento primario de la
DraggableBoxView no es un AbsoluteLayout .
Si después toca uno de los puntos suspensivos, puede arrastrarla a otra ubicación. Esto requiere una técnica
conocida como "prueba de posicionamiento," lo que implica buscar el objeto gráfico en un momento determinado.
Los puntos suspensivos de SkiaSharp no son elementos de Xamarin.Forms, por lo que no pueden realizar su
propio procesamiento de TouchEffect . El TouchEffect debe aplicarse a todo el objeto SKCanvasView .
El archivo EllipseDrawPage.xaml crea una instancia de SKCanvasView en un Grid de una sola celda. El objeto
TouchEffect se asocia a ese 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>
Cada elipse que representa SkiaSharp se representa mediante un objeto de tipo EllipseDrawingFigure :
class EllipseDrawingFigure
{
SKPoint pt1, pt2;
public EllipseDrawingFigure()
{
}
void MakeRectangle()
{
Rectangle = new SKRect(pt1.X, pt1.Y, pt2.X, pt2.Y).Standardized;
}
Las propiedades StartPoint y EndPoint se utilizan cuando el programa está procesando la entrada táctil; la
propiedad Rectangle se utiliza para dibujar la elipse. La propiedad LastFingerLocation entra en juego cuando se
arrastra la elipse y el método IsInEllipse ayuda en la prueba de posicionamiento. El método devuelve true si el
punto está dentro de la elipse.
El archivo de código subyacente mantiene tres colecciones:
La parte más complicada del procesamiento táctil es el control Pressed . Aquí es donde se realiza la prueba de
posicionamiento, pero si el código detecta una elipse bajo el dedo del usuario, dicha elipse solo se puede arrastrar
si actualmente no la está arrastrando otro dedo. Si no hay ninguna elipse bajo el dedo del usuario, el código
comienza el proceso de dibujar una elipse nueva:
case TouchActionType.Pressed:
bool isDragOperation = false;
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);
Otro ejemplo de SkiaSharp es la página Finger Paint (Dibujo con los dedos). Puede seleccionar un color de trazo
y el ancho del trazo desde dos vistas Picker y después dibujar con uno o más dedos:
Este ejemplo también requiere una clase independiente para representar cada línea dibujada en la pantalla:
class FingerPaintPolyline
{
public FingerPaintPolyline()
{
Path = new SKPath();
}
Un objeto SKPath se usa para representar cada línea. El archivo FingerPaint.xaml.cs mantiene dos colecciones de
estos objetos, una para aquellas polilíneas que se están dibujando actualmente y otra para las polilíneas
completadas:
El procesamiento de Pressed crea una nueva FingerPaintPolyline , llama a MoveTo en el objeto de ruta de acceso
para almacenar el punto inicial y agrega ese objeto al diccionario de inProgressPolylines . El procesamiento de
Moved llama a LineTo en el objeto de ruta con la nueva posición del dedo y el procesamiento de Released
transfiere la polilínea completada desde inProgressPolylines a completedPolylines . Una vez más, el código de
dibujo de SkiaSharp real es relativamente sencillo:
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();
Este tipo de procesamiento táctil es muy útil para un teclado de música. Una tecla debe ser capaz de detectar
cuándo se pulsa, pero también cuándo un dedo pasa de una tecla a otra.
La página Silent Keyboard teclado silencioso define clases WhiteKey y BlackKey pequeñas que derivan de Key ,
que se deriva de BoxView .
La clase Keyestá lista para usarse en un programa de música real. Define propiedades públicas denominadas
IsPressed y KeyNumber , que están pensadas para establecerse en el código de teclas que establece el estándar
MIDI. La clase Key también define un evento denominado StatusChanged , que se invoca cuando la propiedad
IsPressed cambia.
Se permiten varios dedos en cada tecla. Por este motivo, la clase Key mantiene una List de los números de Id.
táctil de todos los dedos que tocan actualmente esa tecla:
El controlador de eventos TouchAction agrega un identificador para la lista ids para un tipo de evento Pressed y
un tipo Entered , pero solo cuando la propiedad IsInContact es true para el evento Entered . Se quita el
identificador de la List para un evento Released o 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;
}
}
Los métodos AddToList y RemoveFromList comprueban si la List ha cambiado entre vacía y no vacía y si es así,
invocan el evento StatusChanged .
Los distintos elementos WhiteKey y BlackKey se organizan en el archivo XAML de la página, que tiene mejor
aspecto cuando se mantiene el teléfono en un modo horizontal:
Si pasa los dedos por las teclas, podrá ver por los pequeños cambios en el color que los eventos táctiles se
transfieren de una tecla a otra.
Resumen
En este artículo se mostró cómo invocar eventos en un efecto, y cómo escribir y usar un efecto que implementa el
procesamiento multitáctil de bajo nivel.
Vínculos relacionados
Multi-Touch Finger Tracking in iOS (Seguimiento de dedos multitáctil en iOS )
Multi-Touch Finger Tracking in Android (Seguimiento de dedos multitáctil en Android)
Touch Tracking Effect (sample) (Efecto de seguimiento táctil [ejemplo])
Gestos de Xamarin.Forms
11/07/2019 • 2 minutes to read • Edit Online
Reconocedores de gestos que se usan para detectar la interacción del usuario con las vistas en una aplicación de
Xamarin.Forms.
La clase GestureRecognizer de Xamarin.Forms admite los gestos de pulsar, reducir, desplazar lateralmente y
deslizar rápidamente en instancias de View .
Descargar el ejemplo
El gesto de pulsar se usa para la detección de pulsaciones y se implementa con la clase TapGestureRecognizer.
Para que se pueda hacer clic en un elemento de interfaz de usuario con el gesto de pulsar, cree una instancia de
TapGestureRecognizer , controle el evento Tapped , y agregue el nuevo reconocedor de gestos a la colección
GestureRecognizers en el elemento de interfaz de usuario. En el ejemplo de código siguiente se muestra un
elemento TapGestureRecognizer adjunto a un elemento Image :
tapGestureRecognizer.NumberOfTapsRequired = 2; // double-tap
Cuando se establece NumberOfTapsRequired por encima de uno, el controlador de eventos solo se ejecuta si las
pulsaciones se producen dentro de un período de tiempo concreto (que no se puede configurar). Si la segunda
pulsación (o las posteriores) no se producen dentro de ese período, se omiten y se reinicia el "recuento de
pulsaciones".
Uso de Xaml
Un reconocedor de gestos se puede agregar a un control en Xaml mediante propiedades adjuntas. La sintaxis para
agregar un elemento TapGestureRecognizer a una imagen se muestra a continuación (en este caso se define un
evento de pulsación doble):
<Image Source="tapped.jpg">
<Image.GestureRecognizers>
<TapGestureRecognizer
Tapped="OnTapGestureRecognizerTapped"
NumberOfTapsRequired="2" />
</Image.GestureRecognizers>
</Image>
El código para el controlador de eventos (en el ejemplo) incrementa un contador y cambia la imagen de color a
blanco y negro.
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";
}
}
Uso de ICommand
Las aplicaciones que usan el patrón Model-View -ViewModel (MVVM ) suelen usar ICommand en lugar de conectar
controladores de eventos directamente. El elemento TapGestureRecognizer puede admitir fácilmente ICommand
estableciendo el enlace en el código:
o con Xaml:
<Image Source="tapped.jpg">
<Image.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding TapCommand}"
CommandParameter="Image1" />
</Image.GestureRecognizers>
</Image>
El código completo para este modelo de vista se puede encontrar en el ejemplo. A continuación se muestran los
detalles de implementación de Command relevantes:
Vínculos relacionados
TapGesture (ejemplo)
GestureRecognizer
TapGestureRecognizer
Agregar un reconocedor de gestos de reducir
11/07/2019 • 5 minutes to read • Edit Online
Descargar el ejemplo
El gesto de reducir se usa para realizar un zoom interactivo y se implementa con la clase PinchGestureRecognizer.
Un escenario común para el gesto de reducir es realizar un zoom interactivo de una imagen en la ubicación donde
se realice el gesto. Esto se logra al escalar el contenido de la ventanilla, como se demuestra en este artículo.
Para que un elemento de interfaz de usuario se pueda mover con el gesto de reducir, cree una instancia de
PinchGestureRecognizer , controle el evento PinchUpdated y agregue el nuevo reconocedor de gestos a la colección
GestureRecognizers en el elemento de interfaz de usuario. En el siguiente ejemplo de código, se muestra un
elemento PinchGestureRecognizer asociado a un elemento Image :
Esto también se puede lograr en XAML, como se muestra en el ejemplo de código siguiente:
<Image Source="waterfront.jpg">
<Image.GestureRecognizers>
<PinchGestureRecognizer PinchUpdated="OnPinchUpdated" />
</Image.GestureRecognizers>
</Image>
Después, se agrega el código del controlador de eventos OnPinchUpdated al archivo de código subyacente:
public PinchToZoomContainer ()
{
var pinchGesture = new PinchGestureRecognizer ();
pinchGesture.PinchUpdated += OnPinchUpdated;
GestureRecognizers.Add (pinchGesture);
}
Esta clase se puede encapsular en un elemento de interfaz de usuario para que el gesto de reducir amplíe o
reduzca el elemento de interfaz de usuario encapsulado. En el siguiente ejemplo de código de XAML, se muestra
cómo encapsular PinchToZoomContainer en un 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>
Cuando el elemento Image recibe un gesto de reducir, la imagen mostrada se ampliará o reducirá. La acción de
zoom se realiza mediante el método PinchZoomContainer.OnPinchUpdated , que se muestra en el siguiente ejemplo de
código:
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);
Este método actualiza el nivel de zoom del elemento de la interfaz de usuario encapsulada basándose en el gesto
de reducir del usuario. Para lograr esto, se usan los valores de las propiedades Scale , ScaleOrigin y Status de la
instancia de PinchGestureUpdatedEventArgs para calcular el factor de escala que se aplicará en el origen del gesto de
reducir. El elemento del usuario encapsulado se amplía o reduce en el origen del gesto de reducir al establecer las
propiedades TranslationX , TranslationY y Scale en los valores calculados.
Vínculos relacionados
PinchGesture (ejemplo)
GestureRecognizer
PinchGestureRecognizer
Adición de un reconocedor de gesto de
desplazamiento lateral
11/07/2019 • 6 minutes to read • Edit Online
Descargar el ejemplo
El gesto de desplazamiento lateral se usa para detectar el movimiento de los dedos alrededor de la pantalla y
aplicar ese movimiento al contenido, y se implementa con la clase PanGestureRecognizer . Un escenario habitual
para el gesto de desplazamiento lateral consiste en desplazar una imagen de forma horizontal y vertical, para
poder ver todo el contenido de imagen cuando se muestre en una ventanilla más pequeña que las dimensiones de
la imagen. Esto se logra moviendo la imagen dentro de la ventanilla, y se muestra en este artículo.
Para que un elemento de interfaz de usuario se pueda mover con el gesto de desplazamiento lateral, cree una
instancia de PanGestureRecognizer , controle el evento PanUpdated y agregue el nuevo reconocedor de gestos a la
colección GestureRecognizers en el elemento de interfaz de usuario. En el ejemplo de código siguiente se muestra
un elemento PanGestureRecognizer adjunto a un elemento Image :
Esto también se puede lograr en XAML, como se muestra en el ejemplo de código siguiente:
<Image Source="MonoMonkey.jpg">
<Image.GestureRecognizers>
<PanGestureRecognizer PanUpdated="OnPanUpdated" />
</Image.GestureRecognizers>
</Image>
Después, se agrega el código para el controlador de eventos OnPanUpdated al archivo de código subyacente:
NOTE
El desplazamiento lateral correcto en Android requiere el paquete NuGet Xamarin.Forms 2.1.0-pre1 como mínimo.
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);
}
Esta clase se puede encapsular en un elemento de interfaz de usuario para que el gesto desplace el elemento de
interfaz de usuario encapsulado. En el ejemplo de código XAML siguiente se muestra la encapsulación de
PanContainer en un 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>
En el ejemplo de código siguiente se muestra cómo el elemento PanContainer encapsula un elemento Image en
una página de C#:
En los dos ejemplos, las propiedades WidthRequest y HeightRequest se establecen en los valores de alto y ancho
de la imagen que se va a mostrar.
Cuando el elemento Image recibe un gesto de desplazamiento lateral, se desplaza lateralmente la imagen
mostrada. El desplazamiento lateral se realiza mediante el método PanContainer.OnPanUpdated , que se muestra en
el ejemplo de código siguiente:
case GestureStatus.Completed:
// Store the translation applied during the pan
x = Content.TranslationX;
y = Content.TranslationY;
break;
}
}
Este método actualiza el contenido visible del elemento de interfaz de usuario encapsulado, en función del gesto de
desplazamiento lateral del usuario. Esto se logra mediante el uso de los valores de las propiedades TotalX y
TotalY de la instancia de PanUpdatedEventArgs para calcular la dirección y la distancia del desplazamiento lateral.
Las propiedades App.ScreenWidth y App.ScreenHeight proporcionan el alto y ancho de la ventanilla, y se
establecen en los valores de ancho y alto de la pantalla del dispositivo por los proyectos específicos de la
plataforma correspondiente. Después, se realiza el desplazamiento lateral del elemento de usuario encapsulado,
mediante el establecimiento de sus propiedades TranslationX y TranslationY en los valores calculados.
Al desplazar lateralmente el contenido de un elemento que no ocupa toda la pantalla, el alto y ancho de la
ventanilla se pueden obtener de las propiedades Height y Width del elemento.
NOTE
Mostrar imágenes de alta resolución puede aumentar considerablemente la superficie de memoria de una aplicación. Por
tanto, solo se deberían crear cuando sea necesario y deberían liberarse en cuanto la aplicación ya no las necesite. Para más
información, vea Optimizar los recursos de imagen.
Vínculos relacionados
PanGesture (ejemplo)
GestureRecognizer
PanGestureRecognizer
Agregar un reconocedor de gesto de deslizar
rápidamente
11/07/2019 • 9 minutes to read • Edit Online
Descargar el ejemplo
Un gesto de deslizar rápidamente se produce cuando un dedo se mueve a través de la pantalla en dirección
horizontal o vertical y, a menudo, se usa para iniciar la navegación a través del contenido. Los ejemplos de código
en este artículo están sacados del ejemplo Swipe Gesture (Gesto de deslizar rápidamente).
Para hacer que View reconozca un gesto de deslizar rápidamente, cree una instancia de SwipeGestureRecognizer ,
establezca la propiedad Direction en un valor de enumeración de SwipeDirection ( Left , Right , Up o Down ),
opcionalmente establezca la propiedad Threshold , controle el evento Swiped y agregue el reconocedor de gestos
nuevo a la colección GestureRecognizers de la vista. En el ejemplo de código siguiente se muestra un elemento
SwipeGestureRecognizer adjunto a BoxView :
boxView.GestureRecognizers.Add(leftSwipeGesture);
La clase SwipeGestureRecognizer también incluye una propiedad Threshold , que opcionalmente se puede
establecer en un valor uint que representa la distancia mínima que debe deslizarse un dedo para que se
reconozca el deslizamiento, en unidades independientes del dispositivo. El valor predeterminado de esta propiedad
es 100, lo cual significa que cualquier deslizamiento por debajo de 100 unidades independientes del dispositivo se
ignorará.
De forma similar, se pueden reconocer los deslizamientos que se producen en el eje horizontal estableciendo la
propiedad Direction en Up y Down :
var swipeGesture = new SwipeGestureRecognizer { Direction = SwipeDirection.Up | SwipeDirection.Down };
Como alternativa, puede crearse un SwipeGestureRecognizer para cada dirección de deslizamiento para que
reconozca los deslizamientos en cada dirección:
boxView.GestureRecognizers.Add(leftSwipeGesture);
boxView.GestureRecognizers.Add(rightSwipeGesture);
boxView.GestureRecognizers.Add(upSwipeGesture);
boxView.GestureRecognizers.Add(downSwipeGesture);
NOTE
En los ejemplos anteriores, el mismo controlador de eventos responde a la activación del evento Swiped . Sin embargo, cada
instancia de SwipeGestureRecognizer puede usar un controlador de eventos distinto, si es necesario.
Respuesta al deslizamiento
En el ejemplo siguiente, se muestra un controlador de eventos para el evento Swiped :
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;
}
}
SwipedEventArgs puede examinarse para determinar la dirección del deslizamiento, con lógica personalizada como
respuesta al deslizamiento, según sea necesario. Se puede obtener la dirección del deslizamiento desde la
propiedad Direction de los argumentos de evento, que se establecerán en uno de los valores de la enumeración
de SwipeDirection . Además, los argumentos de evento también tienen una propiedad Parameter que se
establecerá en el valor de la propiedad CommandParameter , si se ha definido.
Uso de comandos
La clase SwipeGestureRecognizer también incluye las propiedades Command y CommandParameter . Estas propiedades
se utilizan normalmente en aplicaciones que usan el patrón Model-View -ViewModel (MVVM ). La propiedad
Command define el elemento ICommand que se invocará cuando se reconoce un gesto de deslizar rápidamente, con
la propiedad CommandParameter que define un objeto que se pasará al elemento ICommand. . El ejemplo de código
siguiente muestra cómo enlazar la propiedad Command a un elemento ICommand definido en el modelo de vista
cuya instancia se ha establecido como la página BindingContext :
SwipeCommand es una propiedad de tipo ICommand definida en la instancia de modelo de vista que se establece
como la página BindingContext . Cuando se reconoce un gesto de deslizar rápidamente, se ejecuta el método
Execute del objeto SwipeCommand . El argumento para el método Execute es el valor de la propiedad
CommandParameter . Para obtener más información sobre los comandos, consulte The Command Interface ( La
interfaz de comandos).
public SwipeContainer()
{
GestureRecognizers.Add(GetSwipeGestureRecognizer(SwipeDirection.Left));
GestureRecognizers.Add(GetSwipeGestureRecognizer(SwipeDirection.Right));
GestureRecognizers.Add(GetSwipeGestureRecognizer(SwipeDirection.Up));
GestureRecognizers.Add(GetSwipeGestureRecognizer(SwipeDirection.Down));
}
En el ejemplo de código XAML siguiente se muestra la clase SwipeContainer que realiza el ajuste de BoxView :
<ContentPage ...>
<StackLayout>
<local:SwipeContainer Swipe="OnSwiped" ...>
<BoxView Color="Teal" ... />
</local:SwipeContainer>
</StackLayout>
</ContentPage>
En el ejemplo de código siguiente se muestra cómo SwipeContainer realiza el ajuste de BoxView en una página de
C#:
Cuando BoxView recibe un gesto de deslizar rápidamente, el evento Swiped en SwipeGestureRecognizer se activa.
Esto se controla mediante la clase SwipeContainer , que activa su propio evento Swipe . Este evento Swipe se
controla en la página. Posteriormente, SwipedEventArgs puede examinarse para determinar la dirección del
deslizamiento, con lógica personalizada como respuesta al deslizamiento, según sea necesario.
Vínculos relacionados
Gesto de deslizar rápidamente (ejemplo)
GestureRecognizer
SwipeGestureRecognizer
Localización de Xamarin.Forms
11/07/2019 • 2 minutes to read • Edit Online
El marco de trabajo de localización integrado de .NET puede usarse para generar aplicaciones multilingües
multiplataforma con Xamarin.Forms.
Descargar el ejemplo
Las aplicaciones de Xamarin.Forms se pueden localizar con archivos de recursos. NET.
Información general
El mecanismo integrado para la localización de aplicaciones .NET usa archivos RESX y las clases de los espacios de
nombres System.Resources y System.Globalization . Los archivos RESX que contienen las cadenas traducidas se
insertan en el ensamblado de Xamarin.Forms, junto con una clase generada por el compilador que proporciona
acceso fuertemente tipado a las traducciones. Después, se puede recuperar el texto traducido en el código.
Código de ejemplo
Hay dos ejemplos relacionados con este documento:
UsingResxLocalization es una demostración muy simple de los conceptos explicados. Los fragmentos de código
que se muestran a continuación son todos de este ejemplo.
TodoLocalized es una aplicación básica de trabajo que usa estas técnicas de localización.
No se recomiendan los proyectos compartidos
El ejemplo TodoLocalized incluye una demostración del proyecto compartido; sin embargo, debido a las
limitaciones del sistema de compilación, los archivos de recursos no obtienen un archivo .designer.cs generado, lo
cual interrumpe la capacidad de tener acceso a cadenas traducidas fuertemente tipadas en el código.
El resto de este documento se relaciona con los proyectos que utilizan la plantilla de biblioteca .NET Standard de
Xamarin.Forms.
NOTE
En la Plataforma universal de Windows, los archivos RESW deben usarse para la localización de notificaciones push, en lugar
de los archivos RESX. Para obtener más información, consulte Localización de UWP.
Adición de recursos
El primer paso para la globalización de una aplicación de biblioteca .NET Standard de Xamarin.Forms es agregar
los archivos de recursos RESX que se usarán para almacenar todo el texto que se usa en la aplicación. Necesitamos
agregar un archivo RESX que contiene el texto predeterminado y, a continuación, agregar los archivos RESX
adicionales para cada idioma que desee admitir.
Recurso de idioma base
El archivo de recursos base (RESX) contendrá las cadenas del idioma predeterminado (en los ejemplos se asume
que el idioma predeterminado es el inglés). Agregue el archivo al proyecto de código común de Xamarin.Forms,
haciendo clic con el botón derecho en el proyecto y eligiendo Agregar > Nuevo archivo...
Elija un nombre descriptivo, como AppResources, y pulse Aceptar.
Vi si b i l i d a d d e l a c a d e n a
De forma predeterminada, cuando se generan referencias fuertemente tipadas para las cadenas, serán de tipo
internal para el ensamblado. Esto es así porque la herramienta de compilación predeterminada para los archivos
RESX genera el archivo .designer.cs con propiedades de tipo internal .
Seleccione el archivo AppResources.resx y observe el panel Propiedades para ver dónde está configurada esta
herramienta de compilación. La captura de pantalla siguiente muestra Herramienta personalizada:
ResXFileCodeGenerator.
Visual Studio
Visual Studio para Mac
Para hacer que las propiedades de la cadena fuertemente tipada sean public , debe cambiar manualmente la
configuración a Herramienta personalizada: PublicResXFileCodeGenerator, tal y como se muestra en la
captura de pantalla siguiente:
Visual Studio
Visual Studio para Mac
Este cambio es opcional y solo es necesario si desea hacer referencia a las cadenas localizadas en ensamblados
diferentes (por ejemplo, si coloca los archivos RESX en un ensamblado diferente en el código). El ejemplo de este
tema deja las cadenas de tipo internal porque ya están definidas en el mismo ensamblado de biblioteca estándar
.NET Standard de Xamarin.Forms en que se usan.
Basta con establecer la herramienta personalizada en el archivo RESX base tal como se muestra anteriormente; no
es necesario establecer ninguna herramienta de compilación en los archivos RESX específicos del idioma que se
describen en las secciones siguientes.
Ed i c i ó n d e l a r c h i v o R E SX
Por desgracia, no hay ningún editor de RESX integrado en Visual Studio para Mac. La adición de nuevas cadenas
traducibles requiere la adición de un elemento data XML nuevo para cada cadena. Cada elemento data puede
contener lo siguiente:
El atributo name (obligatorio) es la clave para esta cadena traducible. Debe ser un nombre de propiedad C#
válido, por lo que no se permiten espacios ni caracteres especiales.
El elemento value (obligatorio), que es la cadena real que se muestra en la aplicación.
El elemento comment (opcional) puede contener instrucciones para el traductor, con explicaciones sobre cómo
se utiliza esta cadena.
El atributo xml:space (opcional) para controlar cómo se conserva el espaciado en la cadena.
A medida que se escribe la aplicación, cada fragmento de texto que se muestra al usuario debe agregarse al
archivo de recursos RESX base en un nuevo elemento data . Se recomienda incluir elementos comment , tantos
como sea posible, para garantizar una traducción de alta calidad.
NOTE
Visual Studio (incluida la edición gratuita Community) contiene un editor de RESX básico. Si tiene acceso a un equipo
Windows, esta puede ser una manera cómoda de agregar y editar las cadenas en archivos RESX.
A medida que se desarrolla una aplicación y el archivo RESX base tiene texto agregado, debe enviarla a los
traductores, que traducirán cada elemento data y devolverán un archivo de recursos específicos de idioma (con la
convención de nomenclatura que se muestra) para incluir en la aplicación. A continuación, se muestran algunos
ejemplos "traducidos automáticamente":
AppResources.es.resx (español)
El traductor solo debe actualizar el elemento value ; el elemento comment no está pensado para traducirse.
Recuerde: al editar archivos XML, deben aplicarse secuencias de escape a los caracteres reservados, como < , > ,
& con < , > y & si aparecen en value o comment .
La interfaz de usuario en iOS, Android y la Plataforma universal de Windows (UWP ) se representa del modo
esperado, salvo que ahora es posible traducir la aplicación en varios idiomas porque el texto que se carga desde un
recurso en vez de estar codificado de forma rígida. La siguiente captura de pantalla muestra la interfaz de usuario
en cada plataforma antes de la traducción:
Solución de problemas
Prueba de un lenguaje específico
Puede resultar complicado cambiar el simulador o un dispositivo a idiomas distintos, especialmente durante el
desarrollo, cuando se quieren probar rápidamente las distintas referencias culturales.
Puede forzar la carga de un idioma específico estableciendo el elemento Culture tal como se muestra en este
fragmento de código:
// force a specific culture, useful for quick testing
AppResources.Culture = new CultureInfo("fr-FR");
Este enfoque, establecer la referencia cultural directamente en la clase AppResources , también se puede usar para
implementar un selector de idioma dentro de la aplicación (en lugar de utilizar la configuración regional del
dispositivo).
Carga de recursos incrustados
El siguiente fragmento de código es útil cuando se intenta depurar problemas con los recursos incrustados (por
ejemplo, los archivos RESX). Agregue este código a la aplicación (al principio del ciclo de vida de aplicación) y
obtendrá una lista de todos los recursos incrustados en el ensamblado, que muestra el identificador del 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);
}
System.Resources.ResourceManager temp =
new System.Resources.ResourceManager(
"UsingResxLocalization.Resx.AppResources",
typeof(AppResources).GetTypeInfo().Assembly);
Compruebe el resultado de la aplicación para los resultados del código de depuración que se muestra arriba,
para confirmar que se indican los recursos correctos (es decir, "UsingResxLocalization.Resx.AppResources" ).
Si no es así, la clase AppResources no podrá cargar sus recursos. Compruebe lo siguiente para resolver los
problemas que surgen cuando no se pueden encontrar los recursos:
El espacio de nombres predeterminado para el proyecto coincide con el espacio de nombres raíz en el archivo
AppResources.Designer.cs.
Si el archivo AppResources.resx se encuentra en un subdirectorio, el nombre del subdirectorio debe formar
parte del espacio de nombres y debe formar parte del identificador de recursos.
El archivo AppResources.resx tiene la Acción de compilación: EmbeddedResource.
La opción Project Options > Source Code > .NET Naming Policies > Use Visual Studio-style resources
names (Opciones del proyecto > Código fuente > Directivas de nomenclatura de .NET > Usar nombres de
recursos de estilo Visual Studio) está activada. Puede desactivarla, si lo prefiere, pero los espacios de nombres
que se usan al hacer referencia a los recursos RESX tendrán que actualizarse en toda la aplicación.
No funciona en modo de DEPURACIÓN (solo Android)
Si las cadenas traducidas funcionan en las compilaciones de Android PUBLICADAS pero no durante la
depuración, haga clic con el botón derecho en Android Project (Proyecto de Android), seleccione Options >
Build > Android Build (Opciones > Compilar > Compilación de Android ) y asegúrese de que la opción Fast
assembly deployment (Implementación de ensamblado rápido) NO esté activada. Esta opción provoca
problemas con la carga de recursos y no debe usarse si se están probando aplicaciones localizadas.
Visualización del idioma correcto
Hasta ahora hemos examinado cómo escribir código para que se puedan proporcionar traducciones, pero no para
hacer que aparezcan en realidad. El código de Xamarin.Forms puede aprovechar recursos de .NET para cargar las
traducciones en el idioma correcto, pero es necesario consultar el sistema operativo en cada plataforma para
determinar el idioma que ha seleccionado el usuario.
Dado que se requiere algún código específico de la plataforma para obtener la preferencia de idioma del usuario,
utilice un servicio de dependencia para exponer esta información en la aplicación de Xamarin.Forms e
implementarla para cada plataforma.
En primer lugar, defina una interfaz para exponer la referencia cultural preferida del usuario, de forma similar al
código siguiente:
En segundo lugar, utilice DependencyService en la clase App de Xamarin.Forms para llamar a la interfaz y
establecer la referencia cultural de nuestros recursos RESX en el valor correcto. Tenga en cuenta que no es
necesario establecer manualmente este valor para la Plataforma universal de Windows, ya que el marco de trabajo
de los recursos reconoce automáticamente el idioma seleccionado en estas plataformas.
El recurso Culture debe establecerse cuando la aplicación se carga por primera vez, para que se utilicen las
cadenas de idioma correctas. Opcionalmente, puede actualizar este valor conforme a los eventos específicos de la
plataforma que se generen en iOS o Android, si el usuario actualiza sus preferencias de idioma mientras se ejecuta
la aplicación.
Las implementaciones para la interfaz ILocalize se muestran en la sección siguiente, Código específico de la
plataforma. Estas implementaciones aprovechan esta clase 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;
}
}
[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;
}
NOTE
Los bloques try/catch en el método GetCurrentCultureInfo imitan el comportamiento de reserva que se utiliza
normalmente con los especificadores de configuración regional: si no se encuentra la coincidencia exacta, debe buscarse una
coincidencia próxima basándose solo en el idioma (primer bloque de caracteres en la configuración regional).
En el caso de Xamarin.Forms, algunas configuraciones regionales son válidas en iOS, pero no corresponden a una
CultureInfo válida en .NET; el código anterior intenta controlar esta cuestión.
Por ejemplo, la pantalla de iOS Ajustes > Idioma general & Región le permite establecer el Idioma del teléfono como
inglés pero la Región como España, lo cual da como resultado una cadena de configuración regional "en-ES" . Cuando
falla la creación de CultureInfo , el código vuelve a utilizar solo las dos primeras letras para seleccionar el idioma que se
mostrará.
Los desarrolladores pueden modificar los métodos iOSToDotnetLanguage y ToDotnetFallbackLanguage para controlar los
casos específicos necesarios para sus idiomas admitidos.
Algunos elementos de la interfaz de usuario definidos por el sistema los traduce automáticamente iOS, como el
botón Listo del control Picker . Para obligar a iOS a traducir estos elementos, se debe indicar qué idiomas se
admiten en el archivo Info.plist. Puede agregar estos valores a través de Info.plist > Origen, como se muestra
aquí:
De forma alternativa, abra el archivo Info.plist en un editor XML y edite los valores directamente:
<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>
Una vez que haya implementado el servicio de dependencia y haya actualizado Info.plist, la aplicación de iOS
podrá mostrar el texto traducido.
NOTE
Tenga en cuenta que Apple trata el idioma portugués de un modo ligeramente distinto de lo que cabría esperar. En su
documentación podemos leer una información relacionada, que indica la necesidad de utilizar pt como identificador de
idioma para el portugués que se utiliza en Brasil, y pt-PT como identificador de idioma para el portugués que se utiliza en
Portugal. Esto significa que cuando se elige el portugués en una configuración regional no estándar, el idioma de reserva
será el portugués de Brasil en iOS, a menos que se escriba código para cambiar este comportamiento (como
ToDotnetFallbackLanguage en el ejemplo anterior).
Para obtener más información sobre la localización de iOS, consulte Localización de iOS.
Proyecto de aplicación de Android
Android expone la configuración regional seleccionada actualmente a través de Java.Util.Locale.Default y
también usa un separador de carácter de subrayado en lugar de un guion (que será sustituido por el código
siguiente). Agregue esta implementación de servicio de dependencia al proyecto de aplicación de 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-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
Los bloques try/catch en el método GetCurrentCultureInfo imitan el comportamiento de reserva que se utiliza
normalmente con los especificadores de configuración regional: si no se encuentra la coincidencia exacta, debe buscarse una
coincidencia próxima basándose solo en el idioma (primer bloque de caracteres en la configuración regional).
En el caso de Xamarin.Forms, algunas configuraciones regionales son válidas en Android, pero no corresponden a una
CultureInfo válida en .NET; el código anterior intenta controlar esta cuestión.
Los desarrolladores pueden modificar los métodos iOSToDotnetLanguage y ToDotnetFallbackLanguage para controlar los
casos específicos necesarios para sus idiomas admitidos.
Una vez que este código se haya agregado al proyecto de aplicación de Android, podrá mostrar automáticamente
las cadenas traducidas.
NOTE
ADVERTENCIA: Si las cadenas traducidas funcionan en las compilaciones de Android PUBLICADAS pero no durante la
depuración, haga clic con el botón derecho en Android Project (Proyecto de Android), seleccione Options > Build >
Android Build (Opciones > Compilar > Compilación de Android ) y asegúrese de que la opción Fast assembly
deployment (Implementación de ensamblado rápido) NO esté activada. Esta opción provoca problemas con la carga de
recursos y no debe usarse si se están probando aplicaciones localizadas.
Para obtener más información sobre la localización de Android, consulte Localización de Android.
Plataforma universal de Windows
Los proyectos de la Plataforma universal de Windows (UWP ) no requieren el servicio de dependencia. En su lugar,
esta plataforma establece automáticamente la referencia cultural del recurso correctamente.
A sse m b l y I n fo .c s
Expanda el nodo Propiedades en el proyecto de biblioteca de .NET Standard y haga doble clic en el archivo
AssemblyInfo.cs. Agregue la siguiente línea al archivo para establecer el lenguaje de ensamblado de recursos
independiente del idioma como inglés:
[assembly: NeutralResourcesLanguage("en")]
Esto informa al administrador de recursos acerca de la referencia cultural predeterminada de la aplicación y, por lo
tanto, garantiza que las cadenas definidas en el archivo RESX independiente de idioma (AppResources.resx) se
mostrarán cuando la aplicación se ejecute en una de las configuraciones regionales del inglés.
Ejemplo
Después de actualizar los proyectos específicos de plataforma, como se muestra anteriormente, y volver a compilar
la aplicación con archivos RESX traducidos, las traducciones actualizadas estarán disponibles en cada aplicación.
Esta es una captura de pantalla del código de ejemplo traducido a chino simplificado:
Para obtener más información sobre la localización de la plataforma universal de Windows, consulte Localización
de UWP.
Localización de XAML
Al compilar una interfaz de usuario de Xamarin.Forms en XAML, el marcado tendrá un aspecto similar al siguiente,
con cadenas insertadas directamente en el código XML:
El escenario ideal sería poder traducir los controles de interfaz de usuario directamente en XAML, lo cual puede
hacerse mediante la creación de una extensión de marcado. El código para una extensión de marcado que expone
los recursos RESX en XAML se muestra a continuación. Esta clase se debe agregar al código común de
Xamarin.Forms (junto con las 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";
public TranslateExtension()
{
if (Device.RuntimePlatform == Device.iOS || Device.RuntimePlatform == Device.Android)
{
ci = DependencyService.Get<ILocalize>().GetCurrentCultureInfo();
}
}
El fragmento de código XAML siguiente muestra cómo usar la extensión de marcado. Su funcionamiento requiere
dos pasos:
1. Declarar el espacio de nombres xmlns:i18n personalizado en el nodo raíz. namespace y assembly deben tener
exactamente la misma configuración del proyecto; en este ejemplo es idéntica, pero podría ser diferente en su
proyecto específico.
2. Usar la sintaxis {Binding} en los atributos que normalmente deben contener el texto para llamar a la extensión
de marcado Translate . La clave de recurso es el único parámetro necesario.
<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 las plataformas resolverán automáticamente las referencias de imágenes como éstas en las versiones
localizadas de las imágenes, siempre y cuando se implementen las estructuras de proyecto que se explican a
continuación.
Proyecto de aplicación de iOS
iOS utiliza una denominación estándar, Proyectos de localización, o directorios .lproj que contienen recursos de
cadena e imagen. Estos directorios pueden contener las versiones localizadas de imágenes que se usan en la
aplicación y también el archivo InfoPlist.strings que se puede usar para localizar el nombre de la aplicación. Para
obtener más información sobre la localización de iOS, consulte Localización de iOS.
Imágenes
Esta captura de pantalla muestra la aplicación de ejemplo de iOS con directorios .lproj específicos del idioma. El
directorio del idioma español, denominado es.lproj, contiene las versiones localizadas de la imagen
predeterminada, así como flag.png:
Cada directorio de idioma contiene una copia de flag.png, localizada para dicho idioma. Si no se proporciona
ninguna imagen, el sistema operativo será la imagen del directorio de idioma predeterminado. Para obtener
compatibilidad total con la pantalla Retina, debe proporcionar copias @2x y @3x de cada imagen.
Nombre de la aplicación
El contenido de InfoPlist.strings es simplemente un único par clave-valor para configurar el nombre de la
aplicación:
"CFBundleDisplayName" = "ResxEspañol";
Tenga en cuenta que Android no usa los códigos zh-Hans y zh-Hant para chino simplificado y tradicional; en su
lugar, solo admite los códigos específicos de país zh-CN y zh-TW.
Para admitir imágenes de una resolución distinta para las pantallas de alta densidad, cree carpetas de idioma
adicionales con sufijos -*dpi , como drawables-es-mdpi, drawables-es-xdpi, drawables-es-xxdpi, y así
sucesivamente. Consulte Providing Alternative Android Resources (Proporcionar recursos de Android alternativos)
para obtener más información.
Nombre de la aplicación
El contenido de Strings.xml es simplemente un único par clave-valor para configurar el nombre de la aplicación:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">ResxEspañol</string>
</resources>
Actualice MainActivity.cs en el proyecto de aplicación de Android para que Label haga referencia a las cadenas
XML.
La aplicación ahora localiza la imagen y el nombre de la aplicación. Esta es una captura de pantalla del resultado
(en español):
Vínculos relacionados
Ejemplo de localización de RESX
Aplicación de ejemplo TodoLocalized
Localización multiplataforma
Localización de iOS
Localización de Android
Localización de UWP
Utilizar la clase CultureInfo (MSDN )
Buscar y utilizar recursos para una referencia cultural específica (MSDN )
Localización de derecha a izquierda
11/07/2019 • 9 minutes to read • Edit Online
Descargar el ejemplo
La localización de derecha a izquierda agrega compatibilidad para la dirección de flujo de derecha a izquierda
para las aplicaciones de Xamarin.Forms.
NOTE
La localización de derecha a izquierda requiere el uso de iOS 9 o versiones posteriores; en Android, la API 17 o versiones
posteriores.
La dirección de flujo es la dirección en la que el ojo humano lee los elementos de la interfaz de usuario en la
página. Algunos lenguajes, como el árabe y hebreo, requieren que los elementos de interfaz de usuario se
distribuyan en una dirección de flujo de derecha a izquierda. Esto también puede lograrse estableciendo la
propiedad VisualElement.FlowDirection . Esta propiedad obtiene o establece la dirección en que fluyen los
elementos de interfaz de usuario dentro de cualquier elemento primario que controle su diseño, y debe
establecerse en uno de los valores de enumeración de FlowDirection :
LeftToRight
RightToLeft
MatchParent
TIP
Solo debe establecerse la propiedad FlowDirection en el diseño inicial. El cambio de este valor en tiempo de ejecución
hace que el proceso de diseño sea difícil y que ello afecte al rendimiento.
El valor de la propiedad FlowDirection predeterminado para un elemento sin un elemento primario es
LeftToRight , mientras que el valor predeterminado de FlowDirection para un elemento con un elemento
primario es MatchParent . Por lo tanto, un elemento hereda el valor de la propiedad FlowDirection de su elemento
primario en el árbol visual, y cualquier elemento puede invalidar el valor que obtiene de su elemento primario.
TIP
Al localizar una aplicación para idiomas con flujo de derecha a izquierda, establezca la propiedad FlowDirection en una
página o un diseño raíz. Esto hace que todos los elementos contenidos dentro de la página, o el diseño raíz, respondan
adecuadamente a la dirección del flujo.
this.FlowDirection = Device.FlowDirection;
Posteriormente, todos los elementos secundarios de la página, o el diseño raíz, de forma predeterminada
heredarán el valor Device.FlowDirection .
Configuración de la plataforma
Se requiere una configuración de la plataforma específica para habilitar las configuraciones regionales de derecha
a izquierda.
iOS
La configuración regional de derecha a izquierda necesaria debe agregarse como un idioma compatible con los
elementos de matriz para la clave CFBundleLocalizations Info.plist. En el ejemplo siguiente se muestra el idioma
árabe agregado a la matriz para la clave CFBundleLocalizations :
<key>CFBundleLocalizations</key>
<array>
<string>en</string>
<string>ar</string>
</array>
Para obtener más información, consulte Localization Basics in iOS (Introducción a la localización en iOS ).
A continuación, se puede probar la localización de derecha a izquierda cambiando el idioma y la región del
dispositivo o el simulador a una configuración regional de derecha a izquierda que se haya especificado en
Info.plist.
WARNING
Tenga en cuenta que al cambiar el idioma y la región para una configuración regional de derecha a izquierda en iOS, todas
las vistas DatePicker emitirán una excepción si no se incluyen los recursos necesarios para la configuración regional. Por
ejemplo, al probar una aplicación en árabe que tenga un DatePicker , asegúrese de que mideast (Oriente Medio) esté
seleccionado en la sección Internationalization (Internacionalización) del panel iOS Build (Compilación de iOS).
Android
El archivo AndroidManifest.xml de la aplicación debe actualizarse para que el nodo <uses-sdk> establezca el
atributo android:minSdkVersion en 17 y el nodo <application> establezca el atributo android:supportsRtl en
true :
<Resources>
<Resource Language="x-generate"/>
<Resource Language="en" />
<Resource Language="ar" />
</Resources>
Además, UWP requiere que la referencia cultural predeterminada de la aplicación se defina explícitamente en la
biblioteca .NET Standard. Esto puede realizarse estableciendo el atributo NeutralResourcesLanguage en
AssemblyInfo.cs , o en otra clase, en la referencia cultural predeterminada:
using System.Resources;
[assembly: NeutralResourcesLanguage("en")]
A continuación, se puede probar la localización de derecha a izquierda cambiando el idioma y la región del
dispositivo a la configuración regional de derecha a izquierda adecuada.
Limitaciones
La localización de derecha a izquierda de Xamarin.Forms actualmente tiene una serie de limitaciones:
El control de la ubicación del botón NavigationPage , la ubicación de elementos de barra de herramientas y la
animación de transición lo lleva a cabo la configuración regional del dispositivo, en lugar de la propiedad
FlowDirection .
La dirección de deslizamiento de CarouselPage no realiza la acción.
El contenido visual de Image no se invierte.
El control de la orientación de DisplayAlert y DisplayActionSheet lo lleva a cabo la configuración regional del
dispositivo, en lugar de la propiedad FlowDirection .
El contenido de WebView no respeta la propiedad FlowDirection .
Debe agregarse una propiedad TextDirection , para controlar la alineación del texto.
iOS
El control de la orientación de Stepper lo lleva a cabo la configuración regional del dispositivo, en lugar de la
propiedad FlowDirection .
El control de la alineación del texto de EntryCell lo lleva a cabo la configuración regional del dispositivo, en
lugar de la propiedad FlowDirection .
La alineación y los gestos de ContextActions no se invierten.
Android
El control de la orientación de SearchBar lo lleva a cabo la configuración regional del dispositivo, en lugar de la
propiedad FlowDirection .
El control de la colocación de ContextActions lo lleva a cabo la configuración regional del dispositivo, en lugar
de la propiedad FlowDirection .
UWP
El control de la alineación del texto de Editor lo lleva a cabo la configuración regional del dispositivo, en lugar
de la propiedad FlowDirection .
Los elementos secundarios MasterDetailPage no heredan la propiedad FlowDirection .
El control de la alineación del texto de ContextActions lo lleva a cabo la configuración regional del dispositivo,
en lugar de la propiedad FlowDirection .
Vínculos relacionados
Aplicación de ejemplo TodoLocalizedRTL
MessagingCenter de Xamarin.Forms
11/07/2019 • 5 minutes to read • Edit Online
Descargar el ejemplo
Xamarin.Forms incluye un servicio de mensajería simple para enviar y recibir mensajes.
Información general
MessagingCenter de Xamarin.Forms permite que los modelos de vista y otros componentes se comuniquen sin
tener que saber nada sobre los demás, salvo un sencillo contrato de mensajería.
Funcionamiento de MessagingCenter
MessagingCenter tiene dos partes:
Subscribe: escucha mensajes con una determinada firma y realiza alguna acción cuando se reciben. Varios
suscriptores pueden estar escuchando el mismo mensaje.
Send: publica un mensaje para que los agentes de escucha actúen en consecuencia. Si no hay ningún agente
de escucha suscrito, se omite el mensaje.
MessagingCenter es una clase estática con métodos Subscribe y Send que se usan en toda la solución.
Los mensajes tienen un parámetro de cadena message que se usa como forma de dirigir mensajes. Los métodos
Subscribe y Send usan parámetros genéricos para un mayor control sobre la entrega de los mensajes: dos
mensajes con el mismo texto message pero argumentos de tipo genérico diferentes no se entregan al mismo
suscriptor.
La API de MessagingCenter es simple:
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)
Uso de MessagingCenter
Los mensajes se pueden enviar como resultado de la interacción del usuario (por ejemplo, un clic en un botón), un
evento del sistema (por ejemplo, controles que cambian el estado) o algún otro incidente (como la finalización de
una descarga asincrónica). Los suscriptores pueden escuchar para cambiar la apariencia de la interfaz de usuario,
guardar datos o desencadenar alguna otra operación.
Para obtener más información sobre el uso de la clase MessagingCenter , vea Comunicación entre componentes
débilmente acoplados.
Mensaje de cadena simple
El mensaje más simple contiene solo una cadena en el parámetro message . A continuación se muestra un método
Subscribe que escucha un mensaje de cadena simple: observe el tipo genérico que especifica que se espera que
el remitente sea de tipo MainPage . Las clases de la solución pueden suscribirse al mensaje con esta sintaxis:
En la clase MainPage , el siguiente código envía el mensaje. El parámetro this es una instancia de MainPage .
La cadena no cambia: indica el tipo de mensaje y se usa para determinar a qué suscriptores se va a notificar. Este
tipo de mensaje se usa para indicar que se ha producido un evento, como "carga completada", donde no se
requiere ninguna información adicional.
Pasar un argumento
Para pasar un argumento con el mensaje, especifique el argumento Type en los argumentos genéricos Subscribe
y en la firma Action.
Para enviar el mensaje con argumento, incluya el parámetro genérico Type y el valor del argumento en la llamada
al método Send .
Este ejemplo sencillo usa un argumento string , pero se puede pasar cualquier objeto de C#.
Cancelar suscripción
Un objeto puede cancelar la suscripción de una firma de mensaje para que no se entreguen los mensajes futuros.
La sintaxis del método Unsubscribe debe reflejar la firma del mensaje (así que puede ser necesario incluir el
parámetro genérico Type para el argumento del mensaje).
Resumen
MessagingCenter es una manera sencilla de reducir el acoplamiento, especialmente entre modelos de vista. Se
puede usar para enviar y recibir mensajes sencillos o pasar un argumento entre clases. Las clases deben cancelar
la suscripción a mensajes que ya no quieran recibir.
Vínculos relacionados
Ejemplo de MessagingCenter
Xamarin.Forms Samples (Ejemplos de Xamarin.Forms)
Comunicación entre componentes débilmente acoplados
Navegación por Xamarin.Forms
11/07/2019 • 2 minutes to read • Edit Online
Xamarin.Forms proporciona una serie de experiencias de navegación de páginas diferente, en función del tipo de
página que se use.
Como alternativa, las aplicaciones de Xamarin.Forms Shell usan una experiencia de navegación basada en URI que
no obliga a una jerarquía de navegación del conjunto. Para más información, consulte Navegación en
Xamarin.Forms Shell.
Navegación jerárquica
La clase NavigationPage proporciona una experiencia de navegación jerárquica en la que el usuario puede navegar
por las páginas hacia delante y hacia atrás, si quiere. La clase implementa la navegación como una pila de objetos
Page en la que el último en entrar es el primero en salir ( LIFO ).
TabbedPage
TabbedPage de Xamarin.Forms consta de una lista de pestañas y un área de detalles mayor. Cada pestaña carga
contenido en el área de detalles.
CarouselPage
CarouselPage de Xamarin.Forms es una página que los usuarios pueden deslizar de lado a lado para navegar por
páginas de contenido, como una galería.
MasterDetailPage
MasterDetailPage de Xamarin.Forms es una página que administra dos páginas de información relacionada: una
página maestra que presenta los elementos y una página de detalles que muestra los detalles sobre los elementos
de la página maestra.
Páginas modales
Xamarin.Forms también es compatible con las páginas modales. Una página modal anima a los usuarios a
completar una tarea autocontenida que no se puede abandonar mientras no se complete o se cancele la tarea.
Navegación jerárquica
11/07/2019 • 20 minutes to read • Edit Online
Descargar el ejemplo
La clase NavigationPage proporciona una experiencia de navegación jerárquica en la que el usuario puede
navegar por las páginas hacia adelante y hacia atrás, como quiera. La clase implementa la navegación como
una pila de objetos de página en la que el último en entrar es el primero en salir (LIFO ). En este artículo se
muestra cómo utilizar la clase NavigationPage para realizar la navegación en una pila de páginas.
Para pasar de una página a otra, una aplicación insertará una página nueva en la pila de navegación, donde se
convertirá en la página activa, tal como se muestra en el diagrama siguiente.
Para volver a la página anterior, la aplicación mostrará la página actual de la pila de navegación y la nueva página
de nivel superior se convertirá en la página activa, tal como se muestra en el diagrama siguiente:
La propiedad Navigation expone los métodos de navegación en cualquiera de los tipos derivados de Page . Estos
métodos proporcionan la capacidad para insertar páginas en la pila de navegación, sacar páginas de la pila de
navegación y manipular la pila.
Realizar la navegación
En la navegación jerárquica, se usa la clase NavigationPage para navegar por una pila de objetos ContentPage . En
las siguientes capturas de pantalla, se muestran los componentes principales de la NavigationPage en cada
plataforma:
NOTE
Se recomienda que una NavigationPage debe rellenarse únicamente con instancias de ContentPage .
public App ()
{
MainPage = new NavigationPage (new Page1Xaml ());
}
Esto hace que la instancia de Page1Xaml ContentPage se inserte en la pila de navegación, donde se convertirá en
la página activa y en la página raíz de la aplicación. Esto se muestra en las capturas de pantalla siguientes:
NOTE
La propiedad RootPage de una instancia de NavigationPage permite acceder a la primera página de la pila de
navegación.
Esto hace que la instancia de Page2Xaml se inserte en la pila de navegación, donde se convertirá en la página
activa. Esto se muestra en las capturas de pantalla siguientes:
Sin embargo, el orden exacto en el que se producen estos eventos depende de la plataforma. Para obtener más
información, consulte el capítulo 24 del libro sobre Xamarin.Forms de Charles Petzold.
NOTE
Las llamadas a OnDisappearing y las invalidaciones de OnAppearing no se pueden tratar como indicaciones garantizadas
de navegación de páginas. Por ejemplo, en iOS, la invalidación de OnDisappearing se llama en la página activa cuando la
aplicación finaliza.
Esto hace que la instancia de Page2Xaml se quite de la pila de navegación y que la nueva página de nivel superior
se convierta en la página activa. Al invocar el método PopAsync , ocurre lo siguiente:
Se invoca la invalidación de OnDisappearing de la página que llama a PopAsync .
Se invoca la invalidación de OnAppearing de la página a la que se ha regresado.
La tarea PopAsync vuelve.
Sin embargo, el orden exacto en el que se producen estos eventos depende de la plataforma. Para obtener más
información, consulte el capítulo 24 del libro sobre Xamarin.Forms de Charles Petzold.
Al igual que los métodos PushAsync y PopAsync , la propiedad Navigation de cada página también proporciona
un método PopToRootAsync , que se muestra en el ejemplo de código siguiente:
Este método saca todas las páginas de la pila de navegación, excepto la Page raíz, de manera que la página raíz
de la aplicación se convierte en la página activa.
Animación de transiciones de página
La propiedad Navigation de cada página también proporciona métodos de inserción y extracción invalidados que
incluyen un parámetro boolean que controla si se debe mostrar una animación de página durante la navegación,
como se muestra en el ejemplo de código siguiente:
Al establecer el parámetro boolean en false , la animación de transición de página se deshabilita, mientras que
al establecer el parámetro en true , la animación de transición de página se habilita, siempre que la plataforma
subyacente lo admita. Sin embargo, los métodos de inserción y extracción que carecen de este parámetro
habilitan la animación de manera predeterminada.
Este código crea una instancia de MainPage y pasa la fecha y la hora actuales en formato ISO8601, que se
encapsula en una instancia de NavigationPage .
La instancia de MainPage recibe los datos a través de un parámetro de constructor, tal como se muestra en el
ejemplo de código siguiente:
A continuación, se establece la propiedad Label.Text para que los datos se muestren en la página, como se
muestra en las capturas de pantalla siguientes:
En el ejemplo de código siguiente se muestra cómo se puede realizar el enlace de datos en C#:
A continuación, una serie de controles Label muestran los datos en la página, como se muestra en las capturas
de pantalla siguientes:
Para más información sobre el enlace de datos, consulte Data Binding Basics (Aspectos básicos del enlace de
datos).
El método RemovePage quita la página especificada de la pila de navegación, como se muestra en el diagrama
siguiente:
Estos métodos permiten una experiencia de navegación personalizada, como sustituir una página de inicio de
sesión por una página nueva, después de iniciar sesión correctamente. El ejemplo de código siguiente muestra
esta situación:
<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>
IMPORTANT
Muchas vistas no aparecen en la barra de navegación, salvo que el tamaño de la vista se especifique con las propiedades
WidthRequest y HeightRequest . Como alternativa, la vista puede encapsularse en un StackLayout con las propiedades
HorizontalOptions y VerticalOptions establecidas en los valores adecuados.
Tenga en cuenta que, dado que la clase Layout deriva de la clase View , la propiedad adjunta TitleView se puede
establecer para mostrar una clase de diseño que contiene varias vistas. En iOS y la Plataforma universal de
Windows (UWP ), la altura de la barra de navegación no se puede cambiar y, por tanto, se recortará si la vista que
se muestra en la barra de navegación es mayor que el tamaño predeterminado de la barra de navegación. Sin
embargo, en Android, la altura de la barra de navegación se puede cambiar estableciendo la propiedad enlazable
NavigationPage.BarHeight en un double que represente la altura nueva. Para obtener más información, consulte
Establecer la altura de la barra de navegación en una NavigationPage.
Como alternativa, para sugerir una barra de exploración extendida, se puede colocar una parte del contenido en la
barra de navegación y otra en una vista en la parte superior del contenido de la página que coincida con el color
de la barra de navegación. Además, en iOS, la línea y la sombra del separador que se encuentran en la parte
inferior de la barra de navegación se pueden quitar estableciendo la propiedad enlazable
NavigationPage.HideNavigationBarSeparator en true . Para obtener más información, consulte Ocultar el
separador de la barra de navegación en una NavigationPage.
NOTE
Las propiedades BackButtonTitle , Title , TitleIcon y TitleView pueden definir valores que ocupan espacio en la
barra de navegación. Mientras que el tamaño de la barra de navegación varía según la plataforma y el tamaño de pantalla,
al establecer todas estas propiedades se producirán conflictos a causa del espacio limitado disponible. En lugar de intentar
utilizar una combinación de estas propiedades, es posible que, si solo establece la propiedad TitleView , pueda elaborar
mejor el diseño de la barra de navegación deseado.
Limitaciones
Al mostrar una View en la barra de navegación de una NavigationPage , hay una serie de limitaciones que debe
conocer:
En iOS, las vistas colocadas en la barra de navegación de una NavigationPage se muestran en una posición
diferente según si están habilitados los títulos de gran tamaño. Para obtener más información sobre cómo
habilitar títulos grandes, consulte Mostrar títulos grandes.
En Android, colocar las vistas en la barra de navegación de una NavigationPage solo puede realizarse en las
aplicaciones que utilizan la compatibilidad de aplicaciones.
No se recomienda colocar vistas grandes y complejas, como ListView y TableView , en la barra de navegación
de una NavigationPage .
Vínculos relacionados
Navegación de páginas
Jerárquica (ejemplo)
PassingData (ejemplo)
LoginFlow (ejemplo)
TitleView (ejemplo)
Vídeo sobre cómo crear un flujo de pantalla de inicio de sesión en Xamarin.Forms
NavigationPage
TabbedPage de Xamarin.Forms
11/07/2019 • 12 minutes to read • Edit Online
Descargar el ejemplo
TabbedPage de Xamarin.Forms consta de una lista de pestañas y un área de detalles mayor. Cada pestaña carga
contenido en el área de detalles. En este artículo se muestra cómo usar una instancia de TabbedPage para
navegar por una colección de páginas.
Información general
En las capturas de pantalla siguientes se muestra un elemento TabbedPage en cada plataforma:
NOTE
Observe que el elemento TabbedRenderer para iOS tiene un método reemplazable GetIcon que se puede usar
para cargar iconos de pestaña desde un origen especificado. Esta invalidación permite usar imágenes SVG como
iconos en un elemento TabbedPage . Además, se pueden proporcionar versiones seleccionadas y sin seleccionar de
un icono.
NOTE
Tenga en cuenta que al usar AppCompat en Android, cada pestaña también muestra un icono. Además, el elemento
TabbedPageRenderer para Android AppCompat tiene un método reemplazable GetIconDrawable que se puede
usar para cargar iconos de pestaña desde un elemento Drawable personalizado. Esta invalidación permite usar
imágenes SVG como iconos en un elemento TabbedPage y funciona con barras de pestañas superiores e inferiores.
También se puede usar el método reemplazable SetTabIcon para cargar iconos de pestaña desde un elemento
Drawable personalizado para barras de pestañas superiores.
En los factores de forma de tableta de Windows, las pestañas no siempre están visibles y los usuarios
tienen que deslizar hacia abajo (o hacer clic con el botón derecho, si tienen un mouse asociado) para ver las
pestañas en un elemento TabbedPage (como se muestra a continuación).
Creación de TabbedPage
TabbedPage define las siguientes propiedades:
BarBackgroundColor de tipo Color , el color de fondo de la barra de pestañas.
BarTextColor de tipo Color , el color del texto en la barra de pestañas.
SelectedTabColor de tipo Color , el color de la pestaña cuando está seleccionada.
UnselectedTabColor de tipo Color , el color de la pestaña cuando no está seleccionada.
Todas estas propiedades están respaldadas por objetos BindableProperty , lo que significa que se les pueden
aplicar estilos y que las propiedades pueden ser los destinos de los enlaces de datos.
Para crear una instancia de TabbedPage se pueden usar dos métodos:
Rellenar la instancia de TabbedPage con una colección de objetos secundarios Page , como una colección de
instancias de ContentPage .
Asignar una colección a la propiedad ItemsSource y asignar un elemento DataTemplate a la propiedad
ItemTemplate para devolver páginas de objetos de la colección.
Con ambos métodos, TabbedPage muestra cada página cuando el usuario selecciona cada pestaña.
NOTE
Se recomienda que una instancia de TabbedPage se rellene únicamente con instancias de NavigationPage y
ContentPage . Esto ayuda a garantizar una experiencia de usuario coherente en todas las plataformas.
TabbedPage se rellena con dos objetos secundarios Page . El primer elemento secundario es una instancia de
ContentPage y la segunda pestaña es un elemento NavigationPage que contiene una instancia de ContentPage .
NOTE
La instancia de TabbedPage no admite la virtualización de la interfaz de usuario. Por lo tanto, el rendimiento puede verse
afectado si TabbedPage contiene demasiados elementos secundarios.
Las capturas de pantalla siguientes muestran el elemento TodayPage de la instancia ContentPage , que se muestra
en la pestaña Today:
NOTE
Aunque es aceptable colocar un elemento NavigationPage en una instancia de TabbedPage , no se recomienda colocar un
elemento TabbedPage en NavigationPage . Esto se debe a que, en iOS, un elemento UITabBarController siempre actúa
como contenedor de UINavigationController . Para obtener más información, vea Combined View Controller Interfaces
(Interfaces combinadas del controlador de vistas) en la biblioteca para desarrolladores de iOS.
Esto hace que la instancia de UpcomingAppointmentsPage se inserte en la pila de navegación, donde se convertirá en
la página activa. Esto se muestra en las capturas de pantalla siguientes:
Para obtener más información sobre la navegación mediante la clase NavigationPage , vea Navegación jerárquica.
Rellenar TabbedPage con una plantilla
El ejemplo de código XAML siguiente muestra una instancia de TabbedPage construida mediante la asignación de
DataTemplate a la propiedad ItemTemplate para devolver páginas para objetos de la colección:
<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}" IconImageSource="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>
TabbedPage se rellena con datos al establecer la propiedad ItemsSource en el constructor para el archivo de
código subyacente:
public TabbedPageDemoPage ()
{
...
ItemsSource = MonkeyDataModel.All;
}
Cada pestaña muestra un elemento ContentPage que usa una serie de instancias de StackLayout y Label para
mostrar datos para la pestaña. Las capturas de pantalla siguientes muestran el contenido de la pestaña Tamarin:
Al seleccionar otra pestaña, se muestra el contenido de esa pestaña.
NOTE
La instancia de TabbedPage no admite la virtualización de la interfaz de usuario. Por lo tanto, el rendimiento puede verse
afectado si TabbedPage contiene demasiados elementos secundarios.
Para obtener más información sobre la instancia de TabbedPage , vea el capítulo 25 del libro sobre Xamarin.Forms
de Charles Petzold.
Resumen
En este artículo se ha explicado cómo usar una instancia de TabbedPage para navegar por una colección de
páginas. TabbedPage de Xamarin.Forms consta de una lista de pestañas y un área de detalles mayor. Cada pestaña
carga contenido en el área de detalles.
Vínculos relacionados
Páginas de Xamarin.Forms
TabbedPageWithNavigationPage (ejemplo)
TabbedPage (ejemplo)
TabbedPage
CarouselPage de Xamarin.Forms
11/07/2019 • 7 minutes to read • Edit Online
Descargar el ejemplo
CarouselPage de Xamarin.Forms es una página que los usuarios pueden deslizar de lado a lado para navegar por
páginas de contenido, como una galería. En este artículo se muestra cómo usar CarouselPage para navegar por
una colección de páginas.
Información general
En las capturas de pantalla siguientes se muestra un elemento CarouselPage en cada plataforma:
El diseño de un elemento CarouselPage es idéntico en todas las plataformas. Para navegar por las páginas, hay
que deslizar de derecha a izquierda para avanzar en la colección y de izquierda a derecha para retroceder en la
colección. Las capturas de pantalla siguientes muestran la primera página de una instancia de CarouselPage :
Al deslizar de derecha a izquierda se pasa a la segunda página, como se muestra en las capturas de pantalla
siguientes:
Al volver a deslizar de derecha a izquierda se pasa a la tercera página, mientras que al deslizar de izquierda a
derecha se vuelve a la página anterior.
Creación de CarouselPage
Para crear una instancia de CarouselPage se pueden usar dos métodos:
Rellenar la instancia de CarouselPage con una colección de instancias secundarias de ContentPage .
Asignar una colección a la propiedad ItemsSource y asignar un elemento DataTemplate a la propiedad
ItemTemplate para devolver instancias de ContentPage para objetos de la colección.
Con ambos métodos, CarouselPage muestra a su vez cada página, con una interacción de deslizamiento que pasa
a la página siguiente que se va a mostrar.
NOTE
Una instancia de CarouselPage solo se puede rellenar con instancias de ContentPage , o derivados de ContentPage .
Children.Add (redContentPage);
Children.Add (greenContentPage);
Children.Add (blueContentPage);
}
}
Cada ContentPage muestra simplemente un elemento Label para un color determinado y un elemento BoxView
de ese color.
NOTE
La instancia de CarouselPage no admite la virtualización de la interfaz de usuario. Por lo tanto, el rendimiento puede verse
afectado si CarouselPage contiene demasiados elementos secundarios.
<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>
CarouselPage se rellena con datos al establecer la propiedad ItemsSource en el constructor para el archivo de
código subyacente:
public MainPage ()
{
...
ItemsSource = ColorsDataModel.All;
}
ItemsSource = ColorsDataModel.All;
}
}
Cada ContentPage muestra simplemente un elemento Label para un color determinado y un elemento BoxView
de ese color.
NOTE
La instancia de CarouselPage no admite la virtualización de la interfaz de usuario. Por lo tanto, el rendimiento puede verse
afectado si CarouselPage contiene demasiados elementos secundarios.
Vínculos relacionados
Páginas de Xamarin.Forms
CarouselPage (ejemplo)
CarouselPageTemplate (ejemplo)
CarouselPage
MasterDetailPage de Xamarin.Forms
11/07/2019 • 16 minutes to read • Edit Online
Descargar el ejemplo
MasterDetailPage de Xamarin.Forms es una página que administra dos páginas relacionadas de información: una
página maestra que presenta elementos y una página de detalles que presenta detalles sobre los elementos de la
página maestra. En este artículo se explica cómo usar una instancia de MasterDetailPage y cómo navegar entre
sus páginas de información.
Información general
Normalmente, una página maestra presenta una lista de elementos, como se muestra en las siguientes capturas de
pantalla:
La ubicación de la lista de elementos es idéntica en cada plataforma; al seleccionar uno de los elementos, se le lleva
a la página de detalles correspondiente. Además, la página maestra también incluye una barra de navegación que
contiene un botón que se puede usar para ir a la página de detalles activa:
En iOS, la barra de navegación se encuentra en la parte superior de la página y tiene un botón que lleva a la
página de detalles. Además, se puede ir a la página de detalles activa si se desliza la página maestra hacia la
izquierda.
En Android, la barra de navegación se encuentra en la parte superior de la página y presenta un título, un icono
y un botón que lleva a la página de detalles. El icono se define en el atributo [Activity] que decora la clase
MainActivity en el proyecto específico de la plataforma Android. Además, se puede ir a la página de detalles
activa si se desliza la página maestra hacia la izquierda, si se puntea en el extremo derecho de la pantalla en la
página de detalles y si se pulsa el botón Atrás situado en la parte inferior de la pantalla.
En Plataforma universal de Windows (UWP ), la barra de navegación se encuentra en la parte superior de la
página y tiene un botón que lleva a la página de detalles.
Una página de detalles presenta datos correspondientes al elemento seleccionado en la página maestra; los
componentes principales de la página de detalles se muestran en las capturas de pantalla siguientes:
La página de detalles contiene una barra de navegación cuyo contenido depende de la plataforma:
En iOS, la barra de navegación se encuentra en la parte superior de la página, muestra un título y tiene un
botón que devuelve a la página maestra, siempre que la instancia de la página de detalles esté incluida en la
instancia de NavigationPage . Además, se puede volver a la página maestra si se desliza la página de detalles
hacia la derecha.
En Android, hay una barra de navegación en la parte superior de la página que muestra un título, un icono y un
botón que devuelve a la página maestra. El icono se define en el atributo [Activity] que decora la clase
MainActivity en el proyecto específico de la plataforma Android.
En UWP, la barra de navegación se encuentra en la parte superior de la página, muestra un título y tiene un
botón que devuelve a la página maestra.
Comportamiento de navegación
El comportamiento de la experiencia de navegación entre las páginas maestra y de detalles depende de la
plataforma:
En iOS, la página de detalles se desliza hacia la derecha cuando la página maestra se desliza desde la izquierda,
y la parte izquierda de la página de detalles sigue siendo visible.
En Android, las páginas maestra y de detalles se superponen.
En UWP, la página maestra se desplaza desde el lateral izquierdo de la página de detalles, siempre que la
propiedad MasterBehavior esté establecida en Popover . Para obtener más información, consulte Control del
comportamiento de presentación de la página de detalles.
En el modo horizontal se observa un comportamiento similar, salvo que la página maestra en iOS y Android tiene
un ancho similar al de la página maestra en modo vertical, así que se ve más superficie de la página de detalles.
Para obtener información sobre cómo controlar el comportamiento de navegación, vea Control del
comportamiento de presentación de la página de detalles.
Creación de MasterDetailPage
Una instancia de MasterDetailPage contiene propiedades Master y Detail que son de tipo Page y se usan para
obtener y establecer las páginas maestra y de detalles, respectivamente.
IMPORTANT
Una instancia de MasterDetailPage está diseñada para ser una página raíz. Su empleo como página secundaria en otros
tipos de páginas podría dar lugar a un comportamiento inesperado e incoherente. Además, se recomienda que la página
maestra de una instancia de MasterDetailPage siempre sea una instancia de ContentPage y que la página de detalles
solo se rellene con instancias de TabbedPage , NavigationPage y ContentPage . Esto ayuda a garantizar una experiencia
de usuario coherente en todas las plataformas.
El ejemplo de código XAML siguiente muestra una instancia de MasterDetailPage que establece las propiedades
Master y 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>
public MainPageCS ()
{
masterPage = new MasterPageCS ();
Master = masterPage;
Detail = new NavigationPage (new ContactsPageCS ());
...
}
...
}
La página consta de un elemento ListView que se rellena con datos de XAML al establecer su propiedad
ItemsSource en una matriz de instancias de MasterPageItem . Cada MasterPageItem define propiedades Title ,
IconSource y TargetType .
NOTE
La página MasterDetailPage.Master debe tener su propiedad Title establecida, o se produce una excepción.
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)
});
grid.Children.Add(image);
grid.Children.Add(label, 1, 0);
IconImageSource = "hamburger.png";
Title = "Personal Organiser";
Content = new StackLayout
{
Children = { listView }
};
}
}
Las capturas de pantalla siguientes muestran la página de detalles ContactPage , que se presenta después de
haberse seleccionado en la página maestra:
public MainPageCS ()
{
MasterBehavior = MasterBehavior.Popover;
...
}
}
Pero el valor de la propiedad MasterBehavior solo afecta a las aplicaciones que se ejecutan en el escritorio o en
tabletas. Las aplicaciones que se ejecutan en teléfonos siempre tienen el comportamiento Popover.
Resumen
En este artículo se ha explicado cómo usar una instancia de MasterDetailPage y cómo navegar entre sus páginas
de información. MasterDetailPage de Xamarin.Forms es una página que administra dos páginas de información
relacionada: una página maestra que presenta elementos y una página de detalles que muestra detalles sobre
elementos de la página maestra.
Vínculos relacionados
Páginas de Xamarin.Forms
MasterDetailPage (ejemplo)
MasterDetailPage
Páginas modales de Xamarin.Forms
11/07/2019 • 12 minutes to read • Edit Online
Descargar el ejemplo
Xamarin.Forms es compatible con las páginas modales. Una página modal anima a los usuarios a completar una
tarea autocontenida que no se puede abandonar mientras no se complete o se cancele la tarea. En este artículo se
muestra cómo navegar a páginas modales.
En este artículo se tratan los siguientes temas:
Realizar la navegación: insertar páginas en la pila modal, sacar páginas de la pila modal, deshabilitar el botón
Atrás y animar las transiciones de página.
Pasar datos al navegar: pasar datos a través de un constructor de página y de un BindingContext .
Información general
Una página modal puede ser cualquiera de los tipos Página compatibles con Xamarin.Forms. Para mostrar una
página modal, la aplicación la insertará en la pila modal, donde se convertirá en la página activa, como se muestra
en el siguiente diagrama:
Para volver a la página anterior, la aplicación mostrará la página actual de la pila modal y la nueva página de nivel
superior se convertirá en la página activa, tal como se muestra en el siguiente diagrama:
Realizar la navegación
Los métodos de navegación modal se exponen mediante la propiedad Navigation en cualquier tipo Page
derivado. Estos métodos proporcionan la capacidad de insertar páginas modales en la pila modal, y sacar páginas
modales de la pila modal.
La propiedad Navigation también expone una propiedad ModalStack desde la que se pueden obtener las páginas
modales de la pila modal. Pero no existe el concepto de realizar una manipulación de pila modal o extraer la
página raíz de la navegación modal. Esto se debe a que estas operaciones no se admiten de forma universal en las
plataformas subyacentes.
NOTE
No es necesaria una instancia de NavigationPage para realizar la navegación de páginas modal.
Esto hace que la instancia de ModalPage se inserte en la pila modal, donde se convertirá en la página activa,
siempre que se haya seleccionado un elemento en la ListView en la instancia de MainPage . La instancia de
ModalPage se muestra en la siguiente captura de pantalla:
Con todo, el orden exacto en el que se producen estos eventos depende de la plataforma. Para obtener más
información, consulte el capítulo 24 del libro sobre Xamarin.Forms de Charles Petzold.
NOTE
Las llamadas a OnDisappearing y las invalidaciones de OnAppearing no se pueden tratar como indicaciones garantizadas
de navegación de páginas. Por ejemplo, en iOS, la invalidación de OnDisappearing se llama en la página activa cuando la
aplicación finaliza.
Esto hace que la instancia de ModalPage se quite de la pila modal y que la nueva página de nivel superior se
convierta en la página activa. Al invocar PopModalAsync , ocurre lo siguiente:
Se invoca la invalidación de OnDisappearing de la página que llama a PopModalAsync .
Se invoca la invalidación de OnAppearing de la página a la que se vuelve, siempre que la plataforma subyacente
no sea Android.
Se devuelve la tarea PopModalAsync .
Con todo, el orden exacto en el que se producen estos eventos depende de la plataforma. Para obtener más
información, consulte el capítulo 24 del libro sobre Xamarin.Forms de Charles Petzold.
Deshabilitación del botón Atrás
En Android, el usuario siempre puede volver a la página anterior presionando el botón Atrás estándar en el
dispositivo. Si la página modal requiere que el usuario complete una tarea independiente antes de salir de la
página, la aplicación debe deshabilitar el botón Atrás. Esto puede realizarse invalidando el método
Page.OnBackButtonPressed en la página modal. Para obtener más información, consulte el capítulo 24 del libro
sobre Xamarin.Forms de Charles Petzold.
Animación de transiciones de página
La propiedad Navigation de cada página también proporciona métodos de inserción y extracción invalidados que
incluyen un parámetro boolean que controla si se debe mostrar una animación de página durante la navegación,
como se muestra en el ejemplo de código siguiente:
Al establecer el parámetro boolean en false , la animación de transición de página se deshabilita, mientras que al
establecer el parámetro en true , la animación de transición de página se habilita, siempre que la plataforma
subyacente lo admita. Sin embargo, los métodos de inserción y extracción que carecen de este parámetro habilitan
la animación de manera predeterminada.
Este código crea una instancia de MainPage y pasa la fecha y la hora actuales en formato ISO8601.
La instancia de MainPage recibe los datos a través de un parámetro de constructor, tal como se muestra en el
ejemplo de código siguiente:
Después, se establece la propiedad Label.Text para que los datos se muestren en la página.
Pasar datos a través de un objeto BindingContext
Un enfoque alternativo para pasar datos a otra página durante la navegación es establecer el BindingContext de la
página nueva en los datos, como se muestra en el siguiente ejemplo de código:
<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>
En el ejemplo de código siguiente se muestra cómo se puede realizar el enlace de datos en 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
}
};
}
Resumen
En este artículo se mostró cómo navegar a páginas modales. Una página modal anima a los usuarios a completar
una tarea autocontenida que no se puede abandonar mientras no se complete o se cancele la tarea.
Vínculos relacionados
Page Navigation (Navegación de páginas)
Modal (sample) (Modal [ejemplo])
PassingData (sample) (PassingData [ejemplo])
Xamarin.Forms Shell
11/07/2019 • 3 minutes to read • Edit Online
Introducción
Xamarin.Forms Shell reduce la complejidad del desarrollo de aplicaciones móviles al proporcionar las
características fundamentales que requieren la mayoría de aplicaciones móviles. Esto incluye una experiencia de
usuario de navegación común, un esquema de navegación basado en URI y un controlador de búsqueda
integrada.
Control flotante
El control flotante es el menú raíz de una aplicación de Shell y es accesible por medio de un icono o al deslizar el
dedo desde el lado de la pantalla. El control flotante consta de un encabezado opcional, elementos de control
flotante y elementos de menú opcionales.
Pestañas
Después de un control flotante, el siguiente nivel de navegación en una aplicación de Shell es la barra de pestañas
de la parte inferior. Como alternativa, el modelo de navegación para una aplicación puede comenzar con pestañas
en la parte inferior y no usar un control flotante. En ambos casos, cuando una pestaña inferior contiene más de
una página, las páginas son navegables mediante las pestañas principales.
Configuración de la página
La clase Shell define las propiedades adjuntas que se pueden usar para configurar la apariencia de las páginas
en las aplicaciones de Xamarin.Forms Shell. Esto incluye establecer los colores de la página, deshabilitar la barra
de navegación y la barra de pestañas y mostrar las vistas en la barra de navegación.
Navegación
Las aplicaciones de Shell pueden usar un esquema de navegación basado en URI que emplea rutas para navegar
a cualquier página de la aplicación, sin tener que seguir una jerarquía de navegación establecida.
Búsqueda
Las aplicaciones de Shell pueden usar la funcionalidad de búsqueda integrada que se proporciona en un cuadro
de búsqueda que se puede agregar a la parte superior de cada página.
Representadores personalizados
Las aplicaciones de Shell son muy personalizables mediante las propiedades y los métodos que exponen las
distintas clases de Shell. Sin embargo, también es posible crear a un representador personalizado de Shell cuando
se requieren personalizaciones más sofisticadas específicas de la plataforma.
Introducción a Xamarin.Forms Shell
11/07/2019 • 2 minutes to read • Edit Online
Descargar el ejemplo
Xamarin.Forms Shell reduce la complejidad del desarrollo de aplicaciones móviles al proporcionar las
características fundamentales que requieren la mayoría de aplicaciones móviles, como por ejemplo:
Un único lugar para describir la jerarquía visual de una aplicación.
Una interfaz de usuario de navegación común.
Un esquema de navegación basado en URI que permite la navegación a cualquier página de la aplicación.
Un controlador de búsqueda integrado.
Además, las aplicaciones de Shell se benefician de una mayor velocidad de representación y un consumo reducido
de memoria.
IMPORTANT
El shell de Xamarin.Forms solo está disponible en iOS y Android. Las aplicaciones existentes de iOS y Android pueden adoptar
Shell y aprovechar inmediatamente las mejoras de navegación, rendimiento y extensibilidad.
Al seleccionar un elemento de control flotante, se selecciona y muestra la pestaña inferior que representa el
elemento:
NOTE
Cuando el control flotante no está abierto, la barra de pestañas inferior se puede considerar el nivel superior de navegación
en la aplicación.
Cada pestaña muestra un objeto ContentPage . Sin embargo, si una pestaña inferior contiene más de una página,
las páginas son navegables mediante la barra de pestañas superior:
Descargar el ejemplo
El proceso de creación de una aplicación de Xamarin.Forms Shell es el siguiente:
1. Cree una nueva aplicación de Xamarin.Forms, o cargue una aplicación existente que desee convertir en una
aplicación de Shell.
2. Agregue un archivo XAML al proyecto de código compartido que sirva de subclase de la clase Shell . Para
obtener más información, consulte Subclass the Shell class (Establecimiento de subclases en la clase Shell).
3. Establezca la propiedad MainPage de la clase App de la aplicación en el objeto Shell con subclases. Para
obtener más información, consulte Bootstrap the Shell application (Arranque de la aplicación Shell).
4. Describa la jerarquía visual de la aplicación en la clase Shell con subclases. Para obtener más información,
consulte Describe the visual hierarchy of the application (Descripción de la jerarquía visual de la aplicación).
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Xaminals.AppShell">
</Shell>
using Xamarin.Forms;
namespace Xaminals
{
public partial class AppShell : Shell
{
public AppShell()
{
InitializeComponent();
}
}
}
En este ejemplo, la clase AppShell es el archivo XAML que se deriva de la clase Shell .
NOTE
Mientras se compila una aplicación de Shell en blanco, su ejecución dará como resultado la generación de
InvalidOperationException .
Cuando se ejecuta, este XAML muestra el objeto CatsPage , porque es el primer elemento de contenido declarado
en la clase Shell con subclases:
Al presionar el icono de tres barras, o al deslizar el dedo desde la izquierda, se muestra el control flotante:
IMPORTANT
En una aplicación de Shell, cada ContentPage que es un elemento secundario de un objeto ShellContent se crea durante
el inicio de la aplicación. Agregar objetos ShellContent adicionales mediante esta estrategia dará lugar a la creación de
páginas adicionales durante el inicio de la aplicación, lo que puede conducir a una experiencia de inicio deficiente. Sin
embargo, Shell también es capaz de crear páginas a petición, en respuesta a la navegación. Para más información, consulte
Carga eficiente de páginas en la guía Pestañas de Xamarin.Forms Shell.
Vínculos relacionados
Xaminals (ejemplo)
Control flotante de Xamarin.Forms Shell
11/07/2019 • 21 minutes to read • Edit Online
Descargar el ejemplo
El control flotante es el menú raíz de una aplicación de Shell y es accesible por medio de un icono o al deslizar el
dedo desde el lado de la pantalla. El control flotante consta de un encabezado opcional, elementos de control
flotante y elementos de menú opcionales:
Si es necesario, el color de fondo del control flotante se puede establecer Color mediante la propiedad enlazable
Shell.FlyoutBackgroundColor . Esta propiedad también se puede establecer con una hoja de estilo CSS. Para más
información, consulte Propiedades específicas de Xamarin.Forms Shell.
<Shell ...
FlyoutIcon="flyouticon.png">
...
</Shell>
<Shell ...
FlyoutBehavior="Disabled">
...
</Shell>
NOTE
La propiedad adjunta FlyoutBehavior se puede establecer en los objetos Shell , FlyoutItem , ShellContent y en
objetos de página, para invalidar el comportamiento predeterminado del control flotante.
Además, el control flotante se puede abrir y cerrar mediante programación si se establece la propiedad enlazable
Shell.FlyoutIsPresented en un valor boolean que indica si el control flotante es visible actualmente:
Shell.Current.FlyoutIsPresented = false;
<Shell.FlyoutHeader>
<controls:FlyoutHeader />
</Shell.FlyoutHeader>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Xaminals.Controls.FlyoutHeader"
HeightRequest="200">
<Grid BackgroundColor="Black">
<Image Aspect="AspectFill"
Source="xamarinstore.jpg"
Opacity="0.6" />
<Label Text="Animals"
TextColor="White"
FontAttributes="Bold"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center" />
</Grid>
</ContentView>
<Shell.FlyoutHeaderTemplate>
<DataTemplate>
<Grid BackgroundColor="Black"
HeightRequest="200">
<Image Aspect="AspectFill"
Source="xamarinstore.jpg"
Opacity="0.6" />
<Label Text="Animals"
TextColor="White"
FontAttributes="Bold"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center" />
</Grid>
</DataTemplate>
</Shell.FlyoutHeaderTemplate>
<Shell ...
FlyoutHeaderBehavior="CollapseOnScroll">
...
</Shell>
En este ejemplo, solo se puede acceder a cada objeto ContentPage mediante elementos de control flotante:
NOTE
Cuando no existe un encabezado de control flotante, aparecen elementos de control flotante en la parte superior del control
flotante. En caso contrario, aparecen debajo del encabezado de control flotante.
Shell tiene operadores de conversión implícita que permiten simplificar la jerarquía visual de Shell, sin introducir
vistas adicionales en el árbol visual. Esto es posible porque un objeto Shell con subclases solo puede contener
objetos FlyoutItem o un objeto TabBar , que solo pueden contener objetos Tab , que solo pueden contener
objetos ShellContent . Estos operadores de conversión implícita pueden usarse para quitar los objetos FlyoutItem ,
Tab y ShellContent del ejemplo anterior:
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:Xaminals.Controls"
xmlns:views="clr-namespace:Xaminals.Views"
x:Class="Xaminals.AppShell">
<Shell.FlyoutHeader>
<controls:FlyoutHeader />
</Shell.FlyoutHeader>
<views:CatsPage IconImageSource="cat.png" />
<views:DogsPage IconImageSource="dog.png" />
</Shell>
Esta conversión implícita encapsula automáticamente cada objeto ContentPage en objetos ShellContent , que se
encapsulan en objetos Tab , que se encapsulan en objetos FlyoutItem .
IMPORTANT
En una aplicación de Shell, cada ContentPage que es un elemento secundario de un objeto ShellContent se crea durante
el inicio de la aplicación. Agregar objetos ShellContent adicionales mediante esta estrategia dará lugar a la creación de
páginas adicionales durante el inicio de la aplicación, lo que puede conducir a una experiencia de inicio deficiente. Sin
embargo, Shell también es capaz de crear páginas a petición, en respuesta a la navegación. Para más información, consulte
Carga eficiente de páginas en la guía Pestañas de Xamarin.Forms Shell.
Clase FlyoutItem
La clase FlyoutItem incluye las siguientes propiedades que controlan la apariencia y comportamiento del
elemento del control flotante:
FlyoutDisplayOptions , de tipo FlyoutDisplayOptions , define cómo se muestran el elemento y sus elementos
secundarios en el control flotante. El valor predeterminado es AsSingleItem .
CurrentItem , de tipo Tab , el elemento seleccionado.
Items , de tipo IList<Tab> , define todas las pestañas dentro de FlyoutItem .
FlyoutIcon , de tipo ImageSource , el icono que se usará para el elemento. Si esta propiedad no está establecida,
se volverá a usar el valor de la propiedad Icon .
Icon , de tipo ImageSource , define el icono que se mostrará en las partes del cromo que no son el control
flotante.
IsChecked , de tipo boolean , define si el elemento está actualmente resaltado en la ventana flotante.
IsEnabled , de tipo boolean , define si el elemento es seleccionable en el cromo.
IsTabStop , de tipo bool , indica si se incluye un objeto FlyoutItem en la navegación entre pestañas. Su valor
predeterminado es true , y cuando su valor es false , la infraestructura de navegación entre pestañas omite el
objeto FlyoutItem , independientemente de si se ha definido un objeto TabIndex .
TabIndex , de tipo int , indica el orden en que los objetos FlyoutItem reciben el foco cuando el usuario navega
por los elementos presionando la tecla de tabulación. El valor predeterminado de la propiedad es 0.
Title , de tipo string , el título que se mostrará en la interfaz de usuario.
Route , de tipo string , la cadena usada para abordar el elemento.
Todas estas propiedades, excepto la propiedad Route , están respaldadas por objetos BindableProperty , lo que
significa que las propiedades pueden ser destinos de los enlaces de datos.
NOTE
Todos los objetos FlyoutItem del objeto Shell en subclase se agregan a la colección Shell.Items , que define la lista de
elementos que se mostrarán en el control flotante.
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:Xaminals.Controls"
xmlns:views="clr-namespace:Xaminals.Views"
FlyoutHeaderBehavior="CollapseOnScroll"
x:Class="Xaminals.AppShell">
<Shell.FlyoutHeader>
<controls:FlyoutHeader />
</Shell.FlyoutHeader>
<FlyoutItem Title="Animals"
FlyoutDisplayOptions="AsMultipleItems">
<Tab Title="Domestic"
Icon="paw.png">
<ShellContent Title="Cats"
Icon="cat.png"
ContentTemplate="{DataTemplate views:CatsPage}" />
<ShellContent Title="Dogs"
Icon="dog.png"
ContentTemplate="{DataTemplate views:DogsPage}" />
</Tab>
<ShellContent Title="Monkeys"
Icon="monkey.png"
ContentTemplate="{DataTemplate views:MonkeysPage}" />
<ShellContent Title="Elephants"
Icon="elephant.png"
ContentTemplate="{DataTemplate views:ElephantsPage}" />
<ShellContent Title="Bears"
Icon="bear.png"
ContentTemplate="{DataTemplate views:BearsPage}" />
</FlyoutItem>
<ShellContent Title="About"
Icon="info.png"
ContentTemplate="{DataTemplate views:AboutPage}" />
</Shell>
En este ejemplo, se crean elementos de control flotante para el objeto Tab , que es secundario del objeto
FlyoutItem , y el objeto ShellContent , que son elementos secundarios del objeto FlyoutItem . Esto ocurre porque
cada objeto ShellContent que es secundario del objeto FlyoutItem se encapsula automáticamente en un objeto
Tab . Además, se crea un elemento de control flotante para el objeto ShellContent final, que se encapsula en un
objeto Tab y, luego, en un objeto FlyoutItem .
El resultado son los siguientes elementos de control flotante:
Definición de la apariencia de FlyoutItem
Se puede personalizar la apariencia de cada FlyoutItem mediante el establecimiento de la propiedad adjunta
Shell.ItemTemplate en un objeto DataTemplate :
<Shell ...>
...
<Shell.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.2*" />
<ColumnDefinition Width="0.8*" />
</Grid.ColumnDefinitions>
<Image Source="{Binding FlyoutIcon}"
Margin="5"
HeightRequest="45" />
<Label Grid.Column="1"
Text="{Binding Title}"
FontAttributes="Italic"
VerticalTextAlignment="Center" />
</Grid>
</DataTemplate>
</Shell.ItemTemplate>
</Shell>
NOTE
Shell proporciona las propiedades Title y FlyoutIcon para el objeto BindingContext de ItemTemplate .
Tras definirse un orden de tabulación, al presionar la tecla TAB se recorrerá cíclicamente el foco a través de objetos
FlyoutItem en orden de TabIndex ascendente, con una encapsulación alrededor del principio una vez alcanzado el
control final.
Además de establecer el orden de tabulación de los objetos FlyoutItem , puede ser necesario excluir algunos
objetos de dicho orden. Para ello, se puede usar la propiedad FlyoutItem.IsTabStop , que indica si un objeto
FlyoutItem se incluye en la navegación entre pestañas. Su valor predeterminado es true , y cuando su valor es
false , la infraestructura de navegación entre pestañas omite el objeto FlyoutItem , independientemente de si se
ha definido un objeto TabIndex .
<Shell ...
CurrentItem="{x:Reference aboutItem}">
<FlyoutItem Title="Animals"
FlyoutDisplayOptions="AsMultipleItems">
...
</FlyoutItem>
<ShellContent x:Name="aboutItem"
Title="About"
Icon="info.png"
ContentTemplate="{DataTemplate views:AboutPage}" />
</Shell>
Este código establece el objeto ShellContent llamado aboutItem como la propiedad CurrentItem , que hace que
se muestre. En este ejemplo, se usa una conversión implícita para encapsular el objeto ShellContent en un objeto
Tab , que se encapsula en un objeto FlyoutItem .
Elementos de menú
Los elementos del menú se pueden agregar opcionalmente a la ventana flotante, y cada elemento de menú se
representa mediante un objeto MenuItem . La posición de los objetos MenuItem en el control flotante depende de su
orden de declaración en la jerarquía visual del Shell. Por lo tanto, cualquier objeto MenuItem declarado antes de los
objetos FlyoutItem aparecerá en la parte superior del control flotante, y cualquier objeto MenuItem declarado
después de los objetos FlyoutItem aparecerá en la parte inferior del control flotante.
NOTE
La clase MenuItem tiene un evento Clicked y una propiedad Command . Por lo tanto, los objetos MenuItem permiten
escenarios que ejecutan una acción en respuesta al elemento MenuItem que se pulsa. Estos escenarios incluyen realizar la
navegación y abrir un explorador web en una página web específica.
Se pueden agregar objetos MenuItem al control flotante, tal como se muestra en el ejemplo siguiente:
<Shell ...>
...
<MenuItem Text="Random"
IconImageSource="random.png"
Command="{Binding RandomPageCommand}" />
<MenuItem Text="Help"
IconImageSource="help.png"
Command="{Binding HelpCommand}"
CommandParameter="https://docs.microsoft.com/xamarin/xamarin-forms/app-fundamentals/shell" />
</Shell>
Este código agrega dos objetos MenuItem al control flotante, debajo de todos los elementos del control flotante:
El primer objeto MenuItem ejecuta un elemento ICommand llamado RandomPageCommand , que lleva a una página
aleatoria de la aplicación. El segundo objeto MenuItem ejecuta un elemento ICommand llamado HelpCommand , que
abre la dirección URL especificada por la propiedad CommandParameter en un explorador web.
NOTE
El elemento BindingContext de cada MenuItem se hereda del objeto Shell en subclase.
<Shell ...>
<Shell.MenuItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.2*" />
<ColumnDefinition Width="0.8*" />
</Grid.ColumnDefinitions>
<Image Source="{Binding Icon}"
Margin="5"
HeightRequest="45" />
<Label Grid.Column="1"
Text="{Binding Text}"
FontAttributes="Italic"
VerticalTextAlignment="Center" />
</Grid>
</DataTemplate>
</Shell.MenuItemTemplate>
...
<MenuItem Text="Random"
IconImageSource="random.png"
Command="{Binding RandomPageCommand}" />
<MenuItem Text="Help"
IconImageSource="help.png"
Command="{Binding HelpCommand}"
CommandParameter="https://docs.microsoft.com/xamarin/xamarin-forms/app-fundamentals/shell" />
</Shell>
Este ejemplo adjunta el nivel de Shell MenuItemTemplate a cada objeto MenuItem , mostrando el título de cada
objeto MenuItem en cursiva:
NOTE
Shell proporciona las propiedades Text y IconImageSource para el elemento BindingContext del objeto
MenuItemTemplate .`
Dado que Shell.MenuItemTemplate es una propiedad adjunta, se pueden asociar diferentes plantillas a objetos
MenuItem específicos:
<Shell ...>
<Shell.MenuItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.2*" />
<ColumnDefinition Width="0.8*" />
</Grid.ColumnDefinitions>
<Image Source="{Binding Icon}"
Margin="5"
HeightRequest="45" />
<Label Grid.Column="1"
Text="{Binding Text}"
FontAttributes="Italic"
VerticalTextAlignment="Center" />
</Grid>
</DataTemplate>
</Shell.MenuItemTemplate>
...
<MenuItem Text="Random"
IconImageSource="random.png"
Command="{Binding RandomPageCommand}" />
<MenuItem Text="Help"
Icon="help.png"
Command="{Binding HelpCommand}"
CommandParameter="https://docs.microsoft.com/xamarin/xamarin-forms/app-fundamentals/shell">
<Shell.MenuItemTemplate>
<DataTemplate>
...
</DataTemplate>
</Shell.MenuItemTemplate>
</MenuItem>
</Shell>
Este ejemplo adjunta el MenuItemTemplate de nivel de Shell al primer objeto MenuItem y adjunta el
MenuItemTemplate alineado al segundo MenuItem .
Vínculos relacionados
Xaminals (ejemplo)
Pestañas de Xamarin.Forms Shell
17/07/2019 • 15 minutes to read • Edit Online
Descargar el ejemplo
Cuando el modelo de navegación para una aplicación incluye un control flotante, el siguiente nivel de navegación
de la aplicación es la barra de pestañas de la parte inferior. Además, cuando se cierra el control flotante, la barra
de pestañas inferior se puede considerar el nivel superior de navegación.
Como alternativa, el modelo de navegación para una aplicación puede comenzar con pestañas en la parte inferior
y no usar un control flotante. En este escenario, el elemento secundario del objeto Shell debe ser un objeto
TabBar , que representa la barra de pestañas de la parte inferior.
NOTE
El tipo TabBar deshabilita el control flotante.
Cada objeto FlyoutItem o TabBar puede contener uno o varios objetos Tab , donde cada objeto Tab representa
una pestaña en la barra de pestañas inferior. Cada objeto Tab puede contener uno o varios objetos ShellContent
, y cada objeto ShellContent mostrará un único objeto ContentPage . Cuando hay más de un objeto ShellContent
en un objeto Tab , los objetos ContentPage serán navegables mediante las pestañas superiores.
Dentro de cada objeto ContentPage , se puede navegar a objetos ContentPage adicionales. Para más información
sobre la navegación, consulte Navegación en Xamarin.Forms Shell.
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:views="clr-namespace:Xaminals.Views"
x:Class="Xaminals.AppShell">
<TabBar>
<Tab>
<ShellContent>
<views:CatsPage />
</ShellContent>
</Tab>
</TabBar>
</Shell>
Este ejemplo de código tiene como resultado la siguiente aplicación de página única:
NOTE
Si es necesario, la barra de navegación se puede ocultar mediante el establecimiento de la propiedad adjunta
Shell.NavBarIsVisible en false en el objeto ContentPage .
Shell tiene operadores de conversión implícita que permiten simplificar la jerarquía visual de Shell, sin introducir
vistas adicionales en el árbol visual. Esto es posible porque un objeto Shell con subclases solo puede contener
objetos FlyoutItem o un objeto TabBar , que solo pueden contener objetos Tab , que solo pueden contener
objetos ShellContent . Estos operadores de conversión implícita pueden usarse para quitar los objetos TabBar ,
Tab y ShellContent del ejemplo anterior:
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:views="clr-namespace:Xaminals.Views"
x:Class="Xaminals.AppShell"
FlyoutBehavior="Disabled">
<views:CatsPage />
</Shell>
Esta conversión implícita encapsula automáticamente el objeto ContentPage en un objeto ShellContent , que se
encapsula en un objeto Tab , que se encapsula en un objeto FlyoutItem . Un control flotante no es necesario en
una aplicación de página única y, por lo tanto, la propiedad Shell.FlyoutBehavior está establecida en Disabled .
IMPORTANT
En una aplicación de Shell, cada ContentPage que es un elemento secundario de un objeto ShellContent se crea
durante el inicio de la aplicación. Agregar objetos ShellContent adicionales mediante esta estrategia dará lugar a la
creación de páginas adicionales durante el inicio de la aplicación, lo que puede conducir a una experiencia de inicio deficiente.
Sin embargo, Shell también es capaz de crear páginas a petición, en respuesta a la navegación. Para más información,
consulte Carga eficiente de páginas.
Pestañas inferiores
Los objetos Tab se representan como pestañas inferiores, siempre y cuando haya varios objetos Tab en un
único objeto TabBar :
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:views="clr-namespace:Xaminals.Views"
x:Class="Xaminals.AppShell">
<TabBar>
<Tab Title="Cats"
Icon="cat.png">
<ShellContent>
<views:CatsPage />
</ShellContent>
</Tab>
<Tab Title="Dogs"
Icon="dog.png">
<ShellContent>
<views:DogsPage />
</ShellContent>
</Tab>
</TabBar>
</Shell>
Los títulos e iconos de pestaña se establecen en cada objeto Tab , y se muestran en las pestañas inferiores:
Como alternativa, se pueden usar operadores de conversión implícita de Shell para quitar los objetos
ShellContent y Tab del ejemplo anterior:
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:views="clr-namespace:Xaminals.Views"
x:Class="Xaminals.AppShell">
<TabBar>
<views:CatsPage IconImageSource="cat.png" />
<views:DogsPage IconImageSource="dog.png" />
</TabBar>
</Shell>
Esta conversión implícita encapsula automáticamente cada objeto ContentPage en un objeto ShellContent ,
ambos de los cuales se encapsulan en un objeto Tab .
IMPORTANT
En una aplicación de Shell, cada ContentPage que es un elemento secundario de un objeto ShellContent se crea
durante el inicio de la aplicación. Agregar objetos ShellContent adicionales mediante esta estrategia dará lugar a la
creación de páginas adicionales durante el inicio de la aplicación, lo que puede conducir a una experiencia de inicio deficiente.
Sin embargo, Shell también es capaz de crear páginas a petición, en respuesta a la navegación. Para más información,
consulte Carga eficiente de páginas.
Clase Tab
La clase Tab incluye las siguientes propiedades que controlan la apariencia y el comportamiento de las pestañas:
CurrentItem , de tipo , el elemento seleccionado.
ShellContent
FlyoutDisplayOptions , de tipo FlyoutDisplayOptions , define cómo se muestran el elemento y sus elementos
secundarios en el control flotante. El valor predeterminado es AsSingleItem .
FlyoutIcon , de tipo ImageSource , define el icono que se mostrará en el control flotante.
Icon , de tipo ImageSource , define el icono que se mostrará en partes del cromo que no son la ventana
flotante.
IsChecked , de tipo boolean , define si el elemento está actualmente resaltado en la ventana flotante.
IsEnabled , de tipo boolean , define si el elemento es seleccionable en el cromo.
IsTabStop , de tipo bool , indica si se incluye un objeto Tab en la navegación entre pestañas. Su valor
predeterminado es true , y cuando su valor es false , la infraestructura de navegación entre pestañas omite
el objeto Tab , independientemente de si se ha definido un objeto TabIndex .
Items , de tipo IList<ShellContent> , define todo el contenido dentro de un objeto Tab .
TabIndex , de tipo int , indica el orden en que los objetos Tab reciben el foco cuando el usuario navega por
los elementos presionando la tecla de tabulación. El valor predeterminado de la propiedad es 0.
Title , de tipo string , el título que se mostrará en la pestaña en la interfaz de usuario.
Contenido de Shell
El elemento secundario de cada objeto Tab es un objeto ShellContent cuya propiedad Content está establecida
en ContentPage :
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:views="clr-namespace:Xaminals.Views"
x:Class="Xaminals.AppShell">
<TabBar>
<Tab Title="Cats"
Icon="cat.png">
<ShellContent>
<views:CatsPage />
</ShellContent>
</Tab>
<Tab Title="Dogs"
Icon="dog.png">
<ShellContent>
<views:DogsPage />
</ShellContent>
</Tab>
</TabBar>
</Shell>
Dentro de cada objeto ContentPage , se puede navegar a objetos ContentPage adicionales. Para más información
sobre la navegación, consulte Navegación en Xamarin.Forms Shell.
Clase ShellContent
La clase ShellContent incluye las siguientes propiedades que controlan la apariencia del contenido de las
pestañas y su comportamiento:
Content , de tipo , el contenido de ShellContent .
object
ContentTemplate , de tipo DataTemplate , la plantilla usada para aumentar dinámicamente el contenido de
ShellContent .
FlyoutIcon , de tipo ImageSource , define el icono que se mostrará en el control flotante.
Icon , de tipo ImageSource , define el icono que se mostrará en partes del cromo que no son la ventana
flotante.
IsChecked , de tipo boolean , define si el elemento está actualmente resaltado en la ventana flotante.
IsEnabled , de tipo boolean , define si el elemento es seleccionable en el cromo.
MenuItems , de tipo MenuItemCollection , los elementos de menú para mostrar en el control flotante cuando
ShellContent es la página presentada.
Title , de tipo string , el título que se mostrará en la interfaz de usuario.
Todas estas propiedades están respaldados por objetos BindableProperty , lo que significa que las propiedades
pueden ser destinos de los enlaces de datos.
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:views="clr-namespace:Xaminals.Views"
x:Class="Xaminals.AppShell">
<TabBar>
<Tab Title="Domestic"
Icon="domestic.png">
<ShellContent>
<views:CatsPage />
</ShellContent>
<ShellContent>
<views:DogsPage />
</ShellContent>
</Tab>
<Tab Title="Monkeys"
Icon="monkey.png">
<ShellContent>
<views:MonkeysPage />
</ShellContent>
</Tab>
</TabBar>
</Shell>
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:views="clr-namespace:Xaminals.Views"
x:Class="Xaminals.AppShell">
<TabBar>
<Tab Title="Domestic"
Icon="domestic.png">
<views:CatsPage />
<views:DogsPage />
</Tab>
<views:MonkeysPage IconImageSource="monkey.png" />
</TabBar>
</Shell>
Este XAML crea y muestra CatsPage , porque es el primer elemento del contenido declarado en el objeto Shell
en subclase. Se puede navegar por las páginas CatsPage y MonkeysPage mediante pestañas inferiores, y estas
páginas solo se crean cuando el usuario se desplaza hasta ellas. La ventaja de este enfoque es que se evita la
experiencia de inicio deficiente, ya que las páginas se crean a petición en respuesta a la navegación, y no cuando
se inicia la aplicación.
Todas estas propiedades están respaldados por objetos BindableProperty , lo que significa que las propiedades
pueden ser destinos de los enlaces de datos, y se les puede aplicar estilos.
En el ejemplo siguiente se muestra un estilo XAML que establece diferentes propiedades de color de las pestañas:
<Style x:Key="BaseStyle"
TargetType="Element">
<Setter Property="Shell.TabBarBackgroundColor"
Value="#3498DB" />
<Setter Property="Shell.TabBarTitleColor"
Value="White" />
<Setter Property="Shell.TabBarUnselectedColor"
Value="#B4FFFFFF" />
</Style>
Además, también se puede aplicar estilo a las pestañas mediante Hojas de estilos CSS. Para más información,
consulte Propiedades específicas de Xamarin.Forms Shell.
Vínculos relacionados
Xaminals (ejemplo)
Navegación en Xamarin.Forms Shell
Xamarin.Forms CSS Shell specific properties (Propiedades específicas de Xamarin.Forms CSS Shell)
Configuración de la página Xamarin.Forms Shell
11/07/2019 • 7 minutes to read • Edit Online
Descargar el ejemplo
La clase Shell define las propiedades adjuntas que se pueden usar para configurar la apariencia de las páginas en
las aplicaciones de Xamarin.Forms Shell. Esto incluye establecer los colores de la página, deshabilitar la barra de
navegación y la barra de pestañas y mostrar las vistas en la barra de navegación.
NOTE
También hay propiedades que permiten la definición de los colores de las pestañas. Para obtener más información, vea
Apariencia de las pestañas.
El XAML siguiente muestra el establecimiento de las propiedades de color en una clase Shell con subclases:
</Shell>
En este ejemplo, los valores de color se aplicarán a todas las páginas de la aplicación de Shell, a menos que se
invaliden en el nivel de página.
Dado que las propiedades de color son las propiedades adjuntas, también pueden establecerse en páginas
individuales, para establecer los colores de esa página:
<ContentPage ...
Shell.BackgroundColor="Gray"
Shell.ForegroundColor="White"
Shell.TitleColor="Blue"
Shell.DisabledColor="#95FFFFFF"
Shell.UnselectedColor="#B4FFFFFF">
</ContentPage>
Como alternativa, se pueden establecer las propiedades de color con un estilo XAML:
<Style x:Key="DomesticShell"
TargetType="Element" >
<Setter Property="Shell.BackgroundColor"
Value="#039BE6" />
<Setter Property="Shell.ForegroundColor"
Value="White" />
<Setter Property="Shell.TitleColor"
Value="White" />
<Setter Property="Shell.DisabledColor"
Value="#B4FFFFFF" />
<Setter Property="Shell.UnselectedColor"
Value="#95FFFFFF" />
</Style>
Para obtener más información sobre los estilos XAML, vea Styling Xamarin.Forms Apps using XAML Styles
(Aplicación de estilo a aplicaciones Xamarin.Forms mediante XAML ).
<ContentPage ...
Shell.NavBarIsVisible="false">
...
</ContentPage>
Como resultado, la barra de navegación deja de ser visible cuando se presenta la página:
Deshabilitación de la barra de pestañas
La clase Shell define la propiedad adjunta TabBarIsVisible , de tipo bool , que define si la barra de pestañas
debe estar visible cuando se presenta una página. De forma predeterminada, el valor de la propiedad es true .
Aunque esta propiedad se puede establecer en un objeto Shell con subclases, normalmente se establece en todas
las páginas en las que se desea que no esté visible la barra de pestañas. Por ejemplo, el siguiente XAML muestra la
deshabilitación de la barra de pestañas de ContentPage :
<ContentPage ...
Shell.TabBarIsVisible="false">
...
</ContentPage>
Como resultado, la barra de pestañas deja de ser visible cuando se presenta la página:
<ContentPage ...>
<Shell.TitleView>
<Image Source="xamarin_logo.png"
HorizontalOptions="Center"
VerticalOptions="Center" />
</Shell.TitleView>
...
</ContentPage>
Esto da como resultado una imagen que se muestra en la barra de navegación de la página:
IMPORTANT
Si se ha configurado la barra de navegación para que no sea visible, con la propiedad adjunta NavBarIsVisible , la vista de
título no se mostrará.
Muchas vistas no aparecen en la barra de navegación, salvo que el tamaño de la vista se especifique con las
propiedades WidthRequest y HeightRequest , o la ubicación de la vista se especifique con las propiedades
HorizontalOptions y VerticalOptions .
Dado que la clase Layout se deriva de la clase View , la propiedad adjunta TitleView se puede establecer para
mostrar una clase de diseño que contiene varias vistas. De igual manera, dado que la clase ContentView se deriva
en última instancia de la clase View , la propiedad adjunta TitleView se puede establecer para mostrar un
ContentView que contenga una sola vista.
Vínculos relacionados
Xaminals (ejemplo)
Aplicación de estilos para aplicaciones Xamarin.Forms con estilos XAML
Xamarin.Forms CSS Shell specific properties (Propiedades específicas de Xamarin.Forms CSS Shell)
Navegación en Xamarin.Forms Shell
11/07/2019 • 20 minutes to read • Edit Online
Descargar el ejemplo
Xamarin.Forms Shell incluye una experiencia de navegación basada en el URI que emplea rutas para navegar a
cualquier página de la aplicación, sin tener que seguir una jerarquía de navegación establecida. También ofrece la
posibilidad de navegar hacia atrás sin tener que visitar todas las páginas de la pila de navegación.
Shell define las siguientes propiedades relacionadas con la navegación:
BackButtonBehavior , de tipo BackButtonBehavior , una propiedad adjunta que define el comportamiento del
botón Atrás.
CurrentItem , de tipo FlyoutItem , el valor de FlyoutItem seleccionado actualmente.
CurrentState , de tipo ShellNavigationState , el estado de navegación actual de Shell .
Current , de tipo Shell , un alias con el tipo convertido para Application.Current.MainPage .
La navegación se realiza mediante la invocación del método GoToAsync , desde la clase Shell . Cuando la
navegación está a punto de realizarse, se activa un evento Navigating y cuando finaliza, se activa un evento
Navigated .
NOTE
La navegación todavía se puede realizar en una aplicación de Xamarin.Forms Shell mediante la propiedad Navigation. Para
más información, consulte Navegación jerárquica.
Rutas
La navegación se realiza en una aplicación de Shell mediante la especificación de un URI al que navegar. Los URI
de navegación pueden tener tres componentes:
Una ruta, que define la ruta de acceso al contenido que existe como parte de la jerarquía visual de Shell.
Una página. Las páginas que no existen en la jerarquía visual de Shell se pueden insertar en la pila de
navegación desde cualquier lugar dentro de una aplicación de Shell. Por ejemplo, una página de detalles de
elementos no se definirá en la jerarquía visual de Shell, pero se puede insertar en la pila de navegación si es
necesario.
Uno o varios parámetros de consulta. Los parámetros de consulta son parámetros que se pueden pasar a la
página de destino durante la navegación.
Cuando un URI de navegación incluye los tres componentes, la estructura es: //route/page?queryParameters
Registro de rutas
Las rutas se pueden definir en objetos FlyoutItem , Tab y ShellContent mediante sus propiedades Route :
<Shell ...>
<FlyoutItem ...
Route="animals">
<Tab ...
Route="domestic">
<ShellContent ...
Route="cats" />
<ShellContent ...
Route="dogs" />
</Tab>
<ShellContent ...
Route="monkeys" />
<ShellContent ...
Route="elephants" />
<ShellContent ...
Route="bears" />
</FlyoutItem>
<ShellContent ...
Route="about" />
...
</Shell>
NOTE
Todos los elementos de la jerarquía de Shell tienen asociada una ruta. Si el desarrollador no establece una ruta, esta se
genera en tiempo de ejecución. Sin embargo, no se garantiza que las rutas generadas sean coherentes entre distintas
sesiones de aplicación.
En este ejemplo se crea la siguiente jerarquía de ruta desde la misma aplicación, que se puede usar en la
navegación mediante programación:
animals
domestic
cats
dogs
monkeys
elephants
bears
about
Para desplazarse al objeto ShellContent de la ruta dogs , el URI de la ruta absoluta es //animals/domestic/dogs .
Igualmente, para desplazarse al objeto ShellContent de la ruta about , el URL de la ruta absoluta es //about .
IMPORTANT
Se permiten nombres duplicados de ruta. Sin embargo, no se permiten rutas duplicadas. Si se detecta una ruta duplicada,
se produce una excepción ArgumentException al inicio de la aplicación.
En este ejemplo se registran como rutas páginas de detalles de elementos que no están definidas en la subclase
de Shell. Luego, es posible desplazarse por estas páginas desde cualquier lugar de la aplicación mediante la
navegación basada en el URI. Las rutas de estas páginas se conocen como rutas globales.
NOTE
Si es necesario, se puede cancelar el registro de las páginas cuyas rutas se han registrado con el método
Routing.RegisterRoute , con el método Routing.UnRegisterRoute .
Routing.RegisterRoute("monkeys/details", typeof(MonkeyDetailPage));
Routing.RegisterRoute("bears/details", typeof(BearDetailPage));
Routing.RegisterRoute("cats/details", typeof(CatDetailPage));
Routing.RegisterRoute("dogs/details", typeof(DogDetailPage));
Routing.RegisterRoute("elephants/details", typeof(ElephantDetailPage));
En este ejemplo se habilita la navegación contextual por las páginas, donde la navegación a la ruta details
desde la página de la ruta monkeys muestra MonkeyDetailPage . De forma similar, al desplazarse a la ruta
details desde la página de la ruta elephants se muestra ElephantDetailPage .
IMPORTANT
Actualmente, se permiten nombres de ruta duplicados cuando se usa el método Routing.RegisterRoute , donde el
registro duplicado sobrescribe el registro anterior.
Realización de la navegación
Para realizar la navegación, se debe obtener primero una referencia a la subclase Shell . Esta referencia se
puede obtener mediante la conversión de la propiedad App.Current.MainPage en un objeto Shell , por medio de
la propiedad Shell.Current . Luego, se puede realizar la navegación mediante la llamada al método GoToAsync
en el objeto Shell . Este método lleva a ShellNavigationState y devuelve un objeto Task que se completa una
vez completada la animación de navegación. El objeto ShellNavigationState se construye mediante el método
GoToAsync , desde una propiedad string o Uri , y tiene su propiedad Location establecida en el argumento
string o Uri .
Cuando se navega a una ruta de la jerarquía visual de Shell, no se crea una pila de navegación. Sin embargo,
cuando se navega a una página que no está en la jerarquía visual de Shell, se crea una pila de navegación.
NOTE
El estado actual de navegación de Shell se puede recuperar mediante la propiedad Shell.Current.CurrentState , que
incluye el URI de la ruta mostrada en la propiedad Location .
Rutas absolutas
Se puede realizar la navegación mediante la especificación de un URI absoluto válido como argumento del
método GoToAsync :
await Shell.Current.GoToAsync("//animals/monkeys");
En este ejemplo se navega a la página de la ruta monkeys , donde dicha ruta se define en un objeto ShellContent .
El objeto ShellContent que representa la ruta monkeys es un elemento secundario de un objeto FlyoutItem ,
cuya ruta es animals .
Rutas relativas
La navegación se puede realizar también mediante la especificación de un URI relativo válido como argumento
del método GoToAsync . El sistema de enrutamiento intenta hacer coincidir el URI con un objeto ShellContent .
Por lo tanto, si todas las rutas de una aplicación son únicas, la navegación se puede realizar con solo especificar
el nombre de ruta único como un URI relativo:
await Shell.Current.GoToAsync("monkeydetails");
FORMATO DESCRIPCIÓN
Navegación contextual
Las rutas relativas permiten la navegación contextual. Por ejemplo, considere la siguiente jerarquía de ruta:
monkeys
details
bears
details
Cuando se muestra la página registrada para la ruta monkeys , al navegar a la ruta details se mostrará la
página registrada para la ruta monkeys/details . Igualmente, cuando se muestra la página registrada para la ruta
bears , al navegar a la ruta details se mostrará la página registrada para la ruta bears/details . Para
información sobre cómo registrar las rutas en este ejemplo, consulte Registro de rutas de página.
Rutas no válidas
Los siguientes formatos de ruta no son válidos:
FORMATO EXPLICACIÓN
El uso de cualquiera de estos formatos de ruta dará como resultado una excepción Exception .
IMPORTANT
Al intentar navegar a una ruta inexistente, se producirá una excepción ArgumentException .
Depuración de la navegación
Algunas de las clases de Shell se representan con DebuggerDisplayAttribute , que especifica cómo el depurador
muestra una clase o campo. Esto puede ayudar a depurar las solicitudes de navegación puesto que se muestran
los datos relacionados con la solicitud de navegación. Por ejemplo, en la captura de pantalla siguiente se
muestran las propiedades CurrentItem y CurrentState del objeto Shell.Current :
En este ejemplo, la propiedad CurrentItem , de tipo FlyoutItem , muestra el título y la ruta del objeto FlyoutItem .
Igualmente, la propiedad CurrentState , de tipo ShellNavigationState , muestra el URI de la ruta mostrada
dentro de la aplicación de Shell.
Clase Tab
La clase Tab define una propiedad Stack , de tipo IReadOnlyList<Page> , que representa la pila de navegación
actual insertada en Tab . La clase también proporciona los siguientes métodos de navegación reemplazables:
GetNavigationStack , devuelve IReadOnlyList<Page >, la pila de navegación actual.
OnInsertPageBefore , que se llama cuando se llama a INavigation.InsertPageBefore .
OnPopAsync , devuelve Task<Page> , y se llama cuando se llama a INavigation.PopAsync .
OnPopToRootAsync , devuelve Task , y se llama cuando se llama a INavigation.OnPopToRootAsync .
OnPushAsync , devuelve Task , y se llama cuando se llama a INavigation.PushAsync .
OnRemovePage , que se llama cuando se llama a INavigation.RemovePage .
Eventos de navegación
La clase Shell define un evento Navigating , que se desencadena cuando está a punto de realizarse la
navegación, ya sea debido a la navegación mediante programación o a la interacción del usuario. El objeto
ShellNavigatingEventArgs que acompaña al evento Navigating proporciona las siguientes propiedades:
Además, la clase ShellNavigatingEventArgs proporciona un método Cancel que se puede usar para cancelar la
navegación.
NOTE
El evento Navigated se desencadena por el método OnNavigating reemplazable de la clase Shell .
La clase Shell también define un evento Navigated , que se desencadena cuando se ha completado la
navegación. El objeto ShellNavigatedEventArgs que acompaña al evento Navigating proporciona las siguientes
propiedades:
NOTE
El evento Navigating se desencadena por el método OnNavigated reemplazable de la clase Shell .
Unknown
Push
Pop
PopToRoot
Insert
Remove
ShellItemChanged
ShellSectionChanged
ShellContentChanged
Por lo tanto, en un controlador del evento Navigating , es posible interceptar la navegación y realizar acciones en
función del origen de navegación. Por ejemplo, el código siguiente muestra cómo cancelar la navegación hacia
atrás si no se han guardado los datos de la página:
Pasar datos
Al realizar la navegación mediante programación, los datos pueden pasarse como parámetros de consulta. Por
ejemplo, el código siguiente se ejecuta en la aplicación de ejemplo cuando un usuario selecciona un elefante en
ElephantsPage :
[QueryProperty("Name", "name")]
public partial class ElephantDetailPage : ContentPage
{
public string Name
{
set
{
BindingContext = ElephantData.Elephants.FirstOrDefault(m => m.Name ==
Uri.UnescapeDataString(value));
}
}
...
}
El primer argumento de QueryPropertyAttribute especifica el nombre de la propiedad que recibirá los datos,
mientras que el segundo argumento especifica el identificador del parámetro de consulta. Por tanto, el elemento
QueryPropertyAttribute del ejemplo anterior especifica que la propiedad Name recibirá los datos pasados al
parámetro de consulta name del URI en la llamada al método GoToAsync . La propiedad Name decodifica
entonces el valor del parámetro de consulta en una dirección URL y lo usa para establecer el objeto
BindingContext de la página en el objeto que se mostrará.
NOTE
Una clase se puede representar con varios objetos QueryPropertyAttribute .
Todas estas propiedades están respaldados por objetos BindableProperty , lo que significa que las propiedades
pueden ser destinos de los enlaces de datos.
La clase BackButtonBehavior se puede consumir mediante el establecimiento de la propiedad adjunta
Shell.BackButtonBehavior a un objeto BackButtonBehavior :
<ContentPage ...>
<Shell.BackButtonBehavior>
<BackButtonBehavior Command="{Binding BackCommand}"
IconOverride="back.png" />
</Shell.BackButtonBehavior>
...
</ContentPage>
La propiedad Command se establece en ICommand para ejecutarse cuando se presiona el botón Atrás, y la
propiedad IconOverride se establece en el icono que se usa para el botón Atrás:
Vínculos relacionados
Xaminals (ejemplo)
Búsqueda de Xamarin.Forms Shell
11/07/2019 • 19 minutes to read • Edit Online
Descargar el ejemplo
Xamarin.Forms Shell incluye la funcionalidad de búsqueda integrada que proporciona la clase SearchHandler . La
funcionalidad de búsqueda se puede agregar a una página mediante el establecimiento de la propiedad adjunta
Shell.SearchHandler en un objeto SearchHandler en subclase. El resultado es un cuadro de búsqueda que se
agrega en la parte superior de la página:
Cuando se escribe una consulta en el cuadro de búsqueda, la propiedad Query se actualiza y, en cada
actualización, se ejecuta el método OnQueryChanged . Este método se puede invalidar para rellenar el área de
sugerencias de búsqueda con datos:
Luego, cuando se selecciona un resultado del área de sugerencias de búsqueda, se ejecuta el método
OnItemSelected . Este método se puede invalidar para responder de forma adecuada; por ejemplo, navegando a
una página de detalles.
if (string.IsNullOrWhiteSpace(newValue))
{
ItemsSource = null;
}
else
{
ItemsSource = MonkeyData.Monkeys
.Where(monkey => monkey.Name.ToLower().Contains(newValue.ToLower()))
.ToList<Animal>();
}
}
// Note: strings will be URL encoded for navigation (e.g. "Blue Monkey" becomes "Blue%20Monkey").
Therefore, decode at the receiver.
await (App.Current.MainPage as Xamarin.Forms.Shell).GoToAsync($"monkeydetails?name=
{((Animal)item).Name}");
}
}
La invalidación OnQueryChanged tiene dos argumentos: oldValue , que contiene la consulta de búsqueda anterior, y
newValue , que contiene la consulta de búsqueda actual. El área de sugerencias de búsqueda se puede actualizar
mediante el establecimiento de la propiedad SearchHandler.ItemsSource en una colección IEnumerable que
contiene elementos que coinciden con la consulta de búsqueda actual.
Cuando el usuario selecciona un resultado de búsqueda, se ejecuta la invalidación OnItemSelected y se establece la
propiedad SelectedItem . En este ejemplo, el método dirige a otra página que muestra datos sobre el elemento
Animal seleccionado. Para más información sobre la navegación, consulte Navegación en Xamarin.Forms Shell.
NOTE
Se pueden establecer propiedades SearchHandler adicionales para controlar la apariencia del cuadro de búsqueda.
<ContentPage ...
xmlns:controls="clr-namespace:Xaminals.Controls">
<Shell.SearchHandler>
<controls:MonkeySearchHandler Placeholder="Enter search term"
ShowsResults="true"
DisplayMemberName="Name" />
</Shell.SearchHandler>
...
</ContentPage>
<ContentPage ...
xmlns:controls="clr-namespace:Xaminals.Controls">
<Shell.SearchHandler>
<controls:MonkeySearchHandler Placeholder="Enter search term"
ShowsResults="true">
<controls:MonkeySearchHandler.ItemTemplate>
<DataTemplate>
<Grid Padding="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.15*" />
<ColumnDefinition Width="0.85*" />
</Grid.ColumnDefinitions>
<Image Source="{Binding ImageUrl}"
Aspect="AspectFill"
HeightRequest="40"
WidthRequest="40" />
<Label Grid.Column="1"
Text="{Binding Name}"
FontAttributes="Bold" />
</Grid>
</DataTemplate>
</controls:MonkeySearchHandler.ItemTemplate>
</controls:MonkeySearchHandler>
</Shell.SearchHandler>
...
</ContentPage>
grid.Children.Add(image);
grid.Children.Add(nameLabel, 1, 0);
return grid;
})
});
Los elementos especificados en DataTemplate definen la apariencia de cada elemento en el área de sugerencias. En
este ejemplo, el diseño dentro de DataTemplate se administra mediante un objeto Grid . El objeto Grid contiene
un objeto Image y un objeto Label , que enlazan ambos con las propiedades de cada objeto Monkey .
Las capturas de pantalla siguientes muestran el resultado de crear plantillas para cada elemento del área de
sugerencias:
Para obtener más información sobre las plantillas de datos, consulte Plantillas de datos de Xamarin.Forms.
<ContentPage ...
xmlns:controls="clr-namespace:Xaminals.Controls">
<Shell.SearchHandler>
<controls:MonkeySearchHandler SearchBoxVisibility="Hidden"
... />
</Shell.SearchHandler>
...
</ContentPage>
Apariencia SearchHandler
La clase SearchHandler define las siguientes propiedades que afectan a su apariencia:
BackgroundColor , del tipo Color , es el color de fondo para el texto del cuadro de búsqueda.
CancelButtonColor , del tipo Color , es el color del botón Cancelar.
FontAttributes , del tipo FontAttributes , indica si el texto del cuadro de búsqueda está en negrita o cursiva.
FontFamily , del tipo string , es la familia de fuentes utilizada para el texto del cuadro de búsqueda.
FontSize , del tipo double , es el tamaño del texto del cuadro de búsqueda.
HorizontalTextAlignment , del tipo TextAlignment , es la alineación horizontal del texto del cuadro de búsqueda.
PlaceholderColor , del tipo Color , es el color del texto del cuadro de búsqueda del marcador de posición.
TextColor , del tipo Color , es el color del texto del cuadro de búsqueda.
Teclado SearchHandler
El teclado que aparece cuando los usuarios interactúan con un SearchHandler se puede establecer mediante
programación a través de la propiedad Keyboard en una de las siguientes propiedades desde la clase Keyboard :
Chat : se usa para el texto y los lugares donde los emoji son útiles.
Default : el teclado predeterminado.
Email : se usa al especificar direcciones de correo electrónico.
Numeric : se usa al escribir números.
Plain : se usa al escribir texto, sin ningún KeyboardFlags especificado.
Telephone : se usa al escribir números de teléfono.
Text : se usa al escribir texto.
Url : se usa para especificar las rutas de acceso de archivo y direcciones web.
La clase Keyboard tiene también un patrón de diseño Factory Method Create que puede usarse para personalizar
un teclado mediante la especificación del comportamiento de las mayúsculas y minúsculas, el corrector ortográfico
y las sugerencias. Los valores de enumeración KeyboardFlags se especifican como argumentos para el método,
con la devolución de un Keyboard personalizado. La enumeración KeyboardFlags contiene los valores siguientes:
None : no se agregan características al teclado.
CapitalizeSentence : indica que la primera letra de la primera palabra de cada frase se escribirá
automáticamente en mayúsculas.
Spellcheck : indica que se pasará el corrector ortográfico al texto especificado.
Suggestions : indica que se ofrecerán finalizaciones de palabra para el texto especificado.
CapitalizeWord : indica que las primeras letras de todas las palabras se escribirán automáticamente en
mayúsculas.
CapitalizeCharacter : indica que todos los caracteres se escribirán automáticamente en mayúsculas.
CapitalizeNone : indica que no se producirá ningún uso automático de mayúsculas.
All : indica que se pasará el corrector automático, se ofrecerán finalizaciones de palabras y las frases
empezarán en mayúsculas en el texto especificado.
El ejemplo de código XAML siguiente muestra cómo personalizar el Keyboard predeterminado para ofrecer
finalizaciones de palabras y poner en mayúsculas todos los caracteres especificados:
Referencia de SearchHandler
La clase SearchHandler define las siguientes propiedades que controlan su apariencia y comportamiento:
BackgroundColor , del tipo Color , es el color de fondo para el texto del cuadro de búsqueda.
CancelButtonColor , del tipo Color , es el color del botón Cancelar.
ClearIcon , de tipo ImageSource , el icono que aparece para borrar el contenido del cuadro de búsqueda.
ClearIconHelpText , de tipo string , el texto de ayuda accesible para el icono de borrar.
ClearIconName , de tipo string , el nombre del icono de borrar para usar con los lectores de pantalla.
ClearPlaceholderCommand , de tipo ICommand , que se ejecuta cuando se pulsa ClearPlaceholderIcon .
ClearPlaceholderCommandParameter , de tipo object , que es el parámetro que se pasa a ClearPlaceholderCommand .
ClearPlaceholderEnabled , de tipo bool , que determina si se puede ejecutar ClearPlaceholderCommand . El valor
predeterminado es true .
ClearPlaceholderHelpText , de tipo string , el texto de ayuda accesible para el icono de borrar marcador de
posición.
ClearPlaceholderIcon , de tipo ImageSource , el icono de borrar marcador de posición que se muestra cuando el
cuadro de búsqueda está vacío.
ClearPlaceholderName , de tipo string , el nombre del icono de borrar marcador de posición para su uso con los
lectores de pantalla.
Command , de tipo ICommand , que se ejecuta cuando se confirma la consulta de búsqueda.
CommandParameter , de tipo object , que es el parámetro que se pasa a Command .
DisplayMemberName , de tipo string , que representa el nombre o la ruta de acceso de la propiedad que se
muestra para cada elemento de datos de la colección ItemsSource .
FontAttributes , del tipo FontAttributes , indica si el texto del cuadro de búsqueda está en negrita o cursiva.
FontFamily , del tipo string , es la familia de fuentes utilizada para el texto del cuadro de búsqueda.
FontSize , del tipo double , es el tamaño del texto del cuadro de búsqueda.
HorizontalTextAlignment , del tipo TextAlignment , es la alineación horizontal del texto del cuadro de búsqueda.
IsFocused , del tipo bool , que representa si un SearchHandler actualmente tiene foco de entrada.
IsSearchEnabled , de tipo bool , que representa el estado habilitado del cuadro de búsqueda. El valor
predeterminado es true .
ItemsSource , de tipo IEnumerable , especifica la colección de elementos que se mostrarán en el área de
sugerencias, y tiene un valor predeterminado de null .
ItemTemplate , de tipo DataTemplate , especifica la plantilla que se aplicará a cada elemento de la colección de
elementos que se mostrará en el área de sugerencias.
Keyboard , del tipo Keyboard , es el teclado para el SearchHandler .
Placeholder , de tipo string , el texto que se muestra cuando el cuadro de búsqueda está vacío.
PlaceholderColor , del tipo Color , es el color del texto del cuadro de búsqueda del marcador de posición.
Query , de tipo string , el texto especificado por el usuario en el cuadro de búsqueda.
QueryIcon , de tipo ImageSource , el icono utilizado para indicar al usuario que la búsqueda está disponible.
QueryIconHelpText , de tipo string , el texto de ayuda accesible para el icono de consulta.
QueryIconName , de tipo string , el nombre del icono de consulta para su uso con los lectores de pantalla.
SearchBoxVisibility , de tipo SearchBoxVisibility , la visibilidad del cuadro de búsqueda. De forma
predeterminada, el cuadro de búsqueda está visible y totalmente expandido.
SelectedItem , de tipo object , el elemento seleccionado en los resultados de búsqueda. Esta propiedad es de
solo lectura y tiene un valor predeterminado de null .
ShowsResults , de tipo bool , indica si se deben esperar resultados de búsqueda en el área de sugerencias, al
escribir texto. El valor predeterminado es false .
TextColor , del tipo Color , es el color del texto del cuadro de búsqueda.
Todas estas propiedades están respaldados por objetos BindableProperty , lo que significa que las propiedades
pueden ser destinos de los enlaces de datos.
Además, la clase SearchHandler proporciona los métodos reemplazables siguientes:
OnClearPlaceholderClicked , que se llama cada vez que se pulsa ClearPlaceholderIcon .
OnItemSelected , que se llama cada vez que el usuario selecciona un resultado de búsqueda.
OnFocused , al que se llama cuando un SearchHandler adquiere el foco de entrada.
OnQueryChanged , que se llama cuando cambia la propiedad Query .
OnQueryConfirmed , que se llama cada vez que el usuario presiona Entrar o confirma su consulta en el cuadro de
búsqueda.
OnUnfocus , al que se llama cuando un SearchHandler pierde el foco de entrada.
Vínculos relacionados
Xaminals (ejemplo)
Navegación en Xamarin.Forms Shell
Representadores personalizados de Xamarin.Forms
Shell
11/07/2019 • 6 minutes to read • Edit Online
Una de las ventajas de las aplicaciones de Xamarin.Forms Shell es que su apariencia y comportamiento es muy
personalizable mediante las propiedades y los métodos que exponen las distintas clases de Shell. Sin embargo,
también es posible crear a un representador personalizado de Shell cuando se requieren personalizaciones más
sofisticadas específicas de la plataforma. Al igual que con otros representadores personalizados, se puede agregar
un representador personalizado de Shell a solo un proyecto de plataforma para personalizar la apariencia y el
comportamiento, mientras se permite el comportamiento predeterminado en la otra plataforma; o se puede
agregar un representador personalizado de Shell diferente a cada proyecto de plataforma para personalizar la
apariencia y el comportamiento en iOS y Android.
Las aplicaciones de Shell se representan mediante la clase ShellRenderer en iOS y Android. En iOS, la clase
ShellRenderer se puede encontrar en el espacio de nombres Xamarin.Forms.Platform.iOS . En Android, la clase
ShellRenderer se puede encontrar en el espacio de nombres Xamarin.Forms.Platform.Android .
NOTE
Es opcional para proporcionar un representador personalizado de Shell en cada proyecto de plataforma. Si no está registrado
un representador personalizado, se usará entonces la clase ShellRenderer predeterminada.
SetElementSize CreateFragmentForPage
CreateFlyoutRenderer CreateShellFlyoutContentRenderer
CreateNavBarAppearanceTracker CreateShellFlyoutRenderer
CreatePageRendererTracker CreateShellItemRenderer
CreateShellFlyoutContentRenderer CreateShellSectionRenderer
CreateShellItemRenderer CreateTrackerForToolbar
CreateShellItemTransition CreateToolbarAppearanceTracker
CreateShellSearchResultsRenderer CreateTabLayoutAppearanceTracker
CreateShellSectionRenderer CreateBottomNavViewAppearanceTracker
CreateTabBarAppearanceTracker OnElementPropertyChanged
Dispose OnElementSet
OnCurrentItemChanged SwitchFragment
OnElementPropertyChanged Dispose
OnElementSet
UpdateBackgroundColor
Las clases FlyoutItem y TabBar son alias de la clase ShellItem , y la clase Tab es un alias de la clase
ShellSection . Por lo tanto, el método CreateShellItemRenderer se debe invalidar al crear un representador
personalizado para objetos FlyoutItem , y el método CreateShellSectionRenderer se debe invalidar al crear un
representador personalizado para objetos Tab .
IMPORTANT
Hay clases de representador adicionales de Shell, como ShellSectionRenderer y ShellItemRenderer , en iOS y Android.
Sin embargo, estas clases de representador adicionales se crean mediante invalidaciones en la clase ShellRenderer . Por lo
tanto, para personalizar el comportamiento de estas clases de representador adicionales, puede crear una subclase de ellas y
una instancia de la subclase en la invalidación adecuada de la clase ShellRenderer en subclase.
Ejemplo de iOS
En el ejemplo de código siguiente se muestra una clase ShellRenderer en subclase para iOS, que establece una
imagen de fondo en la barra de navegación de la aplicación de Shell:
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using Android.Content;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using Android.Support.V7.Widget;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
namespace Xaminals.Droid
{
public class MyShellToolbarAppearanceTracker : ShellToolbarAppearanceTracker
{
public MyShellToolbarAppearanceTracker(IShellContext context) : base(context)
{
}
IMPORTANT
Solo es necesario agregar el objeto ExportRendererAttribute a un representador personalizado que se deriva de la clase
ShellRenderer . Se crean clases de representador de Shell en subclase adicionales mediante la clase ShellRenderer en
subclase.
Vínculos relacionados
Representadores personalizados de Xamarin.Forms
Plantillas de control de Xamarin.Forms
11/07/2019 • 2 minutes to read • Edit Online
Las plantillas de control proporcionan una separación clara entre el aspecto de una página y su contenido, lo que
permite crear páginas a las que se les puede aplicar temas fácilmente.
Introducción
Las plantillas de control de Xamarin.Forms permiten crear y cambiar fácilmente el tema de las páginas de la
aplicación en tiempo de ejecución. En este artículo se proporciona una introducción a las plantillas de control.
Las plantillas de control de Xamarin.Forms permiten crear y cambiar fácilmente el tema de las páginas de la
aplicación en tiempo de ejecución. En este artículo se proporciona una introducción a las plantillas de control.
Los controles tienen propiedades diferentes, como BackgroundColor y TextColor , que pueden definir los aspectos
de la apariencia del control. Estas propiedades se pueden establecer mediante estilos, que se pueden cambiar en
tiempo de ejecución para implementar la creación de temas básicos. Pero los estilos no mantienen una separación
clara entre la apariencia de una página y su contenido, y los cambios que se pueden realizar mediante el
establecimiento de estas propiedades son limitados.
Las plantillas de control proporcionan una separación clara entre el aspecto de una página y su contenido, lo que
permite crear páginas a las que se les puede aplicar temas fácilmente. Por ejemplo, una aplicación puede contener
plantillas de control de nivel de aplicación que proporcionan un tema oscuro y un tema claro. Se pueden crear
temas de todos los elementos ContentPage de la aplicación si se aplica una de las plantillas de control sin cambiar
el contenido mostrado por cada página. Además, los temas que proporcionan las plantillas de control no están
limitados al cambio de las propiedades de los controles. También pueden cambiar los controles que se usan para
implementar el tema.
Cuando se crea un elemento ControlTemplate y se asigna a estos tipos, cualquier apariencia existente se reemplaza
con la que se define en el elemento ControlTemplate . Además de establecer la apariencia con la propiedad
ControlTemplate , también se pueden aplicar plantillas de control mediante estilos para ampliar más las funciones
del tema.
NOTE
¿Qué son los tipos TemplatedPage y TemplatedView ? TemplatedPage es la clase base para ContentPage y es el tipo de
página más básico proporcionado por Xamarin.Forms. A diferencia de ContentPage , TemplatedPage no tiene una
propiedad Content . Por tanto, no se puede agregar contenido directamente a una instancia de TemplatedPage . En su
lugar, el contenido se agrega mediante el establecimiento de la plantilla de control para la instancia de TemplatedPage . De
forma similar, TemplatedView es la clase base para ContentView . A diferencia de ContentView , TemplatedView no tiene
una propiedad Content . Por tanto, no se puede agregar contenido directamente a una instancia de TemplatedView . En su
lugar, el contenido se agrega mediante el establecimiento de la plantilla de control para la instancia de TemplatedView .
Vínculos relacionados
Estilos
ControlTemplate
ContentPresenter
Creación de una clase ControlTemplate
11/07/2019 • 9 minutes to read • Edit Online
Descargar el ejemplo
Las plantillas de control se pueden definir en el nivel de aplicación o en el de página. En este artículo se explica
cómo crear y consumir plantillas de control.
<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 instancia de ControlTemplate se crea como un objeto reutilizable en un elemento ResourceDictionary . Esto se
consigue mediante la asignación de un atributo x:Key único a cada declaración, para proporcionarle una clave
descriptiva en el objeto ResourceDictionary .
En el ejemplo de código siguiente se muestra el código subyacente de App asociado:
public partial class App : Application
{
public App ()
{
InitializeComponent ();
MainPage = new HomePage ();
}
}
Además de establecer la propiedad MainPage , el código subyacente también debe llamar al método
InitializeComponent para cargar y analizar el código XAML asociado.
En el ejemplo de código siguiente se muestra un elemento ContentPage que aplica TealTemplate a 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>
NOTE
En un elemento ContentPage , se puede asignar la propiedad Content y también se puede establecer la propiedad
ControlTemplate . En ese caso, si ControlTemplate contiene una instancia de ContentPresenter , el contenido asignado
a la propiedad Content se presentará por medio del elemento ContentPresenter de ControlTemplate .
<Style TargetType="ContentView">
<Setter Property="ControlTemplate" Value="{StaticResource TealTemplate}" />
</Style>
Como la instancia de Style es implícita, se aplicará a todas las instancias de ContentView de la aplicación. Por
tanto, ya no es necesario establecer la propiedad ContentView.ControlTemplate , como se muestra en el ejemplo de
código siguiente:
<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>
La clase AquaTemplate es idéntica a la clase TealTemplate , salvo que se usan otros colores para las propiedades
BoxView.Color y Label.TextColor .
En el ejemplo de código siguiente se muestra un elemento ContentPage que aplica TealTemplate a 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;
}
}
Las instancias de ControlTemplate se crean mediante la especificación del tipo de las clases que definen las
plantillas de control, en el constructor ControlTemplate .
La propiedad ContentView.Content se establece en un elemento StackLayout que define el contenido que se
mostrará en ContentPage . Este contenido se mostrará mediante el elemento ContentPresenter incluido en
TealTemplate . El mismo mecanismo descrito anteriormente se usa para cambiar el tema en tiempo de ejecución
para el objeto AquaTheme .
IMPORTANT
Se debe llamar al método GetTemplateChild solo una vez que se ha llamado al método OnApplyTemplate .
<controls:MyCustomControl ...>
<controls:MyCustomControl.ControlTemplate>
<ControlTemplate>
<Label x:Name="myLabel" />
</ControlTemplate>
<controls:MyCustomControl.ControlTemplate>
</controls:MyCustomControl>
Se le asigna un nombre al elemento Label y, por lo tanto, se puede recuperar en el código subyacente del control
personalizado. Para lograrlo, se llama al método GetTemplateChild desde la invalidación OnApplyTemplate del
control personalizado:
En este ejemplo, se recupera el objeto Label con nombre myLabel . Luego, la clase MyCustomControl puede
acceder a myLabel y manipularlo.
Vínculos relacionados
Estilos
Tema sencillo (ejemplo)
ControlTemplate
ContentPresenter
ContentView
ResourceDictionary
Enlace de una clase ControlTemplate de
Xamarin.Forms
11/07/2019 • 9 minutes to read • Edit Online
Descargar el ejemplo
Los enlaces a plantilla permiten a los controles en una plantilla de control enlazar datos a propiedades públicas, lo
que permite que los valores de propiedad en los controles de la plantilla de control se puedan cambiar fácilmente.
En este artículo se muestra cómo usar enlaces a plantilla para realizar el enlace de datos desde una plantilla de
control.
TemplateBinding se usa para enlazar la propiedad de un control en una plantilla de control a una propiedad
enlazable en el elemento primario de la vista de destino propietaria de la plantilla de control. Por ejemplo, en lugar
de definir el texto mostrado por las instancias de Label dentro de ControlTemplate , se podría usar un enlace a
plantilla para enlazar la propiedad Label.Text a propiedades enlazables que definen el texto que se va a mostrar.
Un elemento TemplateBinding es similar a un elemento Binding existente, salvo que el origen de
TemplateBinding siempre se establece de forma automática en el elemento primario de la vista de destino
propietaria de la plantilla de control. Pero tenga en cuenta que no se admite el uso de TemplateBinding fuera de
ControlTemplate .
<ControlTemplate x:Key="TealTemplate">
<Grid>
...
<Label Text="{TemplateBinding Parent.HeaderText}" ... />
...
<Label Text="{TemplateBinding Parent.FooterText}" ... />
</Grid>
</ControlTemplate>
En lugar de establecer las propiedades Label.Text en texto estático, las propiedades pueden usar enlaces a
plantilla para enlazar a propiedades enlazables del elemento primario de la vista de destino propietaria del
elemento ControlTemplate . Pero tenga en cuenta que los enlaces a plantilla se enlazan a Parent.HeaderText y
Parent.FooterText , en lugar de a HeaderText y FooterText . En este ejemplo, esto se debe a que las propiedades
enlazables se definen en el elemento primario principal de la vista de destino, en lugar del elemento primario,
como se muestra en el ejemplo de código siguiente:
<ContentPage ...>
<ContentView ... ControlTemplate="{StaticResource TealTemplate}">
...
</ContentView>
</ContentPage>
El origen del enlace a plantilla siempre se establece de forma automática en el elemento primario de la vista de
destino propietaria de la plantilla de control, que aquí es la instancia de ContentView . El enlace a plantilla usa la
propiedad Parent para devolver el elemento primario de la instancia de ContentView , que es la instancia de
ContentPage . Por tanto, al usar TemplateBinding en el elemento ControlTemplate para enlazar a
Parent.HeaderText y Parent.FooterText se buscan las propiedades enlazables definidas en ContentPage , como se
muestra en el ejemplo de código siguiente:
Creación de TemplateBinding en C#
En C#, un elemento TemplateBinding se crea mediante el constructor de TemplateBinding , como se muestra en el
ejemplo de código siguiente:
En lugar de establecer las propiedades Label.Text en texto estático, las propiedades pueden usar enlaces a
plantilla para enlazar a propiedades enlazables del elemento primario de la vista de destino propietaria del
elemento ControlTemplate . El enlace a plantilla se crea con el método SetBinding , y se especifica una instancia de
TemplateBinding como segundo parámetro. Tenga en cuenta que los enlaces a plantilla enlazan a
Parent.HeaderText y Parent.FooterText , porque las propiedades enlazables se definen en el elemento primario
principal de la vista de destino, en lugar del elemento primario, como se muestra en el ejemplo de código
siguiente:
Las propiedades de modelo de vista HeaderText y FooterText se pueden enlazar a lo siguiente, como se muestra
en este ejemplo de código XAML:
<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>
También puede enlazar a las propiedades del modelo de vista directamente, para que no sea necesario declarar
elementos BindableProperty para HeaderText y FooterText en el elemento ContentPage , si se enlaza la plantilla
de control a Parent.BindingContext.NombreDePropiedad, por ejemplo:
<ControlTemplate x:Key="TealTemplate">
<Grid>
...
<Label Text="{TemplateBinding Parent.BindingContext.HeaderText}" ... />
...
<Label Text="{TemplateBinding Parent.BindingContext.FooterText}" ... />
</Grid>
</ControlTemplate>
Para obtener más información sobre el enlace de datos a modelos de vista, vea Enlaces de datos a MVVM.
Resumen
En este artículo se ha mostrado cómo usar enlaces a plantilla para realizar el enlace de datos desde una plantilla
de control. Los enlaces a plantilla permiten a los controles en una plantilla de control enlazar datos a propiedades
públicas, lo que permite que los valores de propiedad en los controles de la plantilla de control se puedan cambiar
fácilmente.
Vínculos relacionados
Conceptos básicos del enlace de datos
Enlaces de datos a MVVM
Tema sencillo con enlace a plantilla (ejemplo)
Tema sencillo con enlace a plantilla y modelo de vista (ejemplo)
TemplateBinding
ControlTemplate
ContentView
Plantillas de datos de Xamarin.Forms
11/07/2019 • 2 minutes to read • Edit Online
Descargar el ejemplo
Las plantillas de datos se usan para especificar el aspecto de los datos en los controles admitidos y normalmente
se enlaza a los datos que se van a mostrar.
Introducción
Las plantillas de datos de Xamarin.Forms permiten definir la presentación de los datos en los controles
admitidos. En este artículo se ofrece una introducción a las plantillas de datos y se analiza por qué son
necesarias.
Crear un DataTemplateSelector
Un DataTemplateSelector se puede usar para elegir DataTemplate en tiempo de ejecución según el valor de una
propiedad enlazada a datos. Esto permite aplicar varias instancias de DataTemplate al mismo tipo de objeto para
personalizar la apariencia de objetos concretos. En este artículo se explica cómo crear y consumir un
DataTemplateSelector .
Vínculos relacionados
Plantillas de datos (ejemplo)
Introducción a las plantillas de Xamarin.Forms
11/07/2019 • 7 minutes to read • Edit Online
Descargar el ejemplo
Las plantillas de datos de Xamarin.Forms permiten definir la presentación de los datos en los controles admitidos.
En este artículo se ofrece una introducción a las plantillas de datos y se analiza por qué son necesarias.
Considere la posibilidad de un elemento ListView que muestra una colección de objetos Person . En el ejemplo
de código siguiente se muestra la definición de la clase Person :
La clase Person define las propiedades Name , Age y Location , que se pueden establecer al crear un objeto
Person . El objeto ListView se usa para mostrar la colección de objetos Person , como se muestra en el ejemplo
de código XAML siguiente:
<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>
NOTE
Tenga en cuenta que el elemento x:Array requiere un atributo Type que indica el tipo de los elementos de la matriz.
ListView llama a ToString cuando se muestran los objetos de la colección. Como no hay ninguna invalidación de
Person.ToString , ToString devuelve el nombre de tipo de cada objeto, como se muestra en las capturas de
pantalla siguientes:
El objeto Person puede invalidar el método ToString para mostrar datos significativos, como se muestra en el
ejemplo de código siguiente:
Como resultado, ListView muestra el valor de propiedad Person.Name para cada objeto de la colección, como se
muestra en las capturas de pantalla siguientes:
La invalidación de Person.ToString podría devolver una cadena con formato formada por las propiedades Name ,
Age y Location . Pero este enfoque solo ofrece un control limitado sobre la apariencia de cada elemento de datos.
Para obtener más flexibilidad, se puede crear un elemento DataTemplate que defina la apariencia de los datos.
NOTE
Tenga en cuenta que aunque TableView usa objetos Cell , no usa un elemento DataTemplate . Esto se debe a que los
enlaces de datos siempre se establecen directamente en objetos Cell .
Una instancia de DataTemplate que se coloca como un elemento secundario directo de las propiedades
enumeradas anteriormente se conoce como una plantilla insertada. Como alternativa, se puede definir un
elemento DataTemplate como un recurso de nivel de control, de página o de aplicación. La elección de dónde se
puede definir una instancia de DataTemplate afecta a dónde se puede usar:
Una instancia de DataTemplate definida en el nivel de control solo se puede aplicar al control.
Un instancia de DataTemplate definida en el nivel de página se puede aplicar a varios controles válidos de la
página.
Una instancia de DataTemplate definida en el nivel de aplicación se puede aplicar a los controles válidos de toda
la aplicación.
Las plantillas de datos situadas más abajo en la jerarquía de vistas tienen prioridad sobre las definidas más arriba
cuando comparten atributos x:Key . Por ejemplo, una plantilla de datos de nivel de aplicación se reemplazará por
una plantilla de datos de nivel de página, y una plantilla de datos de nivel de página se reemplazará por una
plantilla de datos de nivel de control, o bien una plantilla de datos insertada.
Vínculos relacionados
Apariencia de etiqueta
Plantillas de datos (ejemplo)
DataTemplate
Creación de una plantilla de datos de Xamarin.Forms
11/07/2019 • 9 minutes to read • Edit Online
Descargar el ejemplo
Las plantillas de datos se pueden crear insertadas, en un objeto ResourceDictionary, o bien a partir de un tipo
personalizado o un tipo de celda de Xamarin.Forms adecuado. En este artículo se explora cada una de las técnicas.
Un escenario de uso común para un elemento DataTemplate es mostrar datos de una colección de objetos en un
control ListView . La apariencia de los datos de cada celda del control ListView se puede administrar mediante el
establecimiento de la propiedad ListView.ItemTemplate en un elemento DataTemplate . Se pueden usar varias
técnicas para realizar esta acción:
Creación de una plantilla de datos insertada.
Creación de una plantilla de datos con un tipo.
Creación de una plantilla de datos como un recurso.
Independientemente de la técnica que se use, el resultado es que la apariencia de cada celda del control ListView
se define mediante un elemento DataTemplate , como se muestra en las capturas de pantalla siguientes:
El elemento secundario de un elemento DataTemplate insertado debe ser de tipo Cell , o bien derivarse de él. En
este ejemplo se usa un ViewCell , que procede de Cell . Aquí, el diseño dentro de ViewCell se administra
mediante un control Grid . Grid contiene tres instancias de Label que enlazan sus propiedades Text a las
propiedades adecuadas de cada objeto Person de la colección.
El código de C# equivalente se muestra en el ejemplo de código siguiente:
public class WithDataTemplatePageCS : ContentPage
{
public WithDataTemplatePageCS()
{
...
var people = new List<Person>
{
new Person { Name = "Steve", Age = 21, Location = "USA" },
...
};
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);
En C#, el elemento DataTemplate insertado se crea mediante una sobrecarga del constructor que especifica un
argumento Func .
<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 de ViewCell , el diseño se administra mediante un control Grid . Grid contiene tres instancias de Label
que enlazan sus propiedades Text a las propiedades adecuadas de cada objeto Person de la colección.
El código de C# equivalente se muestra en el ejemplo siguiente:
public class WithDataTemplatePageFromTypeCS : ContentPage
{
public WithDataTemplatePageFromTypeCS()
{
...
var people = new List<Person>
{
new Person { Name = "Steve", Age = 21, Location = "USA" },
...
};
En C#, DataTemplate se crea mediante una sobrecarga del constructor que especifica el tipo de celda como
argumento. El tipo de celda se debe derivar del tipo ViewCell , como se muestra en el ejemplo de código siguiente:
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
Tenga en cuenta que Xamarin.Forms también incluye tipos de celda que se pueden usar para mostrar datos simples en
celdas ListView . Para obtener más información, vea Apariencia de una celda.
El elemento DataTemplate se agrega a ResourceDictionary con el método Add , que especifica una cadena Key
que se usa para hacer referencia al elemento DataTemplate al recuperarlo.
Resumen
En este artículo se ha explicado cómo crear plantillas de datos, insertadas, a partir de un tipo personalizado, o bien
en un objeto ResourceDictionary . Una plantilla insertada se debe usar si no es necesario volver a utilizarla en otro
lugar. Como alternativa, se puede reutilizar una plantilla de datos si se define como un tipo personalizado, o bien
como un recurso de nivel de página, nivel de aplicación o de nivel de control.
Vínculos relacionados
Apariencia de etiqueta
Plantillas de datos (ejemplo)
DataTemplate
Creación de un elemento DataTemplateSelector de
Xamarin.Forms
11/07/2019 • 7 minutes to read • Edit Online
Descargar el ejemplo
Un elemento DataTemplateSelector se puede usar para elegir una plantilla de datos en tiempo de ejecución
según el valor de una propiedad enlazada a datos. Esto permite aplicar varias instancias de DataTemplate al
mismo tipo de objeto, para personalizar la apariencia de objetos concretos. En este artículo se explica cómo crear
y consumir una instancia de DataTemplateSelector.
Un selector de plantillas de datos habilita escenarios como el enlace de ListView a una colección de objetos,
donde la apariencia de cada objeto de ListView se puede elegir en tiempo de ejecución mediante el selector de
plantillas de datos devolviendo un elemento DataTemplate determinado.
Creación de DataTemplateSelector
Un selector de plantillas de datos se implementa mediante la creación de una clase que hereda de
DataTemplateSelector . Después, se reemplaza el método OnSelectTemplate para devolver un elemento
DataTemplate , como se muestra en el ejemplo de código siguiente:
El método OnSelectTemplate devuelve la plantilla adecuada en función del valor de la propiedad DateOfBirth . La
plantilla que se devuelve es el valor de las propiedades ValidTemplate o InvalidTemplate , que se establecen
cuando se consume PersonDataTemplateSelector .
Después, se puede asignar una instancia de la clase de selector de plantilla de datos a propiedades de control de
Xamarin.Forms como ListView.ItemTemplate . Para obtener una lista de las propiedades válidas, vea Creación de
una plantilla de datos.
Limitaciones
Las instancias de DataTemplateSelector tienen las limitaciones siguientes:
La subclase DataTemplateSelector siempre debe devolver la misma plantilla para los mismos datos si se
consultan varias veces.
La subclase DataTemplateSelector no debe devolver otra subclase DataTemplateSelector .
La subclase DataTemplateSelector no debe devolver nuevas instancias de DataTemplate en cada llamada. En
su lugar, se debe devolver la misma instancia. De lo contrario, se creará una fuga de memoria y se
deshabilitará la virtualización.
En Android, no puede haber más de 20 plantillas de datos diferentes por ListView .
Consumo de una instancia de DataTemplateSelector en XAML
En XAML, se pueden crear instancias de PersonDataTemplateSelector si se declara como un recurso, como se
muestra en el ejemplo de código siguiente:
<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>
Este objeto ResourceDictionary de nivel de página define dos instancias de DataTemplate y una instancia de
PersonDataTemplateSelector . La instancia de PersonDataTemplateSelector establece sus propiedades
ValidTemplate y InvalidTemplate en las instancias de DataTemplate correspondientes mediante la extensión de
marcado StaticResource . Tenga en cuenta que aunque los recursos se definen en el objeto ResourceDictionary
de la página, también se pueden definir en el nivel de control o aplicación.
La instancia de PersonDataTemplateSelector se consume asignándola a la propiedad ListView.ItemTemplate ,
como se muestra en el ejemplo de código siguiente:
public HomePageCS ()
{
...
SetupDataTemplates ();
var listView = new ListView {
ItemsSource = people,
ItemTemplate = new PersonDataTemplateSelector {
ValidTemplate = validTemplate,
InvalidTemplate = invalidTemplate }
};
Vínculos relacionados
Selector de plantillas de datos (ejemplo)
DataTemplateSelector
Desencadenadores de Xamarin.Forms
11/07/2019 • 12 minutes to read • Edit Online
Descargar el ejemplo
Los desencadenadores permiten expresar acciones de forma declarativa en XAML que cambian la apariencia de
controles en función de eventos o cambios en propiedades.
Puede asignar un desencadenador directamente a un control o agregarlo a un diccionario de recursos de nivel de
aplicación o página que se vaya a aplicar a varios controles.
Hay cuatro tipos de desencadenadores:
Desencadenador de propiedades: se produce cuando una propiedad en un control se establece en un valor
determinado.
Desencadenador de datos: usa enlaces de datos para desencadenar basándose en las propiedades de otro
control.
Desencadenador de eventos: se produce cuando tiene lugar un evento en el control.
Multi-desencadenador: permite establecer varias condiciones de desencadenador antes de que se
produzca una acción.
Desencadenadores de propiedad
Un desencadenador simple se puede expresar puramente en XAML, mediante la incorporación de un elemento
Trigger a la colección de desencadenadores de un control. En este ejemplo se muestra un desencadenador que
cambia un color de fondo Entry cuando recibe el foco:
<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>
Desencadenadores de datos
Los desencadenadores de datos usan enlaces de datos para supervisar otro control a fin de que se llame a los
elementos Setter . En lugar del atributo Property de un desencadenador de propiedad, establezca el atributo
Binding para supervisar el valor especificado.
El ejemplo siguiente usa la sintaxis de enlace de datos {Binding Source={x:Reference entry}, Path=Text.Length} ,
que es como se hace referencia a las propiedades de otro control. Cuando la longitud de entry es cero, el
desencadenador se activa. En este ejemplo el desencadenador deshabilita el botón cuando la entrada está vacía.
Desencadenadores de eventos
El elemento EventTrigger solo requiere una propiedad Event , como "Clicked" , en el ejemplo siguiente.
<EventTrigger Event="Clicked">
<local:NumericValidationTriggerAction />
</EventTrigger>
Tenga en cuenta que no hay elementos Setter , sino una referencia a una clase definida por
local:NumericValidationTriggerAction que requiere que se declare xmlns:local en el código XAML de la 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"
La propia clase implementa TriggerAction , lo que significa que debe proporcionar una invalidación para el
método Invoke al que se llama cada vez que se produce el evento desencadenador.
Una implementación de acción de desencadenador debe:
Implementar la clase genérica TriggerAction<T> , con el parámetro genérico correspondiente al tipo de
control al que se va a aplicar el desencadenador. Puede usar superclases como VisualElement para escribir
acciones de desencadenador que funcionen con una serie de controles, o especificar un tipo de control
como Entry .
Invalidar el método Invoke : se llama a este método cada vez que se cumplen los criterios del
desencadenador.
Opcionalmente, exponer propiedades que se pueden establecer en el código XAML cuando se declara el
desencadenador (como Anchor , Scale y Length en este ejemplo).
Las propiedades expuestas por la acción de desencadenador se pueden establecer en la declaración de XAML de
este modo:
<EventTrigger Event="TextChanged">
<local:NumericValidationTriggerAction />
</EventTrigger>
Tenga cuidado al compartir desencadenadores en una instancia de ResourceDictionary , ya que una instancia se
comparte entre controles, con lo que cualquier estado que se configure una vez se va a aplicar a todos ellos.
Tenga en cuenta que los desencadenadores de eventos no admiten los elementos EnterActions y ExitActions
descritos abajo.
Multi-desencadenadores
Un elemento MultiTrigger se parece Trigger o DataTrigger , salvo que en él puede haber más de una
condición. Todas las condiciones deben cumplirse para que se desencadenen los elementos Setter .
Este es el ejemplo de un desencadenador de un botón que se enlaza a dos entradas diferentes ( email y 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>
<ResourceDictionary>
<local:MultiTriggerConverter x:Key="dataHasBeenEntered" />
</ResourceDictionary>
A continuación se muestra el código XAML. Observe las siguientes diferencias con respecto al primer ejemplo de
multi-desencadenador:
El botón tiene IsEnabled="false" establecido de forma predeterminada.
Las condiciones del multi-desencadenador usan el convertidor para convertir el valor Text.Length en un
.
boolean
Cuando todas las condiciones son true , el establecedor convierte en true la propiedad IsEnabled del
botón.
Estas capturas de pantalla muestran la diferencia entre los dos ejemplos de multi-desencadenadores anteriores.
En la parte superior de las pantallas, la entrada de texto con un solo elemento Entry basta para habilitar el botón
Guardar. En la parte inferior de las pantallas, el botón Iniciar sesión permanece inactivo hasta que ambos
campos contienen datos.
EnterActions y ExitActions
Otra forma de implementar cambios cuando se produce un desencadenador es mediante la incorporación de
colecciones EnterActions y ExitActions y la especificación de implementaciones TriggerAction<T> .
Puede proporcionar tanto EnterActions como ExitActions , así como Setter en un desencadenador, pero tenga
en cuenta que se llama a los elementos Setter de inmediato (no se espera a que se completen EnterAction o
ExitAction ). También puede hacer todo en el código y no usar elementos Setter en absoluto.
<Trigger.ExitActions>
<local:FadeTriggerAction StartsFrom="1" />
</Trigger.ExitActions>
<!-- You can use both Enter/Exit and Setter together if required -->
</Trigger>
</Entry.Triggers>
</Entry>
Como siempre, cuando se hace referencia a una clase en XAML, se debe declarar un espacio de nombres como
xmlns:local , como se muestra aquí:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:WorkingWithTriggers;assembly=WorkingWithTriggers"
}),
length:1000, // milliseconds
easing: Easing.Linear);
}
}
Vínculos relacionados
Ejemplo de desencadenadores
Documentación de la API de Xamarin.Forms
Vistas de interfaz de usuario de Xamarin.Forms
12/07/2019 • 8 minutes to read • Edit Online
descargar el ejemplo
Cómo usar las vistas de Xamarin.Forms
ActivityIndicator
El ActivityIndicator es un control animado que se indica a los usuarios que la aplicación esté implicada en una
actividad larga, sin dar ninguna indicación del progreso.
Animación
Xamarin.Forms incluye su propia infraestructura de animación es sencillo para crear animaciones sencillas, pero
también lo suficientemente versátil para crear animaciones complejas.
BoxView
El BoxView es un simple rectángulo de color, pero puede utilizarse para elementos decorativos, gráficos
rudimentarias y para obtener la entrada táctil iterativo.
Button
El Button responde a un pulse o haga clic en que se dirige a una aplicación para llevar a cabo una tarea
determinada.
CheckBox
El CheckBox es un tipo de botón que puede ser activado ni estar vacío. Cuando se activa una casilla de verificación,
se considera en. Cuando una casilla de verificación está vacía, se considera estar apagado.
CollectionView
El CollectionView es una vista flexible y eficaz para presentar las listas de datos con las especificaciones de diseño
diferente.
Colores
Definición y uso de colores en las plataformas pueden ser complicados cuando cada plataforma tiene su propio
estándares y los valores predeterminados.
DataPages
DataSourceControl proporciona una API para enlazar de forma rápida y sencilla un origen de datos a vistas
precompiladas. Elementos de lista y páginas de detalle representarán los datos de forma automática y
personalizadas utilizando temas.
DatePicker
El DatePicker permite al usuario seleccionar una fecha dentro de un intervalo especificado. Se implementa
mediante el selector de fecha admitido por la plataforma concreta donde se ejecuta la aplicación.
Imágenes
Las imágenes se pueden compartir entre plataformas con Xamarin.Forms, se pueden cargar específicamente para
cada plataforma, o se pueden descargar para su presentación.
ImageButton
La ImageButton muestra una imagen y responde a un pulse o haga clic en que se dirige a una aplicación para llevar
a cabo una tarea determinada.
Diseños
Xamarin.Forms tiene varios diseños para organizar contenidos en pantalla. StackLayout , Grid , FlexLayout ,
AbsoluteLayout , ScrollView , y RelativeLayout pueden ser utilizadas para crear interfaces de usuario atractivas y
con capacidad de respuesta.
ListView
Xamarin.Forms proporciona un control de vista de lista para mostrar las filas de desplazamiento de datos. El
control incluye acciones contextuales, ajuste de tamaño automático de HasUnevenRows , personalización de
separador, Deslizar para actualizar y encabezados y pies de página.
Mapas
Agregar mapas requiere una descarga del paquete NuGet adicional y alguna configuración específica de la
plataforma. Mapas y marcadores de pin pueden agregarse en unas pocas líneas de código una vez que se realiza la
configuración.
Selector
El Picker vista es un control para seleccionar un elemento de texto en una lista de datos.
Barra de progreso
El ProgressBar es un control que se representa visualmente el progreso como una barra horizontal que se rellena
en función de una propiedad de tipo float.
Slider
El Slider permite al usuario seleccionar un valor numérico de un intervalo continuo.
Control de incremento
El Stepper permite al usuario seleccionar un valor numérico de un intervalo de valores. Consta de dos botones
etiquetados con menos y signos más. Manipulación de los dos botones cambia el valor seleccionado de forma
incremental.
Estilos
Fuente, color y otros atributos se pueden agrupar en estilos que se pueden compartir entre los controles, diseños o
toda la aplicación mediante objetos ResourceDictionary.
Switch
El Switch es un tipo de botón que se puede alternar entre activar y desactivar los Estados.
TableView
La vista de tabla es similar a una vista de lista, pero en lugar de que se está diseñando para las listas largas de datos
está pensado para las pantallas de estilo de entrada de datos de desplazamiento de los controles o los menús
desplegables simple.
Texto
Xamarin.Forms tiene varias vistas para presentar y recibir el texto. Las vistas de texto pueden formatearlos y
personalizadas para las plataformas. Configuración de la fuente específica puede habilitar la compatibilidad con
características de accesibilidad.
Temas
Los temas de Xamarin.Forms definen una apariencia visual específica para los controles estándar. Una vez que
agregue un tema para el diccionario de recursos de la aplicación, cambiará la apariencia de los controles estándar.
TimePicker
El TimePicker permite al usuario seleccionar una hora. Se implementa mediante el selector de hora compatible
con la plataforma concreta donde se ejecuta la aplicación.
Visual
Xamarin.Forms Material Visual puede utilizarse para crear aplicaciones de Xamarin.Forms que tienen un aspecto
idénticos o idéntica en gran medida en iOS y Android.
WebView
Xamarin.Forms usa el control del explorador web nativos en cada plataforma y puede mostrar cadenas Html
generadas, los sitios Web y los recursos locales.
Vínculos relacionados
Galería de Xamarin.Forms (ejemplo)
Xamarin.Forms ActivityIndicator
12/07/2019 • 2 minutes to read • Edit Online
Descargar el ejemplo
Xamarin.Forms ActivityIndicator es un control que muestra una animación para mostrar que la aplicación esté
implicada en una actividad larga. A diferencia de la ProgressBar , el ActivityIndicator no proporciona ninguna
indicación de progreso. El ActivityIndicator hereda View .
La siguiente captura de pantalla muestra un ActivityIndicator control en iOS y Android:
Estas propiedades están respaldadas por BindableProperty objetos, lo que significa que el ActivityIndicator
puede cambiar el estilo y ser el destino de los enlaces de datos.
Crear un ActivityIndicator
Un ActivityIndicator se pueden crear instancias en XAML. Su IsRunning se puede establecer la propiedad para
determinar si el control está visible y animación. Si el IsRunning propiedad no está establecida, el valor
predeterminado es false y ActivityIndicator no será visible. El ejemplo siguiente muestra cómo crear una
instancia de un ActivityIndicator en XAML con el elemento opcional IsRunning conjunto de propiedades:
Vínculos relacionados
Demostraciones de ActivityIndicator
Barra de progreso
Animación de Xamarin.Forms
11/07/2019 • 2 minutes to read • Edit Online
Xamarin.Forms incluye su propia infraestructura de animación es sencillo para crear animaciones sencillas, pero
también lo suficientemente versátil para crear animaciones complejas.
Las clases de animación de Xamarin.Forms tienen como objetivo diferentes propiedades de elementos visuales.
Una animación típica que cambia de forma progresiva una propiedad de un valor a otro durante un período de
tiempo. Tenga en cuenta que no hay ninguna interfaz XAML para las clases de animación de Xamarin.Forms. Sin
embargo, estas se pueden encapsular en comportamientos y se puede hacer referencia a ellas posteriormente
desde XAML.
Animaciones simples
La clase ViewExtensions proporciona métodos de extensión que pueden usarse para construir animaciones simples
que giran, escalan, traducen y desvanecen instancias VisualElement . En este artículo se muestra cómo crear y
cancelar animaciones mediante la clase ViewExtensions .
Funciones de aceleración
Xamarin.Forms incluye la clase Easing , que permite especificar una función de transferencia que controla cómo se
aceleran o ralentizan las animaciones durante su ejecución. En este artículo se muestra cómo usar las funciones de
aceleración predefinidas y cómo crear funciones de aceleración personalizadas.
Animaciones personalizadas
La clase Animation es el bloque de creación de todas las animaciones de Xamarin.Forms. Con los métodos de
extensión de la clase ViewExtensions se pueden crar uno o varios objetos Animation . En este artículo se muestra
cómo usar la clase Animation para crear y cancelar animaciones, sincronizar varias animaciones y crear
animaciones personalizadas que animan propiedades que no están animadas mediante métodos existentes de
animación.
Animaciones sencillas en Xamarin.Forms
11/07/2019 • 19 minutes to read • Edit Online
descargar el ejemplo
La clase ViewExtensions proporciona métodos de extensión que se pueden usar para construir las animaciones
sencillas. En este artículo muestra cómo crear y cancelar las animaciones mediante la clase ViewExtensions.
El ViewExtensions clase proporciona los siguientes métodos de extensión que pueden usarse para crear
animaciones sencillas:
TranslateTo anima el TranslationX y TranslationY las propiedades de un VisualElement .
ScaleTo anima el Scale propiedad de un VisualElement .
RelScaleTo se aplica un aumento incremental animado o disminución en el Scale propiedad de un
VisualElement .
RotateTo anima el Rotation propiedad de un VisualElement .
RelRotateTo se aplica un aumento incremental animado o disminución en el Rotation propiedad de un
VisualElement .
RotateXTo anima el RotationX propiedad de un VisualElement .
RotateYTo anima el RotationY propiedad de un VisualElement .
FadeTo anima el Opacity propiedad de un VisualElement .
De forma predeterminada, cada animación tardará 250 milisegundos. Sin embargo, se puede especificar una
duración de cada animación al crear la animación.
El ViewExtensions clase también incluye un CancelAnimations método que puede usarse para cancelar las
animaciones.
NOTE
El ViewExtensions clase proporciona un LayoutTo método de extensión. Sin embargo, este método está pensado para
usarse diseños para animar las transiciones entre Estados de diseño que contienen el tamaño y posición de los cambios. Por
lo tanto, que debe usarse únicamente por Layout subclases.
Los métodos de extensión de la animación de la clase ViewExtensions son asincrónicos y devuelven un objeto
Task<bool> . El valor devuelto es false si se completa la animación y true si esta se cancela. Por lo tanto, los
métodos de animación normalmente deben usarse con el operador await , lo que permite determinar fácilmente
cuándo se ha completado una animación. Además, después se pueden crear animaciones secuenciales con
métodos de animación posteriores que se ejecutan después de que se haya completado el método anterior. Para
obtener más información, consulte Animaciones compuestas.
Si hay un requisito para permitir que una animación completa en segundo plano, el await se puede omitir el
operador. En este escenario, los métodos de extensión de la animación se devolverá rápidamente después de
iniciar la animación, con la animación que se producen en segundo plano. Esta operación puede aprovecharse al
crear animaciones compuestas. Para obtener más información, consulte animaciones compuesto.
Para obtener más información sobre la await operador, consulte información general de soporte técnico de
Async.
Animaciones únicas
Cada método de extensión en el ViewExtensions implementa una operación de animación única que
progresivamente cambia una propiedad de un valor a otro valor durante un período de tiempo. Esta sección
explora cada operación de animación.
Giro
En el ejemplo de código siguiente se muestra cómo utilizar el RotateTo método se va a animar el Rotation
propiedad de un Image :
Este código se anima la Image instancia girando hasta 360 grados superior a 2 segundos (2.000 milisegundos). El
RotateTo método obtiene la actual Rotation propiedad valor para el inicio de la animación y, a continuación, se
gira desde ese valor a su primer argumento (360). Una vez que la animación se complete, la imagen Rotation
propiedad se restablece a 0. Esto garantiza que el Rotation propiedad no se queda en 360 después de que
concluya la animación, que podrían impedir que las rotaciones adicionales.
Las capturas de pantalla siguientes muestran la rotación en curso en cada plataforma:
Giro relativa
En el ejemplo de código siguiente se muestra cómo utilizar el RelRotateTo método para aumentar o disminuir de
forma incremental el Rotation propiedad de un Image :
Cambiar escala
En el ejemplo de código siguiente se muestra cómo utilizar el ScaleTo método se va a animar el Scale propiedad
de un Image :
Este código se anima la Image instancia mediante el escalamiento vertical a dos veces su tamaño superior a 2
segundos (2.000 milisegundos). El ScaleTo método obtiene la actual Scale el valor de propiedad (valor
predeterminado de 1) para el inicio de la animación y, a continuación, se escala desde ese valor a su primer
argumento (2). Esto tiene el efecto de aumentar el tamaño de la imagen a dos veces su tamaño.
Las capturas de pantalla siguientes muestran el escalado en curso en cada plataforma:
NOTE
El VisualElement también define la clase ScaleX y ScaleY propiedades, que se pueden escalar el VisualElement
manera diferente en el direcciones horizontal y vertical. Estas propiedades se pueden animar con la Animation clase. Para
obtener más información, consulte animaciones personalizadas en Xamarin.Forms.
Este código se anima la Image instancia mediante el escalamiento vertical a dos veces su tamaño superior a 2
segundos (2.000 milisegundos). El RelScaleTo método obtiene la actual Scale valor de propiedad para el inicio
de la animación y, a continuación, se escala desde ese valor para el valor más su primer argumento (2). Esto
garantiza que cada animación siempre será un escalamiento de 2 desde la posición inicial.
Escalado y la rotación con delimitadores
El AnchorX y AnchorY propiedades establecen el centro de ajuste de escala o rotación para el Rotation y Scale
propiedades. Por lo tanto, sus valores también afectan a la RotateTo y ScaleTo métodos.
Dado un Image que se ha colocado en el centro de un diseño, en el ejemplo de código siguiente se muestra la
rotación de la imagen en torno al centro del diseño estableciendo su AnchorY propiedad:
Conversión
En el ejemplo de código siguiente se muestra cómo utilizar el TranslateTo método se va a animar el
TranslationX y TranslationY las propiedades de un Image :
Este código se anima la Image instancia convirtiendo, vertical y horizontalmente en 1 segundo (1000
milisegundos). El TranslateTo método traduce al mismo tiempo la imagen 100 píxeles a la izquierda y 100 píxeles
hacia arriba. Esto es porque el primer y segundo argumentos son ambos números negativos. Proporcionar los
números positivos traduciría la imagen a la derecha y abajo.
Las capturas de pantalla siguientes muestran la traducción en curso en cada plataforma:
NOTE
Si un elemento se distribuyen inicialmente fuera de la pantalla y, a continuación, se traduce en la pantalla, después de la
traducción, diseño de entrada del elemento permanece fuera de la pantalla y el usuario no puede interactuar con él. Por lo
tanto, se recomienda que una vista debe disponerse en su posición final y, a continuación, los necesarios traducciones
realizadas.
Corrección selectiva
En el ejemplo de código siguiente se muestra cómo utilizar el FadeTo método se va a animar el Opacity
propiedad de un Image :
image.Opacity = 0;
await image.FadeTo (1, 4000);
Este código se anima la Image instancia por desvanezcan en más de 4 segundos (de 4000 milisegundos). El
FadeTo método obtiene la actual Opacity valor de propiedad para el inicio de la animación y, a continuación,
fundidos en desde ese valor a su primer argumento (1).
Las capturas de pantalla siguientes muestran la atenuación en curso en cada plataforma:
Animaciones compuestas
Una animación compuesta es una combinación secuencial de las animaciones y se pueden crear con el await
operador, como se muestra en el ejemplo de código siguiente:
En este ejemplo, el Image se traduce en 6 segundos (6.000 milisegundos). La traducción de la Image utiliza cinco
animaciones con la await operador que indica que cada animación se ejecuta de forma secuencial. Por lo tanto,
los métodos de la animación siguiente ejecutan después de que se ha completado el método anterior.
Animaciones de composición
Una animación compuesta es una combinación de animaciones donde se ejecutan simultáneamente dos o más de
las animaciones. Las animaciones de composición se pueden crear mezclando animaciones esperadas y que no es
"awaited", como se muestra en el ejemplo de código siguiente:
En este ejemplo, el Image es escalar y girar simultáneamente más de 4 segundos (de 4000 milisegundos). El
escalado de la Image utiliza dos animaciones secuenciales que se producen al mismo tiempo como la rotación. El
RotateTo método se ejecuta sin un await operador y se devuelve inmediatamente, con la primera ScaleTo , a
continuación, a partir de animación. El await operador en la primera ScaleTo retrasa la llamada al método el
segundo ScaleTo hasta la primera llamada a un método ScaleTo ha completado la llamada al método. En este
momento la RotateTo animación es la mitad forma completa y el Image estará gira 180 grados. Durante los
últimos 2 segundos (2.000 milisegundos), el segundo ScaleTo animación y RotateTo animación ambos
completar.
Ejecución simultánea de varios métodos asincrónicos
El static Task.WhenAny y Task.WhenAll métodos se utilizan para ejecutar varios métodos asincrónicos
simultáneamente y, por lo tanto, puede usarse para crear animaciones compuestas. Ambos métodos devuelven un
Task de objetos y Aceptar una colección de métodos que cada valor devuelto una Task objeto. El Task.WhenAny
método se completa cuando cualquier método en su colección completa su ejecución, como se muestra en el
ejemplo de código siguiente:
await Task.WhenAny<bool>
(
image.RotateTo (360, 4000),
image.ScaleTo (2, 2000)
);
await image.ScaleTo (1, 2000);
En este ejemplo, el Task.WhenAny llamada de método contiene dos tareas. La primera tarea gira la imagen más de
4 segundos (de 4000 milisegundos) y la segunda tarea escala la imagen superior a 2 segundos (2.000
milisegundos). Cuando se completa la segunda tarea, el Task.WhenAny se completa la llamada al método. Sin
embargo, aunque el RotateTo método todavía se está ejecutando, el segundo ScaleTo método puede comenzar.
El Task.WhenAll método se completa cuando se hayan completado todos los métodos en su colección, como se
muestra en el ejemplo de código siguiente:
// 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)
);
En este ejemplo, el Task.WhenAll llamada de método contiene tres tareas, cada uno de los cuales se ejecuta más
de 10 minutos. Cada Task hace que sea un número diferente de rotaciones de 360 grados: 307 rotaciones para
RotateTo , 251 rotaciones para RotateXTo y 199 rotaciones para RotateYTo . Estos valores son números primos,
por lo tanto, lo que garantiza que las rotaciones no están sincronizadas y, por tanto, no origine patrones
repetitivos.
Las capturas de pantalla siguientes muestran las rotaciones varias en curso en cada plataforma:
Cancelar las animaciones
Una aplicación puede cancelar una o varias animaciones con una llamada a la static
ViewExtensions.CancelAnimations método, como se muestra en el ejemplo de código siguiente:
ViewExtensions.CancelAnimations (image);
Esta operación cancelará inmediatamente todas las animaciones que se están ejecutando en el Image instancia.
Resumen
En este artículo se muestra creando y cancelación de animaciones con la ViewExtensions clase. Esta clase
proporciona métodos de extensión que se pueden usar para construir las animaciones sencillas que giran,
escalarán, traducirán y atenuación VisualElement instancias.
Vínculos relacionados
Información general sobre la compatibilidad con Async
Animación básica (ejemplo)
ViewExtensions
Funciones de aceleración en Xamarin.Forms
11/07/2019 • 7 minutes to read • Edit Online
descargar el ejemplo
Xamarin.Forms incluye una clase de entrada y salida lenta que le permite especificar una función de transferencia
que controla cómo las animaciones aceleran o ralentizar se están ejecutando. En este artículo se muestra cómo
utilizar las funciones de aceleración predefinidas y cómo crear funciones de aceleración.
El Easing clase define una serie de funciones de aceleración que puede consumir las animaciones:
El BounceIn función de aceleración rebota la animación al principio.
El BounceOut función de aceleración rebota la animación al final.
El CubicIn lentamente en función de aceleración acelera la animación.
El CubicInOut función de aceleración acelera la animación al principio y ralentiza la animación al final.
El CubicOut rápidamente en función de aceleración disminuye la velocidad de la animación.
El Linear función de aceleración usa una velocidad constante y es el valor predeterminado función de
aceleración.
El SinIn sin problemas en función de aceleración acelera la animación.
El SinInOut sin problemas en función de aceleración acelera la animación al principio y disminuye la velocidad
sin problemas la animación al final.
El SinOut sin problemas en función de aceleración disminuye la velocidad de la animación.
El SpringIn función de aceleración hace que la animación acelerar rápidamente hacia el final.
El SpringOut función de aceleración hace que la animación que se ralentice rápidamente hacia el final.
El In y Out sufijos indican si el efecto de la función de aceleración es apreciable al principio de la animación, al
final, o ambos.
Además, se pueden crear funciones de aceleración. Para obtener más información, consulte funciones de
aceleración personalizada.
Al especificar una función de aceleración para una animación, la velocidad de animación se convierte en no lineal
y genera el efecto de la función de aceleración. Si se omite una función de aceleración al crear una animación hace
que la animación que utilice el valor predeterminado Linear función, lo que produce una velocidad lineal de
aceleración.
Para obtener más información sobre el uso de los métodos de extensión de la animación en el ViewExtensions de
clases, vea las animaciones sencillas. Funciones de aceleración también pueden utilizarse en el Animation clase.
Para obtener más información, consulte animaciones personalizadas.
Funciones de aceleración personalizadas
Existen tres enfoques principales para crear una función de aceleración personalizada:
1. Crear un método que toma un double argumento y devuelve un double resultado.
2. Creará un control Func<double, double> .
3. Especifique la función de aceleración como argumento para el Easing constructor.
En los tres casos, la función de aceleración personalizada debe devolver 0 para un argumento de 0 y 1 para un
argumento de 1. Sin embargo, se puede devolver cualquier valor entre los valores de argumento de 0 y 1. A su
vez ahora se explicará cada enfoque.
Método de aceleración personalizadas
Se puede definir una función de aceleración personalizada como un método que toma un double argumento y
devuelve un double como resultado, como se muestra en el ejemplo de código siguiente:
El CustomEase método trunca el valor entrante a los valores 0, 0,2, 0,4, 0.6, 0.8 y 1. Por lo tanto, el Image instancia
se traduce en saltos discretos, en lugar de forma fluida.
Aceleración Func personalizadas
También se puede definir una función de aceleración personalizada como un Func<double, double> , tal y como se
muestra en el ejemplo de código siguiente:
El CustomEase Func representa una función de entradas y salidas lenta que comienza rápido, se ralentiza e
invierte el curso y, a continuación, invierte nuevo curso para acelerar rápidamente hacia el final. Por tanto,
mientras el movimiento general de la Image instancia está hacia abajo, invierte también temporalmente a mitad
de camino a través de la animación del curso.
Constructor de aceleración personalizadas
También se puede definir una función de aceleración personalizada como el argumento de la Easing constructor,
tal y como se muestra en el ejemplo de código siguiente:
await image.TranslateTo (0, 200, 2000, new Easing (t => 1 - Math.Cos (10 * Math.PI * t) * Math.Exp (-5 * t)));
Resumen
En este artículo se muestra cómo utilizar las funciones de aceleración predefinidas y cómo crear funciones de
aceleración. Xamarin.Forms incluye la clase Easing , que permite especificar una función de transferencia que
controla cómo se aceleran o ralentizan las animaciones durante su ejecución.
Vínculos relacionados
Información general sobre la compatibilidad con Async
Funciones de aceleración (ejemplo)
Aceleración
ViewExtensions
Animaciones personalizadas en Xamarin.Forms
11/07/2019 • 20 minutes to read • Edit Online
descargar el ejemplo
La clase de animación es el bloque de creación de todas las animaciones de Xamarin.Forms, con los métodos de
extensión en la clase ViewExtensions crear uno o varios objetos de animación. En este artículo se muestra cómo
usar la clase de animación para crear y cancelar las animaciones, sincronizar varias animaciones y crear
animaciones personalizadas que animan las propiedades que no se animación mediante los métodos de
animación existentes.
Se debe especificar un número de parámetros al crear un Animation objeto, incluidos los valores inicial y final de
la propiedad que se anima y una devolución de llamada que cambia el valor de la propiedad. Un Animation
objeto también puede mantener una colección de animaciones secundarias que se pueden ejecutar y
sincronizado. Para obtener más información, consulte animaciones secundarias.
Ejecuta una animación que se creó con la Animation (clase), que puede o no incluir animaciones secundarias, se
logra mediante una llamada a la Commit método. Este método especifica la duración de la animación y, entre
otros elementos, una devolución de llamada que controla si se debe repetir la animación.
Este código define una animación de la Scale propiedad de un Image la instancia de un valor de 1 a un valor de
2. El valor animado, que se deriva mediante Xamarin.Forms, se pasa a la devolución de llamada especificado
como el primer argumento, donde se usa para cambiar el valor de la Scale propiedad.
La animación se inicia con una llamada a la Commit método, como se muestra en el ejemplo de código siguiente:
animation.Commit (this, "SimpleAnimation", 16, 2000, Easing.Linear, (v, c) => image.Scale = 1, () => true);
Tenga en cuenta que el Commit método no devuelve un Task objeto. En su lugar, las notificaciones se
proporcionan a través de métodos de devolución de llamada.
Los siguientes argumentos se especifican en el Commit método:
El primer argumento (propietario) identifica al propietario de la animación. Esto puede ser el elemento visual
en el que se aplica la animación u otro elemento visual, como la página.
El segundo argumento (nombre) identifica la animación con un nombre. El nombre se combina con el
propietario para identificar de forma única la animación. Esta identificación única, a continuación, puede usarse
para determinar si se está ejecutando la animación ( AnimationIsRunning ), o para cancelarla ( AbortAnimation ).
El tercer argumento (tasa) indica el número de milisegundos entre cada llamada al método de devolución de
llamada definido en el Animation constructor
El cuarto argumento ( longitud) indica la duración de la animación, en milisegundos.
El quinto argumento (aceleración) define la función de aceleración que se usará en la animación. Como
alternativa, la función de aceleración se puede especificar como argumento a la Animation constructor. Para
obtener más información acerca de funciones de aceleración, vea funciones de aceleración.
El sexto argumento (terminado) es una devolución de llamada que se ejecutará cuando se haya completado la
animación. Esta devolución de llamada toma dos argumentos, con el primer argumento que indica un valor
final y el segundo argumento es un bool que se establece en true si se ha cancelado la animación. Como
alternativa, el terminado devolución de llamada se puede especificar como argumento a la Animation
constructor. Sin embargo, con una animación única, si terminado las devoluciones de llamada se especifican
tanto en el Animation constructor y el Commit método, solo la devolución de llamada especificado en el
Commit se ejecutará el método.
El séptimo argumento (repita) es una devolución de llamada que permite que la animación se repita. Se llama
al final de la animación y devolver true indica que se debe repetir la animación.
El efecto general consiste en crear una animación que aumenta la Scale propiedad de un Image de 1 a 2,
superior a 2 segundos (2.000 milisegundos), mediante el Linear función de aceleración. Cada vez que finaliza la
animación, su Scale propiedad se restablece en 1 y se repite la animación.
NOTE
Las animaciones simultáneas, que se ejecutan de forma independiente entre sí se pueden construir mediante la creación de
un Animation para cada animación de objetos y, a continuación, llamar a la Commit método en cada animación.
Animaciones secundarias
El Animation clase también admite animaciones secundarias, que implica la creación de un Animation objeto qué
Sí Animation se agregan objetos. Esto permite una serie de animaciones que se ejecutará y se sincronizan. En el
ejemplo de código siguiente se muestra cómo crear y ejecutar animaciones secundarias:
parentAnimation.Commit (this, "ChildAnimations", 16, 4000, null, (v, c) => SetIsEnabledButtonState (true,
false));
Como alternativa, el ejemplo de código se puede escribir más concisa, como se muestra en el ejemplo de código
siguiente:
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));
En ambos ejemplos de código, un elemento primario Animation se crea el objeto, a la que adicionales Animation
, a continuación, se agregan objetos. Los dos primeros argumentos para el Add método especifique cuándo debe
comenzar y finalizar la animación secundarios. Los valores de argumento deben estar comprendido entre 0 y 1 y
representar el período relativo dentro de la animación principal que se activará la animación secundario
especificado. Por lo tanto, en este ejemplo el scaleUpAnimation estará activa durante la primera mitad de la
animación, la scaleDownAnimation estará activa para la segunda mitad de la animación y el rotateAnimation
estará activa durante toda la duración.
El efecto general es que la animación se produce más de 4 segundos (de 4000 milisegundos). El
scaleUpAnimation anima la Scale propiedad de 1 a 2, más de 2 segundos. El scaleDownAnimation luego anima la
Scale propiedad de 2 a 1, más de 2 segundos. Mientras se lleva a cabo ambas animaciones de escalado, la
rotateAnimation anima la Rotation propiedad comprendido entre 0 y 360, más de 4 segundos. Tenga en cuenta
que las animaciones de escalado también usar funciones de aceleración. El SpringIn función de aceleración hace
que el Image reducir inicialmente antes de obtener mayor y el SpringOut función de aceleración hace que la
Image sea menor que su tamaño real hacia el final de la animación completa.
Hay varias diferencias entre una Animation objeto que usa animaciones secundarias y que no:
Al usar animaciones secundarias, el terminado devolución de llamada en una animación secundaria indica
cuando se haya completado el elemento secundario y el terminado devolución de llamada se pasa a la Commit
método indica cuándo el ha completado la animación completa.
Al usar animaciones secundarias, devolver true desde el repita devolución de llamada en el Commit método
no hará que la animación se repita, pero la animación se seguirá ejecutando sin los nuevos valores.
Al incluir una función de aceleración en el Commit método y la función de aceleración devuelve un valor
mayor que 1, se terminará la animación. Si la función de aceleración devuelve un valor menor que 0, el valor
se fija en 0. Para utilizar una función de entradas y salidas lenta que devuelve un valor menor que 0 o mayor
que 1, debe especificar en una de las animaciones secundarias, en lugar de en el Commit método.
El Animation también incluye la clase WithConcurrent métodos que pueden usarse para agregar animaciones
secundarias a un elemento primario Animation objeto. Sin embargo, sus comenzar y finalizar valores de
argumento no se restringen a 0 a 1, pero solo esa parte de la animación de secundarios que se corresponde con
un intervalo de 0 a 1 estará activa. Por ejemplo, si un WithConcurrent llamada al método define una animación
secundaria que tiene como destino un Scale propiedad desde 1 a 6, pero con comenzar y finalizar valores de -2
y 3, el comenzar valor-2 corresponde a un Scale valor 1 y el finalizar valor 3 corresponde a un Scale valor de 6.
Dado que los valores fuera del intervalo de 0 y 1 no reproducción ninguna parte de una animación, la Scale
propiedad solo se pueden animar de 3 a 6.
this.AbortAnimation ("SimpleAnimation");
Tenga en cuenta que las animaciones se identifican mediante una combinación de propietario de la animación y el
nombre de la animación. Por lo tanto, el propietario y el nombre especifican al ejecutar la animación debe
especificarse para cancelar la animación. Por lo tanto, el ejemplo de código inmediatamente cancelará la
animación denominada SimpleAnimation que sea propiedad de la página.
La animación resultante proporciona la apariencia de avanzar el fondo de página a través de los colores del arco
iris.
Para obtener más ejemplos de creación de animaciones complejas, incluidas una animación de curva de Bézier,
consulte capítulo 22 de Creating Mobile Apps with Xamarin.Forms.
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);
En este ejemplo de código, el ColorTo método anima la TextColor y BackgroundColor las propiedades de un
Label , el BackgroundColor propiedad de una página y el Color propiedad de un BoxView .
Resumen
En este artículo se muestra cómo usar el Animation clase para crear y cancelar las animaciones, sincronizar varias
animaciones y crear animaciones personalizadas que animan las propiedades que no se animación la animación
existente métodos. La Animation clase es el bloque de creación de todas las animaciones de Xamarin.Forms.
Vínculos relacionados
Animaciones personalizadas (ejemplo)
Animación
AnimationExtensions
Xamarin.Forms BoxView
11/07/2019 • 29 minutes to read • Edit Online
descargar el ejemplo
BoxView Representa un rectángulo simple de un ancho especificado, alto y color. Puede usar BoxView como
decoración, gráficos rudimentarias y para la interacción con el usuario a través del tacto.
Dado que Xamarin.Forms no tiene un sistema de gráficos vectoriales integrados, la BoxView ayuda a compensar.
Algunos de los programas de ejemplo que se describe en este artículo se usa BoxView para representar gráficos.
El BoxView puede tendrán el tamaño que se asemeje a una línea de un ancho específico y el grosor y, a
continuación, girar cualquier ángulo utilizando la Rotation propiedad.
Aunque BoxView puede imitar los gráficos sencillos, quizá desee investigar utilizando SkiaSharp en
Xamarin.Forms para conocer los requisitos de gráficos más sofisticados.
En este artículo se trata los temas siguientes:
Establecer el tamaño y BoxView Color – establecer el BoxView propiedades.
Decoraciones de texto de representación – utilizar un BoxView para las líneas de representación.
Mostrar lista de colores con BoxView – mostrar todo el sistema de colores en un ListView .
Reproduce el juego de la vida mediante la creación de subclases BoxView – implementar un famoso
autómata celular.
Creación de un reloj Digital – simular una presentación de la matriz de puntos.
Creación de un reloj analógico – transformar y animar BoxView elementos.
El Color propiedad es de tipo Color ; se puede establecer la propiedad a cualquier Color valor, incluidos los 141
campos estáticos de sólo lectura de comprendido por orden alfabético de colores con nombre AliceBlue a
YellowGreen .
<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>
Este es el resultado:
<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>
Todo el marcado siguiente son elementos secundarios de la StackLayout . Este marcado se compone de varios
tipos de decorativos BoxView elementos utilizados con el Label elemento:
El encabezado elegante en la parte superior de la página se logra con una AbsoluteLayout cuyos elementos
secundarios son cuatro BoxView elementos y un Label , todos los de las cuales se asigna ubicaciones específicas y
tamaños:
<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>
En el archivo XAML, el AbsoluteLayout va seguido de un Label con formato de texto que describe el
AbsoluteLayout .
Una cadena de texto se puede subrayar incluyendo tanto la Label y BoxView en un StackLayout que tiene su
HorizontalOptions valor establecido en algo distinto Fill . El ancho de la StackLayout , a continuación, se rige
por el ancho de la Label , que luego impone ese ancho en el BoxView . El BoxView se asigna solo una altura
explícita:
<StackLayout HorizontalOptions="Center">
<Label Text="Underlined Text"
FontSize="24" />
<BoxView HeightRequest="2" />
</StackLayout>
No se puede usar esta técnica para subrayar palabras individuales dentro de las cadenas más largas de texto o un
párrafo.
También es posible usar un BoxView similar a HTML hr elemento (regla horizontal). Simplemente dejar que el
ancho de la BoxView determinarse mediante su contenedor primario, que en este caso es el StackLayout :
Por último, puede dibujar una línea vertical en un lado de un párrafo de texto, incluya ambos el BoxView y Label
en horizontal StackLayout . En este caso, el alto de la BoxView es el mismo que el alto de StackLayout , que se rige
por el alto de la Label :
<StackLayout Orientation="Horizontal">
<BoxView WidthRequest="4"
Margin="0, 0, 10, 0" />
<Label>
···
</Label>
</StackLayout>
// Static members.
static NamedColor()
{
List<NamedColor> all = new List<NamedColor>();
StringBuilder stringBuilder = new StringBuilder();
Se describen los objetos visuales de programa en el archivo XAML. El ItemsSource propiedad de la ListView está
establecido en estático NamedColor.All propiedad, lo que significa que el ListView muestra todos los individuales
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>
El NamedColorobjetos se les ha aplicado el ViewCell objeto que se establece como la plantilla de datos de la
ListView . Esta plantilla incluye un BoxView cuyo Color propiedad está enlazada a la Color propiedad de la
NamedColor objeto.
public LifeCell()
{
BackgroundColor = Color.White;
LifeCell agrega tres propiedades más BoxView : el Col y Row propiedades almacenan la posición de la celda
dentro de la cuadrícula y el IsAlive propiedad indica su estado. El IsAlive también establece la propiedad la
Color propiedad de la BoxView en negro si la celda está activo y en blanco si la celda no está activa.
LifeCell También se instala un TapGestureRecognizer para permitir al usuario alternar el estado de las celdas
punteando en ellos. La clase traduce la Tapped eventos del reconocedor de gestos en su propio Tapped eventos.
El GameOfLife programa también incluye un LifeGrid clase que encapsula gran parte de la lógica del juego, y
un MainPage clase que controla los objetos visuales del programa. Estos incluyen una superposición que se
describe las reglas del juego. Este es el programa en que se muestra un par de cientos de acción LifeCell objetos
en la página:
Creación de un reloj Digital
El DotMatrixClock programa crea 210 BoxView elementos para simular los puntos de una presentación del 5 al
7 matricial anticuado. Puede leer el tiempo en modo vertical u horizontal, pero es más grande en horizontal:
El archivo XAML poco más que crear una instancia del AbsoluteLayout utiliza el reloj:
<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 lo demás se produce en el archivo de código subyacente. La lógica de visualización matriciales se simplifica
enormemente la definición de varias matrices que describen los puntos correspondientes a cada uno de los 10
dígitos y dos puntos:
···
}
Estos campos concluyan con una matriz tridimensional de BoxView elementos para almacenar los patrones de
punto para los seis dígitos.
El constructor crea todas la BoxView elementos para los dígitos y dos puntos y también inicializa la Color
propiedad de la BoxView elementos de los dos puntos:
···
public MainPage()
{
InitializeComponent();
···
Este programa usa la característica de tamaño y posición relativa AbsoluteLayout . El ancho y alto de cada BoxView
se establecen en valores fraccionarios, específicamente el 85% 1 dividido por el número de puntos horizontales y
verticales. Las posiciones también se establecen en valores fraccionarios.
Dado que todas las posiciones y tamaños son en relación con el tamaño total de la AbsoluteLayout , el
SizeChanged solo necesita establecer el controlador de la página una HeightRequest de la AbsoluteLayout :
···
···
···
bool OnTimer()
{
DateTime dateTime = DateTime.Now;
Todos los objetos visuales en el BoxViewClock programa son elementos secundarios de un AbsoluteLayout .
Estos elementos tienen el tamaño mediante el LayoutBounds propiedad adjunta y girado usando el Rotation
propiedad.
Los tres BoxView elementos para las manecillas del reloj se crea una instancia en el archivo XAML, pero no
colocados o tamaño:
<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>
El constructor del archivo de código subyacente crea una instancia de la 60 BoxView elementos para las marcas de
graduación alrededor de la circunferencia del reloj:
···
public MainPage()
{
InitializeComponent();
···
El ajuste de tamaño y la posición de todos los BoxView elementos se produce en el SizeChanged controlador para
el AbsoluteLayout . Llama una pequeña estructura interna de la clase HandParams describe el tamaño de cada una
de las manos en relación con el tamaño total del reloj tres:
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;
}
···
···
AbsoluteLayout.SetLayoutBounds(boxView,
new Rectangle(center.X - 0.5 * width,
center.Y - offset * height,
width, height));
···
El LayoutHand método tamaños y los coloca cada mano para que apunte directamente hasta la posición 12:00. Al
final del método, el AnchorY propiedad está establecida en la posición correspondiente en el centro del reloj. Esto
indica que el centro de giro.
Las manos se giran en la función de devolución de llamada 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;
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));
}
El segundero se trata de un poco diferente: Se aplica una animación en función de aceleración para que parezca
que el movimiento tiene mecánica en lugar de smooth. En cada paso, el segundero extrae volver un poco y, a
continuación, se insertan su destino. Este pequeño fragmento de código agrega mucho el realismo del
movimiento.
Conclusión
El BoxView puede parecer simple al principio, pero a medida hemos visto, puede ser bastante versátil, y pueden
reproducir casi objetos visuales que normalmente sólo son posibles gráficos vectoriales. Para los gráficos más
sofisticados, consulte utilizando SkiaSharp en Xamarin.Forms.
Vínculos relacionados
BoxView básica (ejemplo)
Decoración de texto (ejemplo)
Color ListBox (ejemplo)
S Game of Life (ejemplo)
Matriz de puntos de reloj (ejemplo)
Reloj BoxView (ejemplo)
BoxView
Botón de Xamarin.Forms
11/07/2019 • 34 minutes to read • Edit Online
descargar el ejemplo
El botón se responde a un pulse o haga clic en que se dirige a una aplicación para llevar a cabo una tarea
determinada.
El Button es el control interactivo más fundamental en todas las de Xamarin.Forms. El Button normalmente
muestra una cadena de texto breve que indica un comando, pero también puede mostrar una imagen de mapa de
bits, o una combinación de texto y una imagen. El usuario presiona el Button con un dedo o hace clic en él con el
mouse para iniciar ese comando.
La mayoría de los temas se describe a continuación corresponden a las páginas de la ButtonDemos ejemplo.
El haga clic en botón básica página en el ButtonDemos ejemplo muestra cómo crear una instancia de un
Button en XAML y controle su Clicked eventos. El BasicButtonClickPage.xaml archivo contiene un
StackLayout con ambos un Label y un 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" />
</StackLayout>
</ContentPage>
El Button tiende a ocupar todo el espacio permitido para él. Por ejemplo, si no establece la HorizontalOptions
propiedad de Button a algo distinto Fill , el Button ocupará todo el ancho de su elemento primario.
De forma predeterminada, el Button es rectangular, pero puede dar TI redondeada esquinas mediante el
CornerRadius propiedad, como se describe a continuación, en la sección botón apariencia .
El Text propiedad especifica el texto que aparece en el Button . El Clicked evento está establecido en un
controlador de eventos denominado OnButtonClicked . Este controlador se encuentra en el archivo de código
subyacente, BasicButtonClickPage.xaml.cs:
public partial class BasicButtonClickPage : ContentPage
{
public BasicButtonClickPage ()
{
InitializeComponent ();
}
Cuando el Button se pulsa, el OnButtonClicked método se ejecuta. El sender argumento es el Button objeto
responsable de este evento. Se puede usar para tener acceso a la Button objeto, o para distinguir entre varias
Button objetos que comparten el mismo Clicked eventos.
Esta particular Clicked controlador llama a una función de animación que gira la Label 360 grados en 1000
milisegundos. Este es el programa que se ejecutan en dispositivos iOS y Android y como una aplicación de
plataforma Universal de Windows (UWP ) en el escritorio de Windows 10:
Tenga en cuenta que el OnButtonClicked método incluye el async modificador porque await se usa en el
controlador de eventos. Un Clicked controlador de eventos requiere la async modificador solo si usa el cuerpo
del controlador await .
Cada plataforma representa el Button en su propia manera específica. En el botón apariencia sección, podrá
ver cómo establecer colores y hacer el Button borde visible para los aspectos más personalizadas. Button
implementa el IFontElement interfaz, por lo que incluye FontFamily , FontSize , y FontAttributes propiedades.
Todo lo que se realiza en el constructor de clase. Dado que el Clicked controlador es solo una instrucción larga,
puede adjuntarse al evento muy sencillo:
Por supuesto, también puede definir el controlador de eventos como un método independiente (al igual que el
OnButtonClick método haga clic en botón básica ) y asocie ese método para el evento:
button.Clicked += OnButtonClicked;
Deshabilitar el botón
A veces, una aplicación está en un estado determinado donde un determinado Button haga clic en no es una
operación válida. En esos casos, el Button debe deshabilitarse estableciendo su IsEnabled propiedad false . El
ejemplo clásico es un Entry control para un nombre de archivo acompañada de un archivo-abrir Button : El
Button debe habilitarse solo si se ha escrito algún texto en el Entry . Puede usar un DataTrigger para esta tarea,
como se muestra en el datos desencadenadores artículo.
Este enfoque es especialmente adecuado en relación con el enlace de datos y especialmente al implementar la
arquitectura Model-View -ViewModel (MVVM ). Estos temas se tratan en los artículos enlace de datos, desde los
enlaces de datos a MVVM, y MVVM.
En una aplicación MVVM, ViewModel define las propiedades de tipo ICommand que están conectados, a
continuación, en el XAML Button elementos con enlaces de datos. Xamarin.Forms también define Command y
Command<T> las clases que implementan la ICommand interfaz y ayudar a definir las propiedades de tipo
ViewModel ICommand .
Los comandos se describen con más detalle en el artículo la interfaz de comandos pero la básica de botón de
comando página en el ButtonDemos muestra el enfoque básico.
El CommandDemoViewModel clase es una clase ViewModel muy simple que define una propiedad de tipo double
denominado Number y dos propiedades de tipo ICommand denominado MultiplyBy2Command y DivideBy2Command :
public CommandDemoViewModel()
{
MultiplyBy2Command = new Command(() => Number *= 2);
Los dos ICommandpropiedades se inicializan en el constructor de clase con dos objetos de tipo Command . El
Command constructores incluyen una pequeña función (denominado el execute argumento de constructor ) que
duplica o mitades el Number propiedad.
El BasicButtonCommand.xaml archivo establece su BindingContext a una instancia de CommandDemoViewModel .
El Label elemento y dos Button elementos contengan enlaces a las tres propiedades en 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" />
Como los dos Button se puntea elementos, los comandos se ejecutan, y el número de cambios de valor:
La ventaja de este enfoque sobre Clicked controladores es que toda la lógica que implican la funcionalidad de
esta página se encuentra en el modelo de vista en lugar de en el archivo de código subyacente, para lograr una
mejor separación de la interfaz de usuario de la lógica de negocios.
También es posible que el Command objetos para controlar la habilitación y deshabilitación de la Button
elementos. Por ejemplo, suponga que desea limitar el intervalo de valores numéricos entre 2 10 y 2–10. Puede
agregar otra función al constructor (denominado el canExecute argumento) que devuelve true si el Button
debe estar habilitada. Esta es la modificación de la CommandDemoViewModel constructor:
class CommandDemoViewModel : INotifyPropertyChanged
{
···
public CommandDemoViewModel()
{
MultiplyBy2Command = new Command(
execute: () =>
{
Number *= 2;
((Command)MultiplyBy2Command).ChangeCanExecute();
((Command)DivideBy2Command).ChangeCanExecute();
},
canExecute: () => Number < Math.Pow(2, 10));
Las llamadas a la ChangeCanExecute método Command son necesarios para que el Command puede llamar al
método el canExecute método y determinar si el Button debe deshabilitarse o no. Con este cambio de código,
como el número alcanza el límite, el Button está deshabilitado:
Es posible que dos o más Button elementos que se van a enlazarse a la misma ICommand propiedad. El Button
elementos se pueden distinguir mediante el CommandParameter propiedad de Button . En este caso, querrá usar
genérico Command<T> clase. El CommandParameter objeto, a continuación, se pasa como argumento a la execute y
canExecute métodos. Esta técnica se muestra en detalle en la comandos básicos sección de la comando
interfaz artículo.
El ButtonDemos ejemplo también usa esta técnica en su MainPage clase. El MainPage.xaml archivo contiene
un Button para cada página del ejemplo:
<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">
</FlexLayout>
</ScrollView>
</ContentPage>
Cada Button tiene su Command propiedad enlazada a una propiedad denominada NavigateCommand y el
CommandParameter está establecido en un Type objeto correspondiente a una de las clases de página en el
proyecto.
Que NavigateCommand propiedad es de tipo ICommand y se define en el archivo de código subyacente:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
BindingContext = this;
}
<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" />
</StackLayout>
</ContentPage>
El archivo de código subyacente se anima la Label cuando un Pressed evento se produce, pero se suspende la
rotación cuando un Released se produce el evento:
public PressAndReleaseButtonPage ()
{
InitializeComponent ();
}
Device.StartTimer(TimeSpan.FromMilliseconds(16), () =>
{
label.Rotation = 360 * (stopwatch.Elapsed.TotalSeconds % 1);
return animationInProgress;
});
}
El resultado es que el Label solo gira mientras un dedo se encuentra en contacto con el Button y se detiene
cuando se suelta el dedo:
Este tipo de comportamiento tiene aplicaciones de juegos: Un dedo mantenido en un Button podría provocar
que un objeto de la pantalla en movimiento en una dirección determinada.
NOTE
El Button clase también tiene Margin y Padding las propiedades que controlan el comportamiento de diseño de la
Button . Para obtener más información, consulte margen y relleno.
Los efectos de seis de estas propiedades (excepto FontFamily y FontAttributes ) se muestran en el apariencia
del botón página. Otra propiedad Image , se describe en la sección usando mapas de bits con el botón.
Todos los enlaces de datos y vistas en el apariencia del botón página se definen en el archivo 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}" />
<Slider x:Name="fontSizeSlider"
Maximum="48"
Minimum="1"
Value="{Binding FontSize}" />
<Slider x:Name="borderWidthSlider"
Minimum="-1"
Maximum="12"
Value="{Binding BorderWidth}" />
<Slider x:Name="cornerRadiusSlider"
Minimum="-1"
Maximum="24"
Value="{Binding CornerRadius}" />
Value="{Binding CornerRadius}" />
<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>
<Picker x:Name="textColorPicker"
ItemsSource="{Binding Source={x:Static local:NamedColor.All}}"
ItemDisplayBinding="{Binding FriendlyName}"
SelectedIndex="0"
Grid.Row="0" Grid.Column="1" />
<Picker x:Name="backgroundColorPicker"
ItemsSource="{Binding Source={x:Static local:NamedColor.All}}"
ItemDisplayBinding="{Binding FriendlyName}"
SelectedIndex="0"
Grid.Row="1" Grid.Column="1" />
<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>
El Button en la parte superior de la página tiene sus tres Color propiedades enlazadas a Picker elementos en
la parte inferior de la página. Los elementos de la Picker elementos son los colores de la NamedColor clase
incluida en el proyecto. Tres Slider elementos contienen enlaces bidireccionales para la FontSize , BorderWidth ,
y CornerRadius propiedades de la Button .
Este programa le permite experimentar con combinaciones de todas estas propiedades:
Para ver el Button borde, deberá establecer un BorderColor a algo distinto Default y el BorderWidth en un valor
positivo.
En iOS, observará que los anchos de borde grande interfieren en el interior de la Button e interfieren con la
presentación del texto. Si opta por utilizar un elemento border con un iOS Button , probablemente deseará
comenzar y terminar la Text propiedad con espacios para conservar su visibilidad.
En UWP, seleccionar un CornerRadius que supera la mitad del alto de la Button produce una excepción.
<VisualState x:Name="Pressed">
<VisualState.Setters>
<Setter Property="Scale"
Value="0.8" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Button>
El Pressed VisualState especifica que, cuando el Button está presionado, su Scale se cambiará la propiedad
de su valor predeterminado de 1 a 0,8. El Normal VisualState especifica que, cuando el Button está en estado
normal, su Scale propiedad se establecerá en 1. Por lo tanto, el efecto general es que cuando el Button está
presionado, se vuelve a escalar para que sea ligeramente más pequeñas pero cuando el Button está publicado,
se escalan a su tamaño predeterminado.
Para obtener más información acerca de los estados visuales, vea Xamarin.Forms Visual State Manager.
public ToggleButton()
{
Clicked += (sender, args) => IsToggled ^= true;
}
// Fire event
toggleButton.Toggled?.Invoke(toggleButton, new ToggledEventArgs(isToggled));
El ToggleButton constructor adjunta un controlador para el Clicked eventos, por lo que TI puede cambiar el
valor de la IsToggled propiedad. El OnIsToggledChanged método activa el Toggled eventos.
La última línea de la OnIsToggledChanged llamadas de método estático VisualStateManager.GoToState método con
el texto de dos cadenas "ToggledOn" y "ToggledOff". Puede leer acerca de este método y cómo la aplicación
puede responder a estados visuales en el artículo Xamarin.Forms Visual State Manager.
Dado que ToggleButton realiza la llamada a VisualStateManager.GoToState , la propia clase no necesita incluir
capacidades adicionales para cambiar la apariencia del botón según su IsToggled estado. Es decir, la
responsabilidad del XAML que hospeda el ToggleButton .
El demostración de botón de alternancia página contiene dos instancias de ToggleButton , incluido el
marcado Visual State Manager que establece el Text , BackgroundColor ,y TextColor del botón en función del
estado visual:
<ContentPage.Resources>
<Style TargetType="local:ToggleButton">
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
<Setter Property="HorizontalOptions" Value="Center" />
</Style>
</ContentPage.Resources>
<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" />
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
Los valores predeterminados son Left y 10 unidades. Dos propiedades de solo lectura de ButtonContentLayout
denominado Position y Spacing proporcione los valores de esas propiedades.
En el código, puede crear un Button y establezca el ContentLayout propiedad similar al siguiente:
Button button = new Button
{
Text = "button text",
ImageSource = new FileImageSource
{
File = "image filename"
},
ContentLayout = new Button.ButtonContentLayout(Button.ButtonContentLayout.ImagePosition.Right, 20)
};
En XAML, debe especificar solo el miembro de enumeración o el espaciado o ambos en cualquier orden separan
por comas:
El imagen Button Demo página usa OnPlatform para especificar los nombres de archivo diferente para iOS,
Android y UWP, los archivos de mapa de bits. Si desea usar el mismo nombre de archivo para cada plataforma y
evitar el uso de OnPlatform , necesitará para almacenar los mapas de bits UWP en el directorio raíz del proyecto.
La primera Button en el imagen Button Demo página establece el Image propiedad pero no la Text
propiedad:
<Button>
<Button.ImageSource>
<OnPlatform x:TypeArguments="ImageSource">
<On Platform="iOS, Android" Value="MonkeyFace.png" />
<On Platform="UWP" Value="Assets/MonkeyFace.png" />
</OnPlatform>
</Button.ImageSource>
</Button>
Si los mapas de bits UWP se almacenan en el directorio raíz del proyecto, este marcado se puede simplificar
considerablemente:
Para evitar mucha marcado redundante en la ImageButtonDemo.xaml archivo implícita Style también se
define para establecer el ImageSource propiedad. Esto Style se aplica automáticamente a otros cinco Button
elementos. Este es el archivo 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="ImageSource">
<OnPlatform x:TypeArguments="ImageSource">
<On Platform="iOS, Android" Value="MonkeyFace.png" />
<On Platform="UWP" Value="Assets/MonkeyFace.png" />
</OnPlatform>
</Setter>
</Style>
</FlexLayout.Resources>
<Button>
<Button.ImageSource>
<OnPlatform x:TypeArguments="ImageSource">
<On Platform="iOS, Android" Value="MonkeyFace.png" />
<On Platform="UWP" Value="Assets/MonkeyFace.png" />
</OnPlatform>
</Button.ImageSource>
</Button>
Los cuatro finales Button elementos hacen uso de la ContentLayout propiedad para especificar una posición y
espaciado del texto y mapa de bits:
Ahora ha visto las distintas formas que puede controlar Button eventos y cambiar el Button apariencia.
Vínculos relacionados
Ejemplo de ButtonDemos
Botón API
Casilla de verificación de Xamarin.Forms
11/07/2019 • 7 minutes to read • Edit Online
descargar el ejemplo
Xamarin.Forms CheckBox es un tipo de botón que puede ser activado ni estar vacío. Cuando se activa una casilla
de verificación, se considera en. Cuando una casilla de verificación está vacía, se considera estar apagado.
CheckBox define un bool propiedad denominada IsChecked , lo que indica si el CheckBox está activada. Esta
propiedad también está respaldada por un BindableProperty objeto, lo que significa que puede cambiar el estilo y
ser el destino de los enlaces de datos.
NOTE
El IsChecked propiedad enlazable tiene un modo de enlace predeterminada de BindingMode.TwoWay .
CheckBox define un CheckedChanged evento que se desencadena cuando el IsChecked los cambios de propiedad,
mediante la manipulación de usuario o cuando una aplicación establece el IsChecked propiedad. El
CheckedChangedEventArgs objeto que acompaña a la CheckedChanged el evento tiene una propiedad única
denominada Value , del tipo bool . Cuando se desencadena el evento, el valor de la Value propiedad está
establecida en el nuevo valor de la IsChecked propiedad.
<CheckBox />
Este XAML hace que aparezca en la que se muestra en las capturas de pantalla siguiente:
De forma predeterminada, el CheckBox está vacío. El CheckBox puede comprobarse la manipulación del usuario, o
estableciendo la IsChecked propiedad true :
Este XAML hace que aparezca en la que se muestra en las capturas de pantalla siguiente:
El sender argumento es el CheckBox responsable de este evento. Se puede usar para tener acceso a la CheckBox
objeto, o para distinguir entre varias CheckBox objetos que comparten el mismo CheckedChanged eventos.
Como alternativa, un controlador de eventos para el CheckedChanged se pueden registrar eventos en el código:
En este ejemplo, el Label usa una expresión de enlace en un desencadenador de datos para supervisar la
IsChecked propiedad de la CheckBox . Cuando esta propiedad se convierte en true , FontAttributes y FontSize
propiedades de la Label cambiar. Cuando el IsChecked propiedad devuelve al false , el FontAttributes y
FontSize propiedades de la Label se restablecen a su estado inicial.
En las capturas de pantalla siguiente, se muestra la captura de pantalla de iOS la Label formato cuando el
CheckBox está vacío, mientras que Android la captura de pantalla muestra la Label formato cuando el CheckBox
está activado:
Para obtener más información acerca de los desencadenadores, consulte Xamarin.Forms desencadenadores.
Las capturas de pantalla siguientes muestran una serie de activado CheckBox objetos, donde cada objeto tiene su
Color propiedad establecida en otro Color :
<CheckBox ...>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="Color"
Value="Red" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="IsChecked">
<VisualState.Setters>
<Setter Property="Color"
Value="Green" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</CheckBox>
En este ejemplo, el IsChecked VisualState especifica que, cuando el CheckBox está activada, su Color propiedad
se establecerá en verde. El Normal VisualState especifica que, cuando el CheckBox está en estado normal, su
Color propiedad se establecerá en rojo. Por lo tanto, el efecto general es que el CheckBox está en rojo cuando
está vacía y verde cuando se activa.
Para obtener más información acerca de los estados visuales, vea Xamarin.Forms Visual State Manager.
Vínculos relacionados
Demostraciones de casilla de verificación (ejemplo)
Desencadenadores de Xamarin.Forms
Administrador de estado Visual de Xamarin.Forms
Xamarin.Forms CollectionView
11/07/2019 • 2 minutes to read • Edit Online
Introducción
El CollectionView es una vista flexible y eficaz para presentar las listas de datos con las especificaciones de diseño
diferente.
Data
Un CollectionView se rellena con datos estableciendo sus ItemsSource propiedad a cualquier colección que
implementa IEnumerable . Se puede definir la apariencia de cada elemento de la lista estableciendo la
ItemTemplate propiedad a un DataTemplate .
Diseño
De forma predeterminada, un CollectionView mostrará sus elementos en una lista vertical. Sin embargo, se
pueden especificar las cuadrículas y listas horizontales y verticales.
Selección
De forma predeterminada, CollectionView la selección está deshabilitada. Sin embargo, se puede habilitar la
selección única o múltiple.
Vistas vacías
En CollectionView , se puede especificar una vista vacía que proporciona comentarios al usuario cuando no hay
datos disponibles para su presentación. La vista vacía puede ser una cadena, una vista o varias vistas.
Desplazarse
Cuando un Deslizamientos de usuario para iniciar un desplazamiento, se puede controlar la posición final del
desplazamiento para que se muestran por completo los elementos. Además, CollectionView define dos ScrollTo
métodos, que se desplace mediante programación los elementos en la vista. Una de las sobrecargas desplaza el
elemento en el índice especificado en la vista, mientras que el otro desplaza el elemento especificado en la vista.
Introducción de Xamarin.Forms CollectionView
11/07/2019 • 5 minutes to read • Edit Online
descargar el ejemplo
CollectionView es una vista para presentar las listas de datos mediante las especificaciones de diseño diferente. Su
objetivo es proporcionar una forma más flexible y una alternativa de alto rendimiento ListView . Por ejemplo, las
capturas de pantalla siguientes muestran un CollectionView que usa una cuadrícula vertical de dos columnas, y
que permite la selección múltiple:
CollectionView está disponible en Xamarin.Forms 4.0. Sin embargo, es experimental actualmente y solo se puede
usar agregando la siguiente línea de código para su AppDelegate clase en iOS, así como su MainActivity clase en
Android, antes de llamar a Forms.Init :
Forms.SetFlags("CollectionView_Experimental");
IMPORTANT
CollectionView está disponible en iOS y Android, pero solo está parcialmente disponible en la plataforma Universal de
Windows.
Vínculos relacionados
CollectionView (ejemplo)
Xamarin.Forms CollectionView datos
11/07/2019 • 7 minutes to read • Edit Online
descargar el ejemplo
CollectionView define las siguientes propiedades que definen los datos que se mostrarán y su apariencia:
ItemsSource , del tipo IEnumerable , especifica la colección de elementos que se mostrarán, y tiene un valor
predeterminado de null .
ItemTemplate , del tipo DataTemplate , especifica la plantilla para aplicar a cada elemento de la colección de
elementos que se mostrará.
Estas propiedades están respaldadas por BindableProperty objetos, lo que significa que las propiedades pueden
ser destinos de enlaces de datos.
<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
Tenga en cuenta que el elemento x:Array requiere un atributo Type que indica el tipo de los elementos de la matriz.
IMPORTANT
Si el CollectionView es necesario actualizar como elementos se agregan, quitados o cambiados en la colección subyacente,
la colección subyacente debe ser un IEnumerable que envía la propiedad de colección de notificaciones de cambios, como
ObservableCollection .
De forma predeterminada, CollectionView muestra elementos en una lista vertical, como se muestra en las
capturas de pantalla siguiente:
Para obtener información sobre cómo cambiar la CollectionView diseño, vea especificar un diseño. Para obtener
información sobre cómo definir la apariencia de cada elemento en el CollectionView , consulte definen la
apariencia del elemento.
Enlace de datos
CollectionView se pueden rellenar con datos mediante el uso de enlace de datos para enlazar su ItemsSource
propiedad a un IEnumerable colección. En XAML, esto se logra con la Binding extensión de marcado:
En este ejemplo, el ItemsSource datos de la propiedad se enlaza a la Monkeys propiedad del modelo de vista
conectada.
NOTE
Enlaces compilados se pueden habilitar para mejorar el rendimiento de enlace de datos en las aplicaciones de Xamarin.Forms.
Para obtener más información, consulte compilado enlaces.
Para obtener más información sobre el enlace de datos, vea Enlace de datos de Xamarin.Forms.
Grid.SetRowSpan(image, 2);
grid.Children.Add(image);
grid.Children.Add(nameLabel, 1, 0);
grid.Children.Add(locationLabel, 1, 1);
return grid;
});
Los elementos especificados en el DataTemplate definen la apariencia de cada elemento en la lista. En el ejemplo,
la disposición dentro de la DataTemplate está administrado por un Grid . El Grid contiene un Image objeto y
dos Label objetos, que todos se enlazan a las propiedades de la Monkey clase:
Las capturas de pantalla siguientes muestran el resultado de las plantillas cada elemento en la lista:
Para obtener más información sobre las plantillas de datos, consulte Plantillas de datos de Xamarin.Forms.
<ContentPage ...
xmlns:controls="clr-namespace:CollectionViewDemos.Controls">
<ContentPage.Resources>
<DataTemplate x:Key="AmericanMonkeyTemplate">
...
</DataTemplate>
<DataTemplate x:Key="OtherMonkeyTemplate">
...
</DataTemplate>
<controls:MonkeyDataTemplateSelector x:Key="MonkeySelector"
AmericanMonkey="{StaticResource AmericanMonkeyTemplate}"
OtherMonkey="{StaticResource OtherMonkeyTemplate}" />
</ContentPage.Resources>
Vínculos relacionados
CollectionView (ejemplo)
Enlace de datos en Xamarin.Forms
Plantillas de datos de Xamarin.Forms
Crear un Xamarin.Forms DataTemplateSelector
Diseño de Xamarin.Forms CollectionView
11/07/2019 • 15 minutes to read • Edit Online
descargar el ejemplo
CollectionView define las siguientes propiedades que controlan el diseño:
ItemsLayout , del tipo IItemsLayout , especifica el diseño que se usará.
ItemSizingStrategy , del tipo ItemSizingStrategy , especifica la estrategia de medida del elemento que se
usará.
Estas propiedades están respaldadas por BindableProperty objetos, lo que significa que las propiedades pueden
ser destinos de enlaces de datos.
De forma predeterminada, un CollectionView mostrará sus elementos en una lista vertical. Sin embargo,
cualquiera de los diseños siguientes pueden utilizarse:
Lista vertical: una lista de columna única que aumenta de tamaño verticalmente conforme se agregan nuevos
elementos.
Lista horizontal: una lista de fila única que crece horizontalmente cuando se agregan nuevos elementos.
Cuadrícula vertical: una cuadrícula de varias columna que aumenta de tamaño verticalmente conforme se
agregan nuevos elementos.
Cuadrícula horizontal: una cuadrícula de varias filas que crece horizontalmente cuando se agregan nuevos
elementos.
Estos diseños se pueden especificar estableciendo el ItemsLayout propiedad a la clase que deriva el ItemsLayout
clase. Esta clase define las siguientes propiedades:
Orientation , del tipo ItemsLayoutOrientation , especifica la dirección en que el CollectionView se expande
cuando se agregan elementos.
SnapPointsAlignment , del tipo SnapPointsAlignment , especifica cómo se alinean los puntos de acoplamiento
con elementos.
SnapPointsType , del tipo SnapPointsType , especifica el comportamiento de puntos de acoplamiento al
desplazarse.
Estas propiedades están respaldadas por BindableProperty objetos, lo que significa que las propiedades pueden
ser destinos de enlaces de datos. Para obtener más información acerca de los puntos de ajuste, vea ajustar puntos
en el Xamarin.Forms CollectionView desplazamiento guía.
El ItemsLayoutOrientation enumeración define los miembros siguientes:
Vertical indica que el CollectionView expandirá verticalmente cuando se agregan elementos.
Horizontal indica que el CollectionView expandirá horizontalmente cuando se agregan elementos.
El ListItemsLayout clase hereda de la ItemsLayout clase y define un ItemSpacing propiedad de tipo double , que
representa el espacio vacío alrededor de cada elemento. El valor predeterminado de esta propiedad es 0, y su
valor debe ser siempre mayor o igual que 0. El ListItemsLayout clase define también estático Vertical y
Horizontal miembros. Estos miembros se pueden usar para crear listas horizontales o verticales,
respectivamente. Como alternativa, un ListItemsLayout objeto puede crearse, especificando un
ItemsLayoutOrientation miembro de enumeración como argumento.
NOTE
CollectionView usa los motores de diseño nativo para realizar el diseño.
Lista vertical
De forma predeterminada, CollectionView mostrará sus elementos en un diseño de la lista vertical. Por lo tanto,
no es necesario establecer la ItemsLayout propiedad que se utilizará este diseño:
Sin embargo, para proporcionar información completa, una CollectionView puede configurarse para mostrar sus
elementos en una lista vertical estableciendo su ItemsLayout propiedad VerticalList :
<CollectionView ItemsSource="{Binding Monkeys}"
ItemsLayout="VerticalList">
...
</CollectionView>
Como alternativa, esto también puede realizarse estableciendo el ItemsLayout propiedad a un objeto de la
ListItemsLayout clase especificando el Vertical ItemsLayoutOrientation miembro de enumeración como
argumento:
Esto da como resultado una lista de columna única, lo que aumenta de tamaño verticalmente conforme se
agregan nuevos elementos:
Lista horizontal
CollectionView puede mostrar sus elementos en una lista horizontal estableciendo su ItemsLayout propiedad
HorizontalList :
<CollectionView ItemsSource="{Binding Monkeys}"
ItemsLayout="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, esto también puede realizarse estableciendo el ItemsLayout propiedad a un ListItemsLayout
objeto, especificando el Horizontal ItemsLayoutOrientation miembro de enumeración como argumento:
Esto da como resultado una lista de fila única, lo que aumenta de tamaño horizontalmente conforme se agregan
nuevos elementos:
Cuadrícula vertical
CollectionView puede mostrar sus elementos en una cuadrícula vertical estableciendo su ItemsLayout propiedad
a un GridItemsLayout cuyo Orientation propiedad está establecida en Vertical :
De forma predeterminada, una vertical GridItemsLayout mostrará los elementos en una sola columna. Sin
embargo, en este ejemplo se establece la GridItemsLayout.Span propiedad en 2. Esto da como resultado una
cuadrícula de dos columnas, lo que aumenta de tamaño verticalmente conforme se agregan nuevos elementos:
Cuadrícula horizontal
CollectionView puede mostrar sus elementos en una cuadrícula horizontal estableciendo su ItemsLayout
propiedad a un GridItemsLayout cuyo Orientation propiedad está establecida en Horizontal :
De forma predeterminada, una horizontal GridItemsLayout mostrará los elementos en una sola fila. Sin embargo,
en este ejemplo se establece la GridItemsLayout.Span propiedad a 4. Esto da como resultado una cuadrícula de
cuatro filas, lo que aumenta de tamaño horizontalmente conforme se agregan nuevos elementos:
Espaciado de elemento
De forma predeterminada, cada elemento en un CollectionView no tiene un espacio vacío alrededor de ella. Se
puede cambiar este comportamiento estableciendo las propiedades en el diseño de elementos utilizado por el
CollectionView .
NOTE
El ListItemsLayout.ItemSpacing propiedad tiene un conjunto de devolución de llamada de validación, lo que garantiza
que el valor de la propiedad es siempre mayor o igual que 0.
Este código da como resultado una lista vertical de columna única, que tiene un espaciado de 20 alrededor de
cada elemento:
NOTE
El GridItemsLayout.VerticalItemSpacing y GridItemsLayout.HorizontalItemSpacing propiedades tienen las
devoluciones de llamada de validación se establece, que garantizan que los valores de las propiedades son siempre mayor o
igual que 0.
Este código da como resultado una cuadrícula vertical de dos columnas, que tiene un espaciado vertical de 20
alrededor de cada elemento y un espaciado horizontal de 30 alrededor de cada elemento:
Ajuste de tamaño de elemento
De forma predeterminada, cada elemento en un CollectionView es individualmente mide y tamaño, siempre que
los elementos de interfaz de usuario en el DataTemplate no especificar tamaños fijos. Este comportamiento, que
se puede cambiar, especificado por el CollectionView.ItemSizingStrategy valor de propiedad. Este valor de
propiedad puede establecerse en uno de los ItemSizingStrategy miembros de enumeración:
MeasureAllItems – individualmente se mide cada elemento. Este es el valor predeterminado.
MeasureFirstItem : se mide solo el primer elemento, con todos los elementos subsiguientes del mismo tamaño
que el primer elemento determinados.
IMPORTANT
El MeasureFirstItem estrategia de ajuste de tamaño dará como resultado un aumento del rendimiento cuando se utiliza
en situaciones donde el tamaño del elemento debe ser uniforme en todos los elementos.
<CollectionView ...
ItemSizingStrategy="MeasureFirstItem">
...
</CollectionView>
El valor predeterminado FlowDirection para un elemento con un elemento primario es MatchParent . Por lo
tanto, el CollectionView hereda el FlowDirection valor de propiedad de la StackLayout , que a su vez hereda el
FlowDirection valor de propiedad de la ContentPage . Esto da como resultado el diseño de derecha a izquierda
que se muestra en las capturas de pantalla siguiente:
Para obtener más información acerca de la dirección del flujo, consulte localización de derecha a izquierda.
Vínculos relacionados
CollectionView (ejemplo)
Localización de derecha a izquierda
Desplazamiento de Xamarin.Forms CollectionView
Selección de Xamarin.Forms CollectionView
11/07/2019 • 12 minutes to read • Edit Online
descargar el ejemplo
CollectionView define las siguientes propiedades que controlan la selección de elementos:
SelectionMode , del tipo SelectionMode , el modo de selección.
SelectedItem , del tipo object , el elemento seleccionado en la lista. Esta propiedad no tiene un modo de
enlace predeterminada de TwoWay y tiene un null valor cuando se selecciona ningún elemento.
SelectedItems , del tipo IList<object> , los elementos seleccionados en la lista. Esta propiedad no tiene un
modo de enlace predeterminada de OneWay y tiene un null valor cuando no hay elementos seleccionados.
SelectionChangedCommand , del tipo ICommand , que se ejecuta cuando cambia el elemento seleccionado.
SelectionChangedCommandParameter , del tipo object , que es el parámetro que se pasa a la
SelectionChangedCommand .
Todas estas propiedades están respaldados por objetos BindableProperty , lo que significa que las propiedades
pueden ser destinos de los enlaces de datos.
De forma predeterminada, CollectionView la selección está deshabilitada. Sin embargo, se puede cambiar este
comportamiento estableciendo el SelectionMode valor de propiedad en uno de los SelectionMode miembros de
enumeración:
None : indica que no se pueden seleccionar elementos. Este es el valor predeterminado.
Single : indica que se puede seleccionar un solo elemento con el elemento seleccionado se resalta.
Multiple : indica que se pueden seleccionar varios elementos con los elementos seleccionados resaltados.
CollectionView define un SelectionChanged evento que se desencadena cuando el SelectedItem los cambios de
propiedad, ya sea debido a la selección de un elemento de la lista, o cuando una aplicación establece la propiedad
del usuario. Además, este evento también se desencadena cuando el SelectedItems los cambios de propiedad. El
SelectionChangedEventArgs objeto que acompaña a la SelectionChanged eventos tiene dos propiedades, ambos de
tipo IReadOnlyList<object> :
PreviousSelection : la lista de elementos que se seleccionaron antes de cambia la selección.
CurrentSelection : la lista de elementos que estén seleccionados, después del cambio de selección.
Selección única
Cuando el SelectionMode propiedad está establecida en Single , un único elemento en el CollectionView puede
seleccionarse. Cuando se selecciona un elemento, el SelectedItem propiedad se establecerá en el valor del
elemento seleccionado. Cuando esta propiedad cambia, el SelectionChangedCommand se ejecuta (con el valor de la
SelectionChangedCommandParameter que se pasan a la ICommand ) y el SelectionChanged desencadena el evento.
El siguiente ejemplo XAML se muestra un CollectionView que puede responder a un solo elemento selección:
<CollectionView ItemsSource="{Binding Monkeys}"
SelectionMode="Single"
SelectionChanged="OnCollectionViewSelectionChanged">
...
</CollectionView>
IMPORTANT
El SelectionChanged eventos pueden activar los cambios que se producen como resultado de cambiar el SelectionMode
propiedad.
Selección múltiple
Cuando el SelectionMode propiedad está establecida en Multiple , varios elementos en el CollectionView puede
seleccionarse. Cuando se seleccionan elementos, la SelectedItems propiedad se establecerá en los elementos
seleccionados. Cuando esta propiedad cambia, el SelectionChangedCommand se ejecuta (con el valor de la
SelectionChangedCommandParameter que se pasan a la ICommand ) y el SelectionChanged desencadena el evento.
El siguiente ejemplo XAML se muestra un CollectionView que puede responder a la selección de varios
elementos:
<CollectionView ItemsSource="{Binding Monkeys}"
SelectionMode="Multiple"
SelectionChanged="OnCollectionViewSelectionChanged">
...
</CollectionView>
IMPORTANT
El SelectionChanged eventos pueden activar los cambios que se producen como resultado de cambiar el SelectionMode
propiedad.
NOTE
El SelectedItem propiedad tiene un modo de enlace predeterminada de TwoWay .
El SelectedItem datos de la propiedad se enlaza a la SelectedMonkey propiedad del modelo de vista conectada,
que es de tipo Monkey . De forma predeterminada, un TwoWay enlace se usa por lo que ese if el usuario cambia el
elemento seleccionado, el valor de la SelectedMonkey se establecerá la propiedad seleccionada Monkey objeto. El
SelectedMonkey propiedad está definida en el MonkeysViewModel clase y se establece en el cuarto elemento de la
Monkeys colección:
Monkey selectedMonkey;
public Monkey SelectedMonkey
{
get
{
return selectedMonkey;
}
set
{
if (selectedMonkey != value)
{
selectedMonkey = value;
}
}
}
public MonkeysViewModel()
{
...
selectedMonkey = Monkeys.Skip(3).FirstOrDefault();
}
...
}
<CollectionView x:Name="collectionView"
ItemsSource="{Binding Monkeys}"
SelectionMode="Multiple"
SelectedItems="{Binding SelectedMonkeys}">
...
</CollectionView>
NOTE
El SelectedItems propiedad tiene un modo de enlace predeterminada de OneWay .
El SelectedItems datos de la propiedad se enlaza a la SelectedMonkeys propiedad del modelo de vista conectada,
que es de tipo ObservableCollection<object> . El SelectedMonkeys propiedad está definida en el MonkeysViewModel
clase y se establece en el segundo, cuarta y quinta los elementos de la Monkeys colección:
namespace CollectionViewDemos.ViewModels
{
public class MonkeysViewModel : INotifyPropertyChanged
{
...
ObservableCollection<object> selectedMonkeys;
public ObservableCollection<object> SelectedMonkeys
{
get
{
return selectedMonkeys;
}
set
{
if (selectedMonkeys != value)
{
selectedMonkeys = value;
}
}
}
public MonkeysViewModel()
{
...
SelectedMonkeys = new ObservableCollection<object>()
{
Monkeys[1], Monkeys[3], Monkeys[4]
};
}
...
}
}
Por lo tanto, cuando el CollectionView aparece, el segundo, cuarto, y están preseleccionados quinto elementos de
la lista:
Borrar selecciones
El SelectedItem y SelectedItems propiedades pueden eliminarse mediante el establecimiento ellos o los objetos
que enlazan, a null .
IMPORTANT
El Style que contiene el Selected VisualState debe tener un TargetType valor de propiedad que es el tipo del
elemento raíz de la DataTemplate , que se establece como el ItemTemplate valor de propiedad.
En este ejemplo, el Style.TargetType el valor de propiedad se establece en Grid porque el elemento raíz de la
ItemTemplate es un Grid . El Selected VisualState especifica que cuando un elemento de la CollectionView
está activada, el BackgroundColor del elemento se establecerá en LightSkyBlue :
[ ] (selection-images/single-selection-color-
large.png#lightbox " CollectionView lista vertical con un color personalizado de selección única")
Para obtener más información acerca de los estados visuales, vea Xamarin.Forms Visual State Manager.
Deshabilitar la selección
CollectionView selección está deshabilitada de forma predeterminada. Sin embargo, si un CollectionView tiene
selección habilitada, se puede deshabilitar estableciendo la SelectionMode propiedad None :
<CollectionView ...
SelectionMode="None" />
Cuando el SelectionMode propiedad está establecida en None , los elementos de la CollectionView no puede
seleccionarse el SelectedItem propiedad permanecer null y el SelectionChanged no se desencadenará el evento.
NOTE
Cuando se selecciona un elemento y el SelectionMode se cambia la propiedad de Single a None , SelectedItem
propiedad se establecerá en null y el SelectionChanged se desencadenará el evento con un valor vacío
CurrentSelection propiedad.
Vínculos relacionados
CollectionView (ejemplo)
Administrador de estado Visual de Xamarin.Forms
Xamarin.Forms CollectionView EmptyView
11/07/2019 • 11 minutes to read • Edit Online
descargar el ejemplo
CollectionView define las siguientes propiedades que pueden usarse para proporcionar comentarios de los
usuarios cuando no hay ningún dato para mostrar:
EmptyView , del tipo object , la cadena, el enlace o la vista que será que se muestra cuando el ItemsSource
propiedad es null , o cuando la colección especificado por el ItemsSource propiedad es null o está vacío. El
valor predeterminado es null .
EmptyViewTemplate , del tipo DataTemplate , la plantilla para dar formato especificado a EmptyView . El valor
predeterminado es null .
Estas propiedades están respaldadas por BindableProperty objetos, lo que significa que las propiedades pueden
ser destinos de enlaces de datos.
Los escenarios de uso principal para la configuración de la EmptyView propiedad se muestran los comentarios de
los usuarios cuando una operación de filtrado en un CollectionView produce no tiene datos y mostrar
comentarios de los usuarios mientras se recuperan datos de un servicio web.
NOTE
El EmptyView propiedad puede establecerse en una vista que incluya contenido interactivo si es necesario.
Para obtener más información sobre las plantillas de datos, consulte Plantillas de datos de Xamarin.Forms.
El resultado es que, dado que los datos de colección enlazan es null , Establece la cadena como el EmptyView se
muestra el valor de propiedad:
<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>
Cuando el SearchBar ejecuta el FilterCommand , la colección mostrada por el CollectionView se filtra para el
término de búsqueda se almacena en el SearchBar.Text propiedad. Si el resultado de la operación de filtrado
ningún dato, la StackLayout establecer como el EmptyView se muestra el valor de propiedad:
<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>
Este XAML define dos ContentView objetos en el nivel de página ResourceDictionary , con el Switch controlar
que el objeto ContentView objeto que se establecerá como el EmptyView valor de propiedad. Cuando el Switch se
activa, el OnEmptyViewSwitchToggled ejecuta el controlador de eventos el ToggleEmptyView método:
El ToggleEmptyView método establece el EmptyView propiedad de la collectionView objeto en uno de los dos
ContentView objetos almacenados en el ResourceDictionary , según el valor de la Switch.IsToggled propiedad.
Cuando el SearchBar ejecuta el FilterCommand , la colección mostrada por el CollectionView se filtra para el
término de búsqueda se almacena en el SearchBar.Text propiedad. Si el resultado de la operación de filtrado
ningún dato, la ContentView objeto establecido como el EmptyView propiedad se muestra:
Para obtener más información acerca de los diccionarios de recursos, consulte diccionarios de recursos de
Xamarin.Forms.
<ContentPage ...
xmlns:controls="clr-namespace:CollectionViewDemos.Controls">
<ContentPage.Resources>
<DataTemplate x:Key="AdvancedTemplate">
...
</DataTemplate>
<DataTemplate x:Key="BasicTemplate">
...
</DataTemplate>
<controls:SearchTermDataTemplateSelector x:Key="SearchSelector"
DefaultTemplate="{StaticResource AdvancedTemplate}"
OtherTemplate="{StaticResource BasicTemplate}" />
</ContentPage.Resources>
<StackLayout Margin="20">
<SearchBar x:Name="searchBar"
SearchCommand="{Binding FilterCommand}"
SearchCommandParameter="{Binding Source={x:Reference searchBar}, Path=Text}"
Placeholder="Filter" />
<CollectionView ItemsSource="{Binding Monkeys}"
EmptyView="{Binding Source={x:Reference searchBar}, Path=Text}"
EmptyViewTemplate="{StaticResource SearchSelector}" />
</StackLayout>
</ContentPage>
Para obtener más información acerca de los selectores de plantilla de datos, vea crear un Xamarin.Forms
DataTemplateSelector.
Vínculos relacionados
CollectionView (ejemplo)
Plantillas de datos de Xamarin.Forms
Diccionarios de recursos de Xamarin.Forms
Crear un Xamarin.Forms DataTemplateSelector
Desplazamiento de Xamarin.Forms CollectionView
11/07/2019 • 9 minutes to read • Edit Online
descargar el ejemplo
CollectionView define dos ScrollTo métodos, que desplazar los elementos en la vista. Una de las sobrecargas
desplaza el elemento en el índice especificado en la vista, mientras que el otro desplaza el elemento especificado
en la vista. Ambas sobrecargas tienen argumentos adicionales que pueden especificarse para indicar la posición
exacta del elemento después de que el desplazamiento se ha completado y si se va a animar el desplazamiento.
CollectionView define un evento que se desencadena cuando uno de los ScrollTo métodos
ScrollToRequested
se invocan. El ScrollToRequestedEventArgs objeto que acompaña a la ScrollToRequested eventos tiene muchas
propiedades, como IsAnimated , Index , Item , y ScrollToPosition . Estas propiedades se establecen en los
argumentos especificados en el ScrollTo llamadas al método.
Cuando un Deslizamientos de usuario para iniciar un desplazamiento, se puede controlar la posición final del
desplazamiento para que se muestran por completo los elementos. Esta característica se conoce como ajuste,
porque los elementos de ajuste para colocar cuando se detiene el desplazamiento. Para obtener más información,
consulte ajustar puntos.
collectionView.ScrollTo(12);
Este código de ejemplo genera el desplazamiento mínimo requerido para desplazar el elemento en la vista:
NOTE
El ScrollToPosition.MakeVisible miembro se usa de forma predeterminada, si la position no se especifica un
argumento al llamar a la ScrollTo método.
Iniciar
El ScrollToPosition.Start miembro indica que el elemento se debe desplazar al principio de la vista:
Fin
El ScrollToPosition.End miembro indica que se debe desplazar el elemento al final de la vista:
Este código de ejemplo genera el elemento que se desplaza hasta el final de la vista:
Puntos de ajuste
Cuando un Deslizamientos de usuario para iniciar un desplazamiento, se puede controlar la posición final del
desplazamiento para que se muestran por completo los elementos. Esta característica se conoce como ajuste,
porque los elementos de ajuste para colocar cuando el desplazamiento se detiene y se controla mediante las
siguientes propiedades de la ItemsLayout clase:
SnapPointsType , del tipo SnapPointsType , especifica el comportamiento de puntos de acoplamiento al
desplazarse.
SnapPointsAlignment , del tipo SnapPointsAlignment , especifica cómo se alinean los puntos de acoplamiento
con elementos.
Estas propiedades están respaldadas por BindableProperty objetos, lo que significa que las propiedades pueden
ser destinos de enlaces de datos.
NOTE
Cuando se produce el ajuste, se producirá en la dirección que genera la menor cantidad de movimiento.
Iniciar
El SnapPointsAlignment.Start miembro indica que los puntos de acoplamiento se alinean con el borde inicial de
elementos.
De forma predeterminada, el SnapPointsAlignment propiedad está establecida en SnapPointsAlignment.Start . Sin
embargo, por razones de integridad, en el siguiente ejemplo XAML se muestra cómo establecer a este miembro
de enumeración:
<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>
Cuando un Deslizamientos de usuario para iniciar un desplazamiento, el elemento superior se alineará con la
parte superior de la vista:
Centrar
El SnapPointsAlignment.Center miembro indica que los puntos de acoplamiento se alinean con el centro de
elementos. En el siguiente ejemplo XAML se muestra cómo establecer a este miembro de enumeración:
<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>
Cuando un Deslizamientos de usuario para iniciar un desplazamiento, el elemento superior estará centrado en la
parte superior de la vista:
Fin
El SnapPointsAlignment.End miembro indica que los puntos de acoplamiento se alinean con el borde final de
elementos. En el siguiente ejemplo XAML se muestra cómo establecer a este miembro de enumeración:
<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>
Cuando un Deslizamientos de usuario para iniciar un desplazamiento, el elemento de la parte inferior se alineará
con la parte inferior de la vista:
Vínculos relacionados
CollectionView (ejemplo)
Colores de Xamarin.Forms
11/07/2019 • 5 minutes to read • Edit Online
descargar el ejemplo
Xamarin.Forms proporciona una clase de Color flexible y multiplataforma.
Este artículo presentan las distintas formas la Color clase puede usarse en Xamarin.Forms.
La Color clase proporciona una serie de métodos para crear una instancia de color
Colores con nombre -una colección de comunes colores con nombre, incluidos Red , Green , y Blue .
FromHex -valor similar a la sintaxis utilizada en HTML, por ejemplo "00FF00" de cadena. Alfa, opcionalmente,
puede especificarse como el primer par de caracteres ("CC00FF00").
FromHsla -matiz, saturación y luminosidad double valores, con el valor alfa opcional (0.0-1.0).
FromRgb -rojo, verde y azul int valores (0-255).
FromRgba -rojo, verde, azul y alfa int valores (0-255).
FromUint -establecer una sola double que representa el valor argb.
Presentamos algunos colores del ejemplo, asignados a la BackgroundColor de algunas etiquetas utilizando
diferentes variaciones de la sintaxis permitida:
Estos colores se muestran en cada plataforma a continuación. Tenga en cuenta el color final - Accent -es un color
blue-ish para iOS y Android; este valor se define mediante Xamarin.Forms.
Color.Default
Use el Default para establecer un valor de color en el valor predeterminado de plataforma (Esto representa un
color subyacente diferente en cada plataforma para cada propiedad de descripción) (o volver a establecer).
Los desarrolladores pueden usar este valor para establecer un Color propiedad pero no debería no consultar
esta instancia para sus valores RGB de componente (que están todo listo en -1).
Color.Transparent
Establezca el color para borrar.
Color.Accent
En iOS y Android, esta instancia se establece en un color de contraste que está visible en el fondo predeterminado,
pero no es el mismo que el color del texto de forma predeterminada.
Métodos adicionales
Color instancias incluyen métodos adicionales que pueden usarse para crear nuevos colores:
AddLuminosity -devuelve un nuevo color si modifica la luminosidad por el delta proporcionado.
WithHue -devuelve un nuevo color, reemplazando el matiz con el valor proporcionado.
WithLuminosity -devuelve un nuevo color, reemplazando la luminosidad con el valor proporcionado.
WithSaturation -devuelve un nuevo color, reemplazando la saturación con el valor proporcionado.
MultiplyAlpha -devuelve un nuevo color mediante la modificación de la versión alfa, multiplicarlo por el valor
alfa proporcionado.
Conversiones implícitas
Conversión implícita entre el Xamarin.Forms.Color y System.Drawing.Color tipos se pueden realizar:
Device.RuntimePlatform
Este fragmento de código usa el Device.RuntimePlatform propiedad para establecer el color de un
ActivityIndicator :
Uso de XAML
También se puedan encontrar fácilmente los colores en XAML mediante los nombres de colores definido o las
representaciones hexadecimales que se muestra aquí:
<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
Cuando se usa la compilación de XAML, los nombres de colores distinguen mayúsculas de minúsculas y por lo tanto, pueden
escribirse en minúsculas. Para obtener más información sobre la compilación de XAML, vea compilación XAML.
Resumen
Xamarin.Forms Color clase se utiliza para crear referencias de color basadas en la plataforma. Se puede usar en
código compartido y XAML.
Vínculos relacionados
ColorsSample
Selector de enlazable (ejemplo)
Controls Reference (Referencia de controles)
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Una descripción de todos los elementos visuales que se usa para construir una aplicación de Xamarin.Forms.
La interfaz visual de una aplicación de Xamarin.Forms se construye de objetos que se asignan a los controles
nativos de cada plataforma de destino. Esto permite que aplicaciones específicas de la plataforma para iOS,
Android y la plataforma Universal de Windows usar el código de Xamarin.Forms contenido en un biblioteca .NET
Standard o un proyecto compartido.
En estos cuatro artículos se muestran los cuatro grupos de control principal usados para crear la interfaz de
usuario de una aplicación de Xamarin.Forms:
Páginas
Diseños
Vistas
Celdas
Por lo general, una página de Xamarin.Forms ocupa toda la pantalla. La página suele contener un diseño, que
contiene las vistas y, posiblemente, otros diseños. Las celdas son componentes especializados utilizados en
conexión con TableView y ListView .
En los artículos en cuatro páginas, diseños, vistas , y celdas, se describe cada tipo de control con vínculos a uno
o más programas de ejemplo, un artículo que describe su uso (si existe) y su documentación de API (si existen).
Cada tipo de control también está acompañado por una captura de pantalla que muestra una página de la
FormsGallery ejemplo que se ejecutan en iOS, Android y UWP dispositivos. Cada captura de pantalla siguiente
se vincula al código de origen para la página de C#, la página XAML equivalente y (cuando corresponda) el
archivo de código subyacente de C# para la página XAML.
Vínculos relacionados
Ejemplo de Xamarin.Forms FormsGallery
Documentación de la API
Páginas de Xamarin.Forms
11/07/2019 • 4 minutes to read • Edit Online
descargar el ejemplo
Las páginas de Xamarin.Forms representan pantallas de aplicaciones móviles multiplataforma.
Todos los tipos de página que se describen a continuación se derivan de Xamarin.Forms Page clase. Estos
elementos visuales ocupan todos o la mayoría de la pantalla. Un Page objeto representa un ViewController en
iOS y un Page en la plataforma Universal de Windows. En Android, cada página ocupa la pantalla como una
Activity , pero las páginas de Xamarin.Forms son no Activity objetos.
Páginas
Xamarin.Forms es compatible con los siguientes tipos de página:
ContentPage
Documentación de la API
MasterDetailPage
Un MasterDetailPage administra dos paneles de
información. Establecer el Master propiedad a una página
con carácter general que muestra una lista o un menú.
Establecer el Detail propiedad a una página que muestra
un elemento seleccionado de la página maestra. El
IsPresented propiedad controla si está visible la página
maestra o de detalle.
NavigationPage
TabbedPage
CarouselPage
CarouselPage se deriva de la clase abstracta MultiPage
clase y permite la navegación entre secundarios páginas a
través de deslizar el dedo. Establecer el Children propiedad
a una colección de ContentPage objetos o conjunto el
ItemsSource propiedad a una colección de objetos de
datos y el ItemTemplate propiedad a un DataTemplate
que describe cómo cada objeto se para representar
visualmente.
TemplatedPage
Vínculos relacionados
Ejemplo de Xamarin.Forms FormsGallery
Xamarin.Forms Samples (Ejemplos de Xamarin.Forms)
Documentación de la API de Xamarin.Forms
Diseños de Xamarin.Forms
11/07/2019 • 5 minutes to read • Edit Online
descargar el ejemplo
Los diseños de Xamarin.Forms se utilizan para crear controles de interfaz de usuario en estructuras visuales.
El Layout y Layout<T> clases de Xamarin.Forms son subtipos especializadas de las vistas que actúan como
contenedores para otros diseños y vistas. El Layout propia clase se deriva de View . Un Layout derivado
normalmente contiene lógica para establecer la posición y tamaño de los elementos secundarios en las
aplicaciones de Xamarin.Forms.
Documentación de la API
Documentación de la API
ScrollView
TemplatedView
ContentPresenter
ContentPresenter es un administrador de diseño para las
vistas con plantilla, se utiliza dentro de un
ControlTemplate para marcar dónde aparece el contenido
que debe presentarse.
Cuadrícula
AbsoluteLayout
AbsoluteLayout coloca los elementos secundarios en
ubicaciones específicas en relación con su elemento primario.
Posición del elemento secundario se indica mediante el
propiedades adjuntas LayoutBounds y LayoutFlags . Un
AbsoluteLayout es útil para animar las posiciones de las
vistas.
RelativeLayout
FlexLayout
Vínculos relacionados
Ejemplo de Xamarin.Forms FormsGallery
Xamarin.Forms Samples (Ejemplos de Xamarin.Forms)
Documentación de la API de Xamarin.Forms
Vistas de Xamarin.Forms
12/07/2019 • 14 minutes to read • Edit Online
descargar el ejemplo
Las vistas de Xamarin.Forms son los bloques de creación de interfaces de usuario móviles multiplataforma.
Las vistas son objetos de interfaz de usuario, como etiquetas, botones y los controles deslizantes que se
conocen normalmente como controles o widgets en otros entornos de programación de gráficos. Las vistas
compatibles con Xamarin.Forms todos se derivan los View clase. Pueden dividirse en varias categorías:
Vistas de presentación
Etiqueta
Imagen
BoxView
BoxView muestra un rectángulo relleno con color de la
Color propiedad. BoxView tiene una solicitud de tamaño
predeterminado de 40 x 40. Para otros tamaños, asigne el
WidthRequest y HeightRequest propiedades.
WebView
OpenGLView
Documentación de la API
Asignación
Map muestra un mapa. El xamarin.Forms.Maps para
debe instalarse el paquete Nuget. Android y plataforma
Universal de Windows requieren una clave de autorización
de mapa.
ImageButton
Guía de / ejemplo
SearchBar
SearchBar muestra un área para el usuario escriba una
cadena de texto y un botón (o una tecla del teclado) que se
indica a la aplicación para realizar una búsqueda. El Text
propiedad proporciona acceso al texto y el
SearchButtonPressed evento indica que se ha presionado
el botón.
Documentación de la API
Slider
Modificador
DatePicker
TimePicker
TimePicker permite al usuario seleccionar una hora con el
selector de hora de la plataforma. El Time propiedad es la
hora seleccionada. Una aplicación puede supervisar los
cambios en el Time propiedad instalando un controlador
para el PropertyChanged eventos.
Editor
ProgressBar
ListView
ListView se deriva de ItemsView y muestra una lista
desplazable de elementos de datos seleccionable. Establecer
el ItemsSource propiedad a una colección de objetos y
establezca el ItemTemplate propiedad a un
DataTemplate objeto que describe cómo los elementos son
para tener el formato. El ItemSelected eventos indica que
se ha realizado una selección, que está disponible como la
SelectedItem propiedad.
Selector
TableView
Vínculos relacionados
Ejemplo de Xamarin.Forms FormsGallery
Xamarin.Forms Samples (Ejemplos de Xamarin.Forms)
Documentación de la API de Xamarin.Forms
Celdas de Xamarin.Forms
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Las celdas de Xamarin.Forms pueden agregarse a ListView y TableViews.
Un celda es un elemento especializado utilizado para los elementos de una tabla y se describe cómo se debe
representar cada elemento en una lista. El Cell clase se deriva de Element , desde el que VisualElement
también se deriva. Una celda no es un elemento visual; en realidad es una plantilla para crear un elemento visual.
Cell se utiliza exclusivamente con ListView y TableView controles. Para obtener información sobre cómo usar
y personalizar celdas, consulte el ListView y TableView documentación.
Celdas
Xamarin.Forms es compatible con los siguientes tipos de celda:
TextCell
ImageCell
EntryCell
Vínculos relacionados
Ejemplo de Xamarin.Forms FormsGallery
Xamarin.Forms Samples (Ejemplos de Xamarin.Forms)
Documentación de la API de Xamarin.Forms
Xamarin.Forms DataSourceControl
11/07/2019 • 3 minutes to read • Edit Online
IMPORTANT
DataSourceControl requiere un Xamarin.Forms tema referencia a representar.
Xamarin.Forms DataSourceControl se anunciaron en Evolve 2016 y están disponible como una vista previa para
clientes probar y proporcionar comentarios.
DataSourceControl proporciona una API para enlazar de forma rápida y sencilla un origen de datos a vistas
precompiladas. Elementos de lista y páginas de detalle representarán los datos de forma automática y se pueden
personalizar utilizando temas.
Para ver cómo funciona la demostración del discurso de apertura evolucionan, consulte el Guía de introducción.
Introducción
Orígenes de datos y las páginas de datos asociadas permiten a los desarrolladores rápida y fácilmente consumir
un origen de datos admitidos y para representarlo mediante integradas se puede personalizar la interfaz de
usuario de scaffolding que con los temas.
DataSourceControl se agrega a una aplicación de Xamarin.Forms mediante la inclusión de la
Xamarin.Forms.Pages paquete Nuget.
Orígenes de datos
La versión preliminar tiene algunos orígenes de datos creada previamente disponibles para su uso:
JsonDataSource
AzureDataSource (separe Nuget)
AzureEasyTableDataSource (separe Nuget)
Consulte la Guía de introducción para obtener un ejemplo con un JsonDataSource .
Las páginas y controles
Las siguientes páginas y controles se incluyen para permitir el enlace sencillo para los orígenes de datos
proporcionado:
ListDataPage : vea la Introducción al ejemplo.
DirectoryPage : una lista con agrupación habilitada.
PersonDetailPage : un elemento de datos únicos en la vista personalizada para un tipo de objeto específico
(una entrada de contacto).
DataView : una vista para exponer datos procedentes del origen de forma genérica.
CardView : una con el estilo de vista que contiene una imagen, el texto del título y el texto de descripción.
HeroImage : una vista de la representación de imágenes.
ListItem : un pregeneradas vista con un diseño similar a los elementos de lista de Android y iOS nativo.
Consulte la DataSourceControl controla referencia para obtener ejemplos.
En segundo plano
Un origen de datos de Xamarin.Forms se adhiere a la IDataSource interfaz.
La infraestructura de Xamarin.Forms interactúa con un origen de datos a través de las siguientes propiedades:
Data : una lista de solo lectura de elementos de datos que se pueden mostrar.
IsLoading : un valor booleano que indica si los datos se cargan y están disponibles para la representación.
[key] – un indizador para recuperar elementos.
Hay dos métodos MaskKey y UnmaskKey que puede utilizarse para ocultar (o mostrar) las propiedades de
elementos de datos (es decir impida que se procesa). La clave corresponde a la una propiedad con nombre en el
objeto de elemento de datos.
Introducción a DataSourceControl
12/07/2019 • 7 minutes to read • Edit Online
descargar el ejemplo
IMPORTANT
DataSourceControl requiere un Xamarin.Forms tema referencia a representar.
Para empezar a crear una página sencilla controlada por datos mediante la versión preliminar de
DataSourceControl, siga estos pasos. Este usa demostración crea un estilo codificado de forma rígida ("eventos")
en la vista previa que sólo funciona con el formato específico de JSON en el código.
<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>
IMPORTANT
También debe seguir los pasos necesarios para cargar ensamblados de tema (abajo) agregando código estereotipado a iOS
AppDelegate y Android MainActivity . Se mejorará en versión preliminar futura.
Archivo de C#
Archivo XAML
Además de cambiar el elemento raíz para <p:ListDataPage> el espacio de nombres personalizado xmlns:p
también se debe agregar:
<ContentPage.Content></ContentPage.Content>
</p:ListDataPage>
Subclase de la aplicación
Cambiar el App constructor de clase para que la MainPage está establecido en un NavigationPage que contiene
el nuevo SessionDataPage . Una página de navegación debe usarse.
NOTE
La versión preliminar requiere un StyleClass atributo para proporcionar sugerencias de representación para el origen de
datos. El StyleClass="Events" hace referencia a un diseño que está predefinido en la vista previa y contiene los estilos
codificado de forma rígida para que coincida con el origen de datos JSON que se va a usar.
<p:ListDataPage.DataSource>
<p:JsonDataSource Source="http://demo3143189.mockable.io/sessions" />
</p:ListDataPage.DataSource>
</p:ListDataPage>
Datos JSON
Un ejemplo de los datos JSON desde el origen demostración se muestra a continuación:
[{
"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. ¡Ejecución!
Deben dar como resultado de los pasos anteriores en una página de datos de trabajo:
Esto funciona porque el estilo pregenerado "Eventos" existe en el paquete Nuget del tema claro y tiene los
estilos definidos que coinciden con el origen de datos (p ej. "title", "image", "presentador").
Los "eventos" StyleClass está diseñado para mostrar el ListDataPage control con un personalizado CardView
control que es definido en Xamarin.Forms.Pages. El CardView control tiene tres propiedades: ImageSource , Text ,
y Detail . El tema está codificado para enlazar tres campos del origen de datos (desde el archivo JSON ) a estas
propiedades para mostrarlas.
5. Personalizar
El estilo heredado puede invalidarse especificando una plantilla y usar enlaces de orígenes de datos. El XAML
siguiente declara una plantilla personalizada para cada fila con el nuevo ListItemControl y
{p:DataSourceBinding} sintaxis que se incluye en el 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>
Proporcionando un DataTemplate este código invalida el StyleClass y en su lugar, usa el diseño predeterminado
para un ListItemControl .
Los programadores que prefieren C# o XAML puede crear datos de origen enlaces demasiado (Recuerde incluir
un using Xamarin.Forms.Pages; instrucción):
Es un poco más trabajo crear temas desde el principio (vea la guía temas) pero las versiones preliminares futuras
hará esto más fácil de hacer.
Solución de problemas
No se pudo cargar el archivo o ensamblado
'Xamarin.Forms.Theme.Light' o uno de sus dependencias
En la versión preliminar, los temas no pueda cargar en tiempo de ejecución. Agregue el código que se muestra a
continuación, en los proyectos correspondientes para corregir este error.
iOS
En el AppDelegate.cs agregue las líneas siguientes después de LoadApplication
var x = typeof(Xamarin.Forms.Themes.DarkThemeResources);
x = typeof(Xamarin.Forms.Themes.LightThemeResources);
x = typeof(Xamarin.Forms.Themes.iOS.UnderlineEffect);
Android
En el MainActivity.cs agregue las líneas siguientes después de LoadApplication
var x = typeof(Xamarin.Forms.Themes.DarkThemeResources);
x = typeof(Xamarin.Forms.Themes.LightThemeResources);
x = typeof(Xamarin.Forms.Themes.Android.UnderlineEffect);
Vínculos relacionados
Ejemplo de DataPagesDemo
Xamarin.Forms DatePicker
11/07/2019 • 9 minutes to read • Edit Online
descargar el ejemplo
Una vista de Xamarin.Forms que permite al usuario seleccionar una fecha.
Xamarin.Forms DatePicker invoca el control de selector de fecha de la plataforma y permite al usuario
seleccionar una fecha. DatePicker define las propiedades de ocho:
MinimumDate de tipo , que de forma predeterminada el primer día del año 1900.
DateTime
MaximumDate de tipoDateTime , que el valor predeterminado es el último día del año 2100.
Date de tipo DateTime , la fecha seleccionada, cuyo valor predeterminado es el valor DateTime.Today .
Format de tipo string , un estándar o personalizado .NET formato de cadena, cuyo valor predeterminado es
"D", patrón de fecha largo.
TextColor de tipo Color , el color utilizado para mostrar la fecha seleccionada, cuyo valor predeterminado es
Color.Default .
FontAttributes de tipo FontAttributes , cuyo valor predeterminado es FontAtributes.None .
FontFamily de tipo string , cuyo valor predeterminado es null .
FontSize de tipo double , que de forma predeterminada va de -1,0.
WARNING
Al establecer MinimumDate y MaximumDate , asegúrese de que MinimumDate siempre es menor o igual que
MaximumDate . En caso contrario, DatePicker , se producirá una excepción.
Internamente, el DatePicker garantiza que Date entre MinimumDate y MaximumDate , ambos inclusive. Si
MinimumDate o MaximumDate se establece para que Date no está entre ellos, DatePicker ajustará el valor de
Date .
Todas las propiedades de ocho están respaldadas por BindableProperty objetos, lo que significa que puede
cambiar el estilo y las propiedades pueden ser destinos de enlaces de datos. El Date propiedad tiene un modo de
enlace predeterminada de BindingMode.TwoWay , lo que significa que puede ser un destino de enlace de datos en
una aplicación que utiliza el Model-View -ViewModel (MVVM ) arquitectura.
Cuando un DateTime se expresa en XAML, el analizador XAML usa la DateTime.Parse método con un
CultureInfo.InvariantCulture argumento para convertir la cadena en un DateTime valor. Se deben especificar las
fechas en un formato preciso: dos dígitos meses, días de dos dígitos y años de cuatro dígitos separados por barras
diagonales:
<DatePicker MinimumDate="01/01/2018"
MaximumDate="12/31/2018"
Date="06/21/2018" />
Si el BindingContext propiedad de DatePicker está establecida en una instancia de un modelo de vista que
contiene las propiedades de tipo DateTime denominado MinDate , MaxDate , y SelectedDate (por ejemplo), puede
crear una instancia el DatePicker similar a éste :
En este ejemplo, las tres propiedades se inicializan en las propiedades correspondientes en el modelo de vista.
Dado que el Date propiedad tiene un modo de enlace de TwoWay , cualquier nueva fecha que el usuario
selecciona automáticamente se refleja en el modelo de vista.
Si el DatePicker no contiene un enlace en su Date propiedad, una aplicación debe adjuntar un controlador para
el DateSelected evento para ser informado cuando el usuario selecciona una nueva fecha.
Para obtener información sobre cómo establecer las propiedades de fuente, consulte fuentes.
DatePicker y diseño
Es posible usar una opción de diseño horizontal sin restricciones, como Center , Start ,o End con DatePicker :
<DatePicker ···
HorizontalOptions="Center"
··· />
Sin embargo, esto no se recomienda. Según la configuración de la Format propiedad, selecciona las fechas
pueden requerir los anchos de pantalla diferente. Por ejemplo, hace que la cadena de formato "D" DateTime
mostrar las fechas en un formato largo y "Miércoles, 12 de septiembre de 2018" requiere un mayor ancho de
pantalla que "Viernes, 4 de mayo de 2018". Según la plataforma, esta diferencia puede provocar la DateTime vista
para cambiar el ancho de diseño o en la presentación se trunque.
TIP
Es mejor usar el valor predeterminado HorizontalOptions de Fill con DatePicker y no se debe utilizar un ancho de
Auto al poner DatePicker en un Grid celda.
<StackLayout Margin="10">
<Label Text="Days Between Dates"
Style="{DynamicResource TitleStyle}"
Margin="0, 20"
HorizontalTextAlignment="Center" />
<DatePicker x:Name="startDatePicker"
Format="D"
Margin="30, 0, 0, 30"
DateSelected="OnDateSelected" />
<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 se asigna un Format propiedad de "D" para un formato de fecha larga. Observe también que el
endDatePicker objeto tiene un enlace que tenga como destino su MinimumDate propiedad. El origen de enlace está
seleccionado Date propiedad de la startDatePicker objeto. Esto garantiza que la fecha de finalización es siempre
posterior o igual que la fecha de inicio. Además de los dos DatePicker objetos, un Switch tiene la etiqueta
"Incluyen dos días en total".
Los dos DatePicker las vistas tienen controladores asociados a la DateSelected eventos y el Switch ha
adjuntado un controlador a su Toggled eventos. Estos controladores de eventos están en el archivo de código
subyacente y desencadenan un nuevo cálculo de los días entre las dos fechas:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
void Recalculate()
{
TimeSpan timeSpan = endDatePicker.Date - startDatePicker.Date +
(includeSwitch.IsToggled ? TimeSpan.FromDays(1) : TimeSpan.Zero);
Cuando se ejecuta el ejemplo primero, ambos DatePicker vistas se inicializan en la fecha de hoy. Captura de
pantalla siguiente muestra el programa que se ejecuta en la plataforma Universal de Windows, iOS y Android:
Al puntear en cualquiera de los DatePicker muestra invoca el selector de fecha de la plataforma. Las plataformas
de implementan este selector de fecha de maneras muy diferentes, pero cada enfoque es familiar para los
usuarios de esa plataforma:
TIP
En Android, el DatePicker cuadro de diálogo se puede personalizar invalidando el CreateDatePickerDialog método en
un representador personalizado. Esto permite, por ejemplo, botones adicionales que se agregan al cuadro de diálogo.
Una vez seleccionadas las dos fechas, la aplicación muestra el número de días entre esas fechas:
Vínculos relacionados
Ejemplo de DaysBetweenDates
DatePicker API
Mostrar elementos emergentes
11/07/2019 • 3 minutes to read • Edit Online
descargar el ejemplo
Xamarin.Forms proporciona dos elementos de la interfaz de usuario similares a elementos emergentes: una alerta
y una hoja de acción. En este artículo muestra cómo utilizar la hoja de las API de alerta y la acción para mostrar
cuadros de diálogo que pedir a los usuarios preguntas sencillas y guiar a los usuarios a través de tareas.
Mostrar una alerta o pedir al usuario que seleccione una opción es una tarea común de la interfaz de usuario.
Xamarin.Forms tiene dos métodos en la clase Page para interactuar con el usuario mediante un elemento
emergente: DisplayAlert y DisplayActionSheet . Se representan con controles nativos adecuados en cada
plataforma.
En este ejemplo, no se recopila información del usuario. La alerta se muestra modalmente y, después de cerrarla, el
usuario sigue interactuando con la aplicación.
El método DisplayAlert también se puede usar para capturar la respuesta de un usuario mediante la presentación
de dos botones y la devolución de un elemento boolean . Para obtener una respuesta de una alerta, agregue texto
para los dos botones y use await para esperar el método. Cuando el usuario seleccione una de las opciones, se
devolverá la respuesta al código. Observe las palabras clave async y await en el código de ejemplo siguiente:
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);
}
El botón destroy se representa de forma distinta y puede dejarse como null , o bien se puede especificar como el
tercer parámetro de cadena. En el ejemplo siguiente, se usa el botón destroy :
descargar el ejemplo
Uso SkiaSharp para gráficos 2D en las aplicaciones de Xamarin.Forms
SkiaSharp es un sistema de gráficos 2D para .NET y C# funciona con el motor de gráficos de Skia de código
abierto que se usa habitualmente en productos de Google. Puede usar SkiaSharp en sus aplicaciones de
Xamarin.Forms para dibujar texto, mapas de bits y gráficos vectoriales en 2D. Consulte la plano 2D guía para
obtener información general sobre la biblioteca de SkiaSharp y algunos otros tutoriales.
En esta guía se da por supuesto que está familiarizado con la programación de Xamarin.Forms.
IMPORTANT
El SkiaSharp.Views.Forms espacio de nombres también contiene un SKGLView clase que derive de View pero usa
OpenGL para representar gráficos. Para fines de simplicidad, esta guía restringe a sí mismo a SKCanvasView , pero al usar
SKGLView en su lugar, es bastante similar.
Transformaciones de SkiaSharp
Las transformaciones permiten que los objetos gráficos uniformemente traducido, escalar, girar, o sesgar.En este
artículo también muestra cómo puede utilizar una matriz de transformación de 3 por 3 estándar para crear
transformaciones no afines y aplicar transformaciones a rutas de acceso.
Efectos de SkiaSharp
Los efectos son propiedades que cambian la visualización de gráficos, incluidos los degradados lineales y circulares
normal, disposición en mosaico de mapa de bits, blend modos de desenfoque y otros usuarios.
Vínculos relacionados
API de SkiaSharp
SkiaSharpFormsDemos (ejemplo)
SkiaSharp con Xamarin.Forms seminario Web (vídeo)
Imágenes en Xamarin.Forms
11/07/2019 • 24 minutes to read • Edit Online
descargar el ejemplo
Las imágenes se pueden compartir entre plataformas con Xamarin.Forms, se pueden cargar específicamente
para cada plataforma, o se pueden descargar para su presentación.
Las imágenes son una parte fundamental de navegación de la aplicación, la facilidad de uso y la personalización
de marca. Las aplicaciones de Xamarin.Forms deben ser capaz de compartir imágenes en todas las plataformas,
pero también puede mostrar diferentes imágenes en cada plataforma.
También se requieren para iconos y pantallas de presentación; las imágenes específicas de plataforma estas
deben configurarse según el acuerdo con la plataforma.
Mostrar imágenes
Xamarin.Forms usa el Image vista para mostrar imágenes en una página. Tiene dos propiedades importantes:
Source -Un ImageSource instancia, archivo, Uri o recurso, que establece la imagen para mostrar.
Aspect -Cómo cambiar el tamaño de la imagen dentro de los límites que se muestra dentro de (ya sea para
stretch, recortar o panorámica).
ImageSource las instancias pueden obtenerse mediante métodos estáticos para cada tipo de origen de la imagen:
FromFile -Requiere un nombre de archivo o ruta del archivo que se puede resolver en cada plataforma.
FromUri -Requiere un objeto Uri, por ejemplo. new Uri("http://server.com/image.jpg") .
FromResource -Requiere un identificador de recurso a un archivo de imagen incrustado en la aplicación o el
proyecto de biblioteca de .NET Standard con un EmbeddedResource: acción de compilación.
FromStream -Requiere un flujo que proporciona los datos de imagen.
Imágenes locales
Archivos de imagen se pueden agregar a cada proyecto de aplicación y hacer referencia desde el código de
Xamarin.Forms compartido. Este método de distribución de imágenes es necesaria cuando las imágenes son
específicos de la plataforma, como al usar distintas resoluciones en distintas plataformas o ligeramente distintos
diseños.
Para usar una imagen única en todas las aplicaciones, se debe usar el mismo nombre de archivo en todas las
plataformas, y debe ser un nombre de recurso de Android válido (es decir. se permiten solo letras minúsculas,
números, el carácter de subrayado y el período).
iOS : la preferida en forma de administrar y admitir imágenes, ya que es usar iOS 9 conjuntos de
imágenes del catálogo de activos, que debe contener todas las versiones de una imagen que son
necesarias para admitir varios dispositivos y factores de escala de un aplicación. Para obtener más
información, consulte agregar imágenes a un conjunto de imágenes de catálogo de activos.
Android -colocar imágenes en el recursos/drawable directorio con acción de compilación:
AndroidResource. También se pueden proporcionar versiones de alta y baja resolución de una imagen (en
un nombre apropiado recursos subdirectorios como drawable ldpi, drawable-hdpiy drawable xhdpi).
Plataforma universal de Windows (UWP ) -colocar imágenes en el directorio raíz de la aplicación con
acción de compilación: Contenido.
IMPORTANT
Antes de iOS 9, las imágenes normalmente se colocaron en el recursos carpeta con acción de compilación:
BundleResource. Sin embargo, este método para trabajar con imágenes en una aplicación de iOS en desuso por Apple.
Para obtener más información, consulte tamaños de imagen y nombres de archivo.
Adhesión a estas reglas de nomenclatura de los archivos y la colocación permite el XAML cargar y mostrar la
imagen en todas las plataformas siguiente:
Las capturas de pantalla siguientes muestran el resultado de mostrar una imagen local en cada plataforma:
Para obtener más flexibilidad el Device.RuntimePlatform propiedad puede utilizarse para seleccionar un archivo
de imagen diferente o la ruta de acceso para algunas o todas las plataformas, como se muestra en este ejemplo
de código:
Los nombres de archivo de imagen UWP puede tener el sufijo con .scale-xxx antes de la extensión de archivo,
donde xxx es el porcentaje de ajuste de escala aplicado al recurso, por ejemplo, myimage.scale 200.png. A
continuación, se pueden hacer referencia de las imágenes en el código o XAML sin el modificador de escala, por
ejemplo, simplemente myimage.png. La plataforma seleccionará la escala de activos correspondiente más
cercana en función de PPP de la pantalla actual.
Controles adicionales que se muestran las imágenes
Algunos controles tienen propiedades que se muestran una imagen, como:
Page -Cualquier tipo que derive de la página Page tiene IconImageSource y BackgroundImageSource
propiedades, que se pueden asignar un archivo, el recurso incrustado, el URI o la secuencia. En
determinadas circunstancias, como cuando un NavigationPage está mostrando un ContentPage , si es
compatible con la plataforma, se mostrará el icono.
IMPORTANT
En iOS, el Page.IconImageSource no se pueden rellenar la propiedad desde una imagen en un conjunto de
imágenes del catálogo activo. En su lugar, cargue las imágenes de icono para el Page.IconImageSource
propiedad desde un archivo, el recurso incrustado, el URI o la secuencia.
ToolbarItem -Tiene un IconImageSource propiedad que se puede establecer en una imagen que se carga
desde un archivo, el recurso incrustado, el URI o la secuencia.
ImageCell -Tiene un ImageSource recupera de la propiedad que se puede establecer en una imagen
desde un archivo, el recurso incrustado, el URI o la secuencia.
Imágenes incrustadas
También se incluyen imágenes incrustadas con una aplicación (por ejemplo, imágenes locales), pero en lugar de
tener una copia de la imagen en la estructura de archivos de la aplicación la imagen de archivo está incrustado
en el ensamblado como un recurso. Este método para distribuir las imágenes se recomienda cuando se usan
imágenes idénticas en cada plataforma y es especialmente adecuado para la creación de componentes, como la
imagen se incluye con el código.
Para incrustar una imagen en un proyecto, haga doble clic para agregar nuevos elementos y seleccione la
imagen/s que desea agregar. De forma predeterminada la imagen tendrá acción de compilación: Ninguno;
Esto se debe establecerse en acción de compilación: EmbeddedResource.
Visual Studio
Visual Studio para Mac
El acción de compilación se pueden ver y cambiar en el propiedades ventana para un archivo.
En este ejemplo es el identificador de recurso WorkingWithImages.beach.jpg. El IDE ha generado este
comportamiento predeterminado mediante la concatenación del predeterminada Namespace para este
proyecto con el nombre de archivo, con un punto (.) entre cada valor.
Si coloca las imágenes incrustadas en carpetas dentro de su proyecto, los nombres de carpeta también están
separados por puntos (.) en el identificador de recurso. Mover el beach.jpg la imagen en una carpeta
denominada MyImages daría lugar a un identificador de recurso de
WorkingWithImages.MyImages.beach.jpg
El código para cargar una imagen incrustada simplemente pasa el Id. de recurso a la ImageSource.FromResource
método tal y como se muestra a continuación:
NOTE
Para admitir mostrar imágenes incrustadas en modo de versión en la plataforma Universal de Windows, es necesario
utilizar la sobrecarga de ImageSource.FromResource que especifica el ensamblado de origen en el que se va a buscar la
imagen.
Actualmente no hay ninguna conversión implícita de los identificadores de recursos. En su lugar, debe usar
ImageSource.FromResource o new ResourceImageSource() para cargar imágenes incrustadas.
Las capturas de pantalla siguientes muestran el resultado de mostrar una imagen incrustada en cada plataforma:
Uso de XAML
Porque no hay ningún convertidor de tipos integrados de string a ResourceImageSource , estos tipos de
imágenes no se puede cargar de forma nativa por XAML. En su lugar, se puede escribir una extensión de
marcado XAML personalizada simple para cargar imágenes mediante un Id. de recurso especificado en XAML:
[ContentProperty (nameof(Source))]
public class ImageResourceExtension : IMarkupExtension
{
public string Source { get; set; }
return imageSource;
}
}
NOTE
Para admitir mostrar imágenes incrustadas en modo de versión en la plataforma Universal de Windows, es necesario
utilizar la sobrecarga de ImageSource.FromResource que especifica el ensamblado de origen en el que se va a buscar la
imagen.
Para usar esta extensión agregar personalizada xmlns para el XAML, con los valores de espacio de nombres y
ensamblado correctos para el proyecto. A continuación, se puede establecer el origen de imagen con esta
sintaxis: {local:ImageResource WorkingWithImages.beach.jpg} . Un ejemplo completo de XAML se muestra a
continuación:
<?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>
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);
}
Descarga de imágenes
Las imágenes se pueden descargar automáticamente para su presentación, como se muestra en el XAML
siguiente:
El ImageSource.FromUri método requiere un Uri de objetos y devuelve un nuevo UriImageSource que lee el
Uri .
También hay una conversión implícita de cadenas URI, por lo que también funcionará en el ejemplo siguiente:
webImage.Source = "https://xamarin.com/content/images/pages/forms/example-app.png";
Las capturas de pantalla siguientes muestran el resultado de mostrar una imagen remota en cada plataforma:
Almacenamiento en caché está habilitado de forma predeterminada y almacenará la imagen localmente durante
24 horas. Para deshabilitar el almacenamiento en caché para una imagen concreta, crear una instancia del origen
de la imagen como sigue:
Para establecer un período de caché específica (por ejemplo, 5 días) crear una instancia del origen de la imagen
como sigue:
Almacenamiento en caché integrado facilita enormemente admitir escenarios como el desplazamiento de las
listas de imágenes, donde puede establecer (o enlazar) una imagen en cada celda y dejar que la memoria caché
integrada se encargue de volver a cargar la imagen cuando se desplaza por la celda en la vista.
Iconos y pantallas de presentación
Aunque no se refiere a la Image vista, los iconos de aplicación y pantallas de presentación también son un uso
importante de las imágenes en proyectos de Xamarin.Forms.
Establecer iconos y pantallas de presentación de las aplicaciones de Xamarin.Forms se realiza en cada uno de los
proyectos de aplicación. Esto significa generar correctamente un tamaño de imágenes para iOS, Android y
UWP. Estas imágenes deben ser llamadas y encuentra según los requisitos de cada las plataformas.
Iconos
Consulte la iOS trabajar con imágenes, Google iconografía, y directrices para los recursos de icono y el icono
para obtener más información sobre cómo crear estos recursos de la aplicación.
Además, pueden mostrar iconos de la fuente del Image vista mediante la especificación de los datos del icono
de fuente en un FontImageSource objeto. Para obtener más información, consulte mostrar iconos de fuente en el
fuentes guía.
Pantallas de presentación
Solo aplicaciones de iOS y UWP requieren una pantalla de presentación (también denominada una imagen de
pantalla o el valor predeterminado de inicio).
Consulte la documentación para iOS trabajar con imágenes y pantallas de presentación en el centro de
desarrollo de Windows.
Resumen
Xamarin.Forms ofrece una serie de diferentes maneras de incluir imágenes en una aplicación multiplataforma, lo
que permite para la misma imagen que se usará en las plataformas o para las imágenes específicas de la
plataforma que se especifique. Imágenes descargadas son también automáticamente en caché, automatizar un
escenario de codificación comunes.
Imágenes de pantalla de presentación y de icono de aplicación están configurados y configurado en cuanto a las
aplicaciones que no sean Xamarin.Forms - sigan las mismas instrucciones que se usa para las aplicaciones
específicas de la plataforma.
Vínculos relacionados
WorkingWithImages (ejemplo)
iOS trabajar con imágenes
Iconografía Android
Directrices para los recursos de icono y el icono
Xamarin.Forms ImageButton
11/07/2019 • 11 minutes to read • Edit Online
descargar el ejemplo
El ImageButton muestra una imagen y responde a un pulse o haga clic en que se dirige a una aplicación para
llevar a cabo una tarea determinada.
El ImageButton ver combina el Button vista y Image vista para crear un botón cuyo contenido es una imagen. El
usuario presiona el ImageButton con un dedo o hace clic en él con el mouse para dirigir la aplicación para llevar a
cabo una tarea determinada. Sin embargo, a diferencia del Button vista, la ImageButton vista no tiene ningún
concepto de texto y la apariencia del texto.
NOTE
Mientras el Button vista define un Image propiedad, que permite mostrar una imagen en el Button , esta propiedad
está pensada para utilizarse cuando se muestra un icono pequeño junto a la Button texto.
<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>
El Source propiedad especifica la imagen que aparece en el ImageButton . En este ejemplo se establece en un
archivo local que se cargarán de cada proyecto de plataforma, lo que resulta en las capturas de pantalla siguiente:
De forma predeterminada, el ImageButton es rectangular, pero puede dar TI redondeada esquinas mediante el
CornerRadius propiedad. Para obtener más información acerca de ImageButton apariencia, consulte ImageButton
apariencia.
El ejemplo siguiente muestra cómo crear una página que es funcionalmente equivalente al ejemplo XAML
anterior, pero en su totalidad C#:
<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>
public ImageButtonDemoPage()
{
InitializeComponent();
}
public ImageButtonDemoPage()
{
Label header = new Label
{
Text = "ImageButton",
FontSize = 50,
FontAttributes = FontAttributes.Bold,
HorizontalOptions = LayoutOptions.Center
};
Deshabilitar el ImageButton
A veces, una aplicación está en un estado determinado donde un determinado ImageButton haga clic en no es
una operación válida. En esos casos, el ImageButton debe deshabilitarse estableciendo su IsEnabled propiedad
false .
Este enfoque es adecuado en relación con el enlace de datos y especialmente al implementar la arquitectura
Model-View -ViewModel (MVVM ).
Para obtener más información sobre el uso de la interfaz de comandos, consulte mediante la interfaz de
comandos en el botón guía.
Para obtener más información acerca de estos eventos, vea presionando y soltando el botón en el botón guía.
Apariencia ImageButton
Además de las propiedades que ImageButton hereda el View (clase), ImageButton también define varias
propiedades que afectan a su apariencia:
Aspect es cómo la imagen se ajustarán el área de presentación.
BorderColor es el color de un área que rodea el ImageButton .
BorderWidth es el ancho del borde.
CornerRadius es el radio de redondeo de la ImageButton .
NOTE
El ImageButton clase también tiene Margin y Padding las propiedades que controlan el comportamiento de diseño de
la ImageButton . Para obtener más información, consulte margen y relleno.
<VisualState x:Name="Pressed">
<VisualState.Setters>
<Setter Property="Scale"
Value="0.8" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</ImageButton>
El Pressed VisualState especifica que, cuando el ImageButton está presionado, su Scale se cambiará la
propiedad de su valor predeterminado de 1 a 0,8. El Normal VisualState especifica que, cuando el ImageButton
está en estado normal, su Scale propiedad se establecerá en 1. Por lo tanto, el efecto general es que cuando el
ImageButton está presionado, se vuelve a escalar para que sea ligeramente más pequeñas pero cuando el
ImageButton está publicado, se escalan a su tamaño predeterminado.
Para obtener más información acerca de los estados visuales, vea Xamarin.Forms Visual State Manager.
Vínculos relacionados
Ejemplo de FormsGallery
Diseños de Xamarin.Forms
11/07/2019 • 16 minutes to read • Edit Online
descargar el ejemplo
Xamarin.Forms tiene varios diseños y características para organizar el contenido en pantalla.
Para obtener un ejemplo de cuándo StackLayout podría ser una buena opción, considere la posibilidad de una
aplicación que necesita para mostrar un botón y una etiqueta, con la etiqueta que se alinea a la izquierda y el
botón alineado a la derecha.
<StackLayout Orientation="Horizontal">
<Label HorizontalOptions="StartAndExpand" Text="Label" />
<Button HorizontalOptions="End" Text="Button" />
</StackLayout>
FlexLayout
El FlexLayout es similar a StackLayout que muestra vistas secundarias horizontal o verticalmente:
<FlexLayout Direction="Column"
AlignItems="Center"
JustifyContent="SpaceEvenly">
Sin embargo, si hay demasiados elementos secundarios para que quepa en una sola fila o columna propio,
FlexLayout también es capaz de ajuste de esas vistas. FlexLayout se basa en el módulo de diseño CSS cuadro
Flexible y tiene muchas de las mismas opciones integradas para colocar y alinear a sus elementos secundarios.
AbsoluteLayout
El AbsoluteLayout se utiliza para mostrar las vistas, con el tamaño y posición que se va a especificar como valores
explícitos o en relación con el tamaño del diseño. A diferencia de StackLayout y Grid , AbsoluteLayout permite
secundarios vistas se superponen. A diferencia de RelativeLayout , AbsoluteLayout no le permite colocar los
elementos fuera de la pantalla.
Para obtener un ejemplo de cuándo AbsoluteLayout podría ser una buena opción, considere la posibilidad de una
aplicación que necesita para presentar las colecciones de objetos como pilas. Esto suele aparecer cuando se
presentan los álbumes de fotografías o canciones. El código siguiente proporciona la apariencia de una pila, con
elementos girados para sugerir el contenido de la pila:
En 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>
RelativeLayout
El RelativeLayout se utiliza para mostrar las vistas, con el tamaño y posición especificados como valores en
relación con los valores de la distribución o en otra vista. Valores relativos no es necesario para que coincida con la
que corresponde el valor en la vista relacionada. Por ejemplo, es posible establecer una vista Width propiedad sea
proporcional a otra vista X propiedad.
RelativeLayout se puede usar para crear interfaces de usuario que se escalan de forma proporcional entre
tamaños de los dispositivos. El XAML siguiente implementa un diseño con los cuadros en las esquinas superiores,
con un asta de la bandera con la marca en el centro:
<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="<-" Grid.Row="3" Grid.Column="2" />
</Grid>
Vínculos relacionados
Directrices de interfaz humana de Apple
Sitio Web de diseño de Android
Diseño (ejemplo)
Ejemplo de BusinessTumble (ejemplo)
Xamarin.Forms StackLayout
11/07/2019 • 6 minutes to read • Edit Online
descargar el ejemplo
StackLayout organiza las vistas en una línea unidimensional ("pila"), ya sea horizontal o verticalmente. Las vistas
en un StackLayout puede ajustarse según el espacio en el diseño mediante las opciones de diseño. Posición viene
determinada por el orden en que se agregaron las vistas en el diseño y las opciones de diseño de las vistas.
Propósito
StackLayout es menos complejo que otras vistas. Se pueden crear interfaces lineales simple con solo agregar
vistas a un StackLayout y las interfaces más complejas creadas por anidarlos.
En 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;
}
}
Espaciado = 0:
Espaciado de diez:
Ajuste de tamaño
El tamaño de una vista en un StackLayout depende de las solicitudes de alto y ancho y las opciones de diseño.
StackLayout aplicará el relleno. La siguiente LayoutOption s hará que las vistas a ocupar espacio está disponible
en el diseño:
CenterAndExpand – centra la vista dentro del diseño y se expande para ocupar espacio le asignará el diseño.
EndAndExpand – coloca la vista al final del diseño (inferior o límite más a la derecha) y se expande para
ocupar espacio le asignará el diseño.
FillAndExpand – coloca la vista para que no tiene relleno y ocupa espacio le asignará el diseño.
StartAndExpand – coloca la vista al principio del diseño y ocupa espacio proporcionará el elemento primario.
Para obtener más información, consulte expansión.
Posición
Se pueden colocar y tamaño utilizando vistas en un StackLayout LayoutOptions . Cada vista puede
proporcionarse VerticalOptions y HorizontalOptions , define cómo las vistas se posicionan en relación con el
diseño. Siguiente predefinidos LayoutOptions están disponibles:
Centro de – centra la vista dentro del diseño.
End – coloca la vista al final del diseño (inferior o límite más a la derecha).
Rellenar – coloca la vista para que no tenga ningún relleno.
Iniciar – coloca la vista al principio del diseño.
El código siguiente muestra cómo establecer las opciones de diseño:
En 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>
En C#:
layout.Children.Add(button);
layout.Children.Add(oneBox);
layout.Children.Add(twoBox);
layout.Children.Add(threeBox);
Content = layout;
}
}
Vínculos relacionados
LayoutOptions
Diseño (ejemplo)
Ejemplo de BusinessTumble (ejemplo)
Xamarin.Forms AbsoluteLayout
11/07/2019 • 13 minutes to read • Edit Online
descargar el ejemplo
AbsoluteLayout coloca y ajusta el tamaño de los elementos secundarios proporcionales a su propio tamaño y
posición o por valores absolutos. Pueden ser vistas secundarias posición y tamaño utilizando valores
proporcionales o valores estáticos y proporcional y se pueden combinar los valores estáticos.
Propósito
Debido al modelo de posicionamiento de AbsoluteLayout , el diseño resulta relativamente sencilla colocar los
elementos para que sean vaciado con cualquier lado del diseño o centrada. Con las posiciones y tamaños
proporcionales, los elementos en un AbsoluteLayout puede escalar automáticamente a cualquier tamaño de la
vista. Para los elementos que debe escalarse sólo la posición, pero no el tamaño, se pueden combinar valores
proporcionales y absolutos.
AbsoluteLayout se puede usar cualquier parte los elementos se deben colocar dentro de una vista y es
especialmente útil cuando se alinean elementos a los bordes.
Uso
Diseños proporcionales
AbsoluteLayout tiene un modelo de delimitador único mediante el cual se coloca el delimitador del elemento
respecto a su elemento como el elemento se coloca en relación con el diseño cuando se usa el posicionamiento
proporcional. Cuando se usa el posicionamiento absoluto, el delimitador se encuentra en (0,0) en la vista. Esto
tiene dos consecuencias importantes:
No se puede colocar elementos fuera de la pantalla con los valores proporcionales.
Los elementos se pueden colocar de forma confiable en cualquier parte del diseño o en el centro,
independientemente del tamaño de la distribución o el dispositivo.
AbsoluteLayout , como RelativeLayout , puede colocar los elementos de forma que se superpongan.
Tenga en cuenta en la siguiente captura de pantalla, el delimitador del cuadro es un punto blanco. Tenga en
cuenta la relación entre el delimitador y el cuadro de medida que avanza el diseño:
Especificar valores
Vistas dentro de un AbsoluteLayout se sitúan mediante cuatro valores:
X – la posición de x (horizontal) del delimitador de la vista
Y – la posición y (vertical) del delimitador de la vista
Ancho – el ancho de la vista
Alto – el alto de la vista
Cada uno de estos valores puede establecerse como un proporcional valor o una absoluta valor.
Los valores se especifican como una combinación de los límites y una marca. LayoutBounds es un Rectangle que
consta de cuatro valores: x , y , width , height .
AbsoluteLayoutFlags
AbsoluteLayoutFlags Especifica cómo se interpretará los valores y tiene las siguientes opciones predefinidas:
Ninguno – interpreta todos los valores como un absoluto. Este es el valor predeterminado si no se especifica
ninguna marca de diseño.
Todos los – interpreta todos los valores como proporcional.
WidthProportional – interpreta el Width valor como proporcional y todos los demás valores como un
absoluto.
HeightProportional – interpreta solo el valor del alto como proporcional con todos los demás valores
absolutos.
XProportional – interpreta el X valor como proporcional, mientras que todos los demás valores como un
absoluto.
YProportional – interpreta el Y valor como proporcional, mientras que todos los demás valores como un
absoluto.
PositionProportional – interpreta el X y Y valores proporcionales, mientras que los valores de tamaño se
interpretan como un absoluto.
SizeProportional – interpreta el Width y Height valores proporcionales mientras que los valores de
posición son absolutos.
En XAML, límites y las marcas se establecen como parte de la definición de vistas en el diseño, utilizando el
AbsoluteLayout.LayoutBounds propiedad. Los límites se establecen como una lista separada por comas de valores,
X , Y , Width , y Height , en ese orden. También se especifican en la declaración de vistas en el diseño mediante
el AbsoluteLayout.LayoutFlags propiedad. Tenga en cuenta que se pueden combinar flags en XAML mediante
una lista separada por comas. Considere el ejemplo siguiente:
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);
layout.Children.Add (bottomLabel);
layout.Children.Add (centerLabel);
layout.Children.Add (rightBox);
layout.Children.Add (leftBox);
layout.Children.Add (topBox);
Content = layout;
}
}
Valores proporcionales
Valores proporcionales definen una relación entre un diseño y una vista. Esta relación define la posición o el valor
de escala de una vista secundaria como una proporción del valor correspondiente del diseño del elemento
primario. Estos valores se expresan como double s con valores comprendidos entre 0 y 1.
Se usan valores proporcionales a la posición y las vistas de tamaño en el diseño. Por lo tanto, cuando se establece
el ancho de la vista como una proporción, el valor del ancho resultante es la proporción multiplicada por el
AbsoluteLayout del ancho. Por ejemplo, con un AbsoluteLayout del ancho 500 y una vista que define para tener
un ancho proporcional de.5, el ancho representado de la vista será 250 (500 x.5.
Para usar valores proporcionales, establezca LayoutBounds utilizando (x, y) proporciones y tamaños
proporcionales, a continuación, establezca LayoutFlags a All .
En XAML:
En 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 explícitamente dónde deben situarse vistas dentro del diseño. A diferencia de los
valores proporcionales, valores absolutos son capaces de posicionar y ajustar el tamaño de una vista que no cabe
dentro de los límites del diseño.
Use valores absolutos para el posicionamiento puede ser peligroso cuando no se conoce el tamaño del diseño. Al
usar posiciones absolutas, se puede desplazar un elemento en el centro de la pantalla con un tamaño en
cualquier otro tamaño. Es importante probar la aplicación a través de los distintos tamaños de pantalla de los
dispositivos compatibles.
Para usar los valores de diseño absoluto, establezca LayoutBounds utilizando (x, y) coordenadas y los tamaños
explícitos, a continuación, establezca LayoutFlags a None .
En XAML:
En 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));
Vínculos relacionados
Creación de aplicaciones móviles con Xamarin.Forms, capítulo 14
AbsoluteLayout
Diseño (ejemplo)
Ejemplo de BusinessTumble (ejemplo)
Xamarin.Forms RelativeLayout
11/07/2019 • 8 minutes to read • Edit Online
descargar el ejemplo
RelativeLayout se usa para la posición y las vistas de tamaño en relación con las propiedades de las vistas de
diseño o del mismo nivel. A diferencia de AbsoluteLayout , RelativeLayout no tiene el concepto del anclaje móvil
y no tiene medios para colocar elementos en relación con la parte inferior o el borde derecho del diseño.
RelativeLayout es compatible con elementos de posición fuera de sus propios límites.
Propósito
RelativeLayout puede utilizarse para colocar las vistas en pantalla en relación con el diseño general o a otras
vistas.
Uso
Restricciones de descripción
Posición y cambio de tamaño de una vista en un RelativeLayout se realiza con las restricciones. Una expresión
de restricción puede incluir la siguiente información:
Tipo – si la restricción es relativo al elemento primario o a otra vista.
Propiedad – qué propiedad desea usar como base para la restricción.
Factor – el factor que se aplican al valor de propiedad.
Constante – el valor que se usará como un desplazamiento del valor.
ElementName – el nombre de la vista que es relativa la restricción.
En XAML, las restricciones se expresan como ConstraintExpression s. Considere el ejemplo siguiente:
En C#, las restricciones se expresan en forma un poco diferente, con funciones en lugar de expresiones en la vista.
Las restricciones se especifican como argumentos para el diseño Add método:
NOTE
Debido al modo en que se definen las restricciones, es posible hacer que los diseños más complejos en C# que se pueden
especificar con XAML.
Los dos ejemplos anteriores definen restricciones como RelativeToParent – es decir, sus valores son en relación
con el elemento primario. También es posible definir restricciones en relación con otra vista. Esto permite diseños
más intuitivos (para el desarrollador) y puede hacer que la intención del código de diseño más evidentes.
Considere la posibilidad de un diseño donde un elemento debe ser menores que el otro 20 píxeles. Si ambos
elementos se definen con valores constantes, menor será podría tener su Y restricción definida como una
constante que es mayores que 20 píxeles el Y puede tomar el elemento superior. Este enfoque no es suficiente si
el elemento superior se coloca con una proporción, por lo que no se conoce el tamaño de píxel. En ese caso, es
más estable restringiendo el elemento basado en la posición de otro elemento:
<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>
Esto genera el siguiente resultado, con la posición del cuadro azul determinada relativa a la posición del cuadro
rojo:
Ajuste de tamaño
Vistas planteados por RelativeLayout tiene dos opciones para especificar su tamaño:
HeightRequest & WidthRequest
RelativeLayout.WidthConstraint & RelativeLayout.HeightConstraint
HeightRequest y WidthRequest especifican el alto deseado y el ancho de la vista, pero pueden ser invalidadas por
los diseños según sea necesario. WidthConstraint y HeightConstraint admite establecer el alto y ancho como un
valor en relación con el diseño o en otra vista Propiedades, o como un valor constante.
Vínculos relacionados
Diseño (ejemplo)
Ejemplo de BusinessTumble (ejemplo)
Cuadrícula de Xamarin.Forms
11/07/2019 • 16 minutes to read • Edit Online
descargar el ejemplo
Grid permite organizar las vistas en filas y columnas. Las filas y columnas se pueden establecer para tener
tamaños proporcionales o tamaños absolutos. El Grid diseño no debe confundirse con las tablas tradicionales y
no está diseñada para presentar los datos tabulares. Grid no tiene el concepto de fila, columna o formato de
celdas. A diferencia de las tablas HTML, Grid está pensado únicamente para diseño de contenido.
Uso
A diferencia de las tablas tradicionales, Grid no infiere el número y tamaño de filas y columnas del contenido. En
su lugar, Grid tiene RowDefinitions y ColumnDefinitions colecciones. Éstos contienen las definiciones de
dispuestos cuántas filas y columnas. Las vistas se agregan a Grid con la fila especificada y los índices de
columnas, que identifican qué fila y columna que se debe colocar en una vista.
Las filas y columnas
Información de fila y columna se almacena en Grid del RowDefinitions & ColumnDefinitions propiedades, que
son colecciones de cada de RowDefinition y ColumnDefinition objetos, respectivamente. RowDefinition tiene una
propiedad única, Height , y ColumnDefinition tiene una propiedad única, Width . Las opciones de alto y ancho
son los siguientes:
Auto – automáticamente los tamaños para ajustar el contenido de la fila o columna. Especificado como
GridUnitType.Auto en C# o como Auto en XAML.
Proportional(*) – cambia el tamaño de filas y columnas como una proporción del espacio restante.
Especificado como un valor y GridUnitType.Star en C# y como #* en XAML, con # que el valor deseado.
Especificación de una fila o columna con * hará que se va a rellenar el espacio disponible.
Absoluta – tamaños de las columnas y filas con valores específicos de alto y ancho fijos. Especificado como un
valor y GridUnitType.Absolute en C# y como # en XAML, con # que el valor deseado.
NOTE
Los valores de ancho para las columnas se establecen como * de forma predeterminada en Xamarin.Forms, lo que
garantiza que la columna rellenará el espacio disponible. También se establecen los valores del alto para las filas como * de
forma predeterminada.
Considere la posibilidad de una aplicación que necesita tres filas y dos columnas. La fila inferior debe ser
exactamente 200px alto y la fila superior debe ser dos veces más alto que la fila central. La columna izquierda
debe ser lo suficientemente ancho como para que quepa el contenido y la columna derecha debe rellenar el
espacio restante.
En XAML:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*" />
<RowDefinition Height="*" />
<RowDefinition Height="200" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid>
En C#:
<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>
En C#:
var grid = new Grid();
grid.Children.Add(topLeft, 0, 0);
grid.Children.Add(topRight, 1, 0);
grid.Children.Add(bottomLeft, 0, 1);
grid.Children.Add(bottomRight, 1, 1);
El código anterior crea la cuadrícula con cuatro etiquetas, dos columnas y dos filas. Tenga en cuenta que cada
etiqueta tendrá el mismo tamaño y que las filas se expandirán para usar todo el espacio disponible.
En el ejemplo anterior, las vistas se agregan a la Grid.Children colección utilizando el Add sobrecarga que
especifique los argumentos izquierdo y superiores. Cuando se usa el Add sobrecarga que especifique a la
izquierda, derecha, superior y argumentos de la parte inferior, mientras la izquierda y argumentos superiores
siempre hará referencia a las celdas de la Grid , la derecha y argumentos de la parte inferior pueden parecer que
hacen referencia a las celdas que están fuera de la Grid . Esto es porque el argumento derecho siempre debe ser
mayor que el argumento izquierdo y el argumento final siempre debe ser mayor que el argumento superior. En el
ejemplo siguiente se muestra código equivalente que utiliza ambos 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);
Espaciado
Grid tiene propiedades para controlar el espaciado entre las filas y columnas. Las propiedades siguientes están
disponibles para personalizar el Grid :
ColumnSpacing – la cantidad de espacio entre las columnas. El valor predeterminado de esta propiedad es 6.
RowSpacing – la cantidad de espacio entre las filas. El valor predeterminado de esta propiedad es 6.
El XAML siguiente especifica un Grid con dos columnas, una fila y 5 px de espaciado entre columnas:
<Grid ColumnSpacing="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid>
En 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
A menudo cuando se trabaja con una cuadrícula, hay un elemento que debe ocupar más de una fila o columna.
Considere la posibilidad de una aplicación de calculadora simple:
Tenga en cuenta que el botón 0 abarca dos columnas, al igual que las calculadoras integradas para cada
plataforma. Esto se logra mediante el ColumnSpan propiedad, que especifica cuántas columnas un elemento deben
ocupar. El XAML para ese botón:
Y en C#:
Tenga en cuenta que en el código, los métodos estáticos de la Grid clase se utilizan para realizar cambios de
posicionamiento, incluidos los cambios a ColumnSpan y RowSpan . Tenga en cuenta que, con otras propiedades que
se pueden establecer en cualquier momento, a diferencia de las propiedades establecidas mediante los métodos
estáticos en ya deben puede estar también en la cuadrícula antes de modificarla.
El XAML completo para la aplicación de calculadora anterior es como sigue:
<?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 la etiqueta en la parte superior de la cuadrícula y el botón cero occuping más de una columna.
Aunque se podría lograr un diseño similar con cuadrículas anidadas, la ColumnSpan & RowSpan enfoque es más
sencillo.
La implementación de C#:
public CalculatorGridCode ()
{
Title = "Calculator - C#";
BackgroundColor = Color.FromHex ("#404040");
Content = controlGrid;
}
Vínculos relacionados
Creación de aplicaciones móviles con Xamarin.Forms, capítulo 17
Grid
Diseño (ejemplo)
Ejemplo de BusinessTumble (ejemplo)
El Xamarin.Forms FlexLayout
11/07/2019 • 43 minutes to read • Edit Online
descargar el ejemplo
Utilice FlexLayout para apilar o encapsula una colección de vistas secundarias.
Xamarin.Forms FlexLayout es nuevo en la versión 3.0 de Xamarin.Forms. Se basa en la hoja CSS Flexible diseño
módulo, normalmente conocido como flex diseño o flex cuadro, se denomina así porque incluye muchas opciones
flexibles para organizar los elementos secundarios en el diseño.
FlexLayout es similar a Xamarin.Forms StackLayout en que pueden organizar sus elementos secundarios
horizontal y verticalmente en una pila. Sin embargo, el FlexLayout también es capaz de ajuste sus elementos
secundarios, si hay demasiados como para caber en una sola fila o columna, y también tiene muchas opciones
para adaptarse a diversos tamaños de pantalla, la alineación y la orientación.
FlexLayout se deriva de Layout<View> y hereda un Children propiedad de tipo IList<View> .
FlexLayout define seis propiedades enlazables públicas y cinco propiedades enlazables adjuntas que afectan al
tamaño, orientación y alineación de sus elementos secundarios. (Si no está familiarizado con las propiedades
enlazables adjuntas, consulte el artículo propiedades adjuntas.) Estas propiedades se describen en detalle en las
secciones siguientes en las propiedades enlazables detalladamente y las propiedades enlazables
asociadas con detalle. Sin embargo, en este artículo comienza con una sección en algunas escenarios de uso
comunes de FlexLayout que muchas de estas propiedades describe de manera más informal. Hacia el final del
artículo, verá cómo combinar FlexLayout con hojas de estilos CSS.
<FlexLayout Direction="Column"
AlignItems="Center"
JustifyContent="SpaceEvenly">
Cuando los elementos de un FlexLayout se organizan en una columna, el FlexLayout se dice que tiene
una vertical eje principal y horizontal entre el eje.
El AlignItems propiedad es de tipo FlexAlignItems y especifica cómo se alinean los elementos en el eje
cruzado. El Center opción hace que cada elemento se centra horizontalmente.
Si usaba una StackLayout en lugar de un FlexLayout para esta tarea, ¿centrar todos los elementos
mediante la asignación de la HorizontalOptions propiedad de cada elemento para Center . El
HorizontalOptions propiedad no funciona para los elementos secundarios de un FlexLayout , pero la única
AlignItems propiedad cumple con el mismo objetivo. Si necesita, puede usar el AlignSelf adjunta la
propiedad enlazable para invalidar el AlignItems propiedad para elementos individuales:
<Label Text="FlexLayout in Action"
FontSize="Large"
FlexLayout.AlignSelf="Start" />
Con este cambio, éste Label se coloca en el borde izquierdo de la FlexLayout cuando el orden de lectura
es de izquierda a derecha.
El JustifyContent propiedad es de tipo FlexJustify y especifica cómo se organizan los elementos en el
eje principal. El SpaceEvenly opción asigna todo espacio vertical sobrante por igual entre todos los
elementos y por encima del primer elemento y por debajo del último elemento.
Si usaba una StackLayout, tiene que asignar el VerticalOptions propiedad de cada elemento para
CenterAndExpand para lograr un efecto similar. Pero la CenterAndExpand opción asignaría el doble de
espacio entre cada elemento que no sea anterior al primer elemento y después del último elemento. Puede
imitar la CenterAndExpand opción de VerticalOptions estableciendo el JustifyContent propiedad de
FlexLayout a SpaceAround .
Estos FlexLayout propiedades se describen con más detalle en la sección las propiedades enlazables
detalladamente a continuación.
Uso de FlexLayout de ajuste de los elementos
El foto ajuste página de la FlexLayoutDemos muestra cómo FlexLayout puede ajustar sus elementos
secundarios en filas o columnas adicionales. El archivo XAML crea instancias el FlexLayout y asigna dos
propiedades de la misma:
<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>
El Direction propiedad de este FlexLayout no se establece, por lo que tiene el valor predeterminado de Row , lo
que significa que los elementos secundarios se organizan en filas y el eje principal es horizontal.
El Wrap propiedad es de un tipo de enumeración FlexWrap . Si hay demasiados elementos para que quepan en
una fila, valor de esta propiedad hace que los elementos que se va a ajustar a la siguiente fila.
Tenga en cuenta que el FlexLayout es un elemento secundario de un ScrollView . Si hay demasiadas filas para
que quepa en la página, el ScrollView tiene un valor predeterminado Orientation propiedad de Vertical y
permite el desplazamiento vertical.
El JustifyContent propiedad asigna espacio restante en el eje principal (el eje horizontal) para que cada elemento
está rodeado por la misma cantidad de espacio en blanco.
El archivo de código subyacente tiene acceso a una colección de fotos de ejemplo y los agrega a la Children
colección de los 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();
}
activityIndicator.IsRunning = false;
activityIndicator.IsVisible = false;
}
}
<FlexLayout Direction="Column">
</FlexLayout>
<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 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=" • Doesn't make a lot of noise" />
<Label Text=" • Often smiles mysteriously" />
<Label Text=" • 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">
<FlexLayout Direction="Column">
<Label Text="Banana Monkey"
Style="{StaticResource headerLabel}" />
<Label Text="Watch this monkey eat a giant banana." />
<Label Text=" • More fun than a barrel of monkeys" />
<Label Text=" • 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=" • Cynical but not unfriendly" />
<Label Text=" • Seven varieties of grimaces" />
<Label Text=" • 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>
El estilo implícito para la Image incluye la configuración de dos propiedades enlazables asociadas de Flexlayout :
<Style TargetType="Image">
<Setter Property="FlexLayout.Order" Value="-1" />
<Setter Property="FlexLayout.AlignSelf" Value="Center" />
</Style>
El Orderde –causas 1 la Image elemento que se mostrarán en primer lugar en cada uno de los anidados
FlexLayout vistas independientemente de su posición dentro de la colección de elementos secundarios. El
AlignSelf propiedad de Center hace que el Image se centre en la FlexLayout . Esto reemplaza la configuración
de la AlignItems propiedad, que tiene un valor predeterminado de Stretch , lo que significa que el Label y
Button elementos secundarios se ajusta a todo el ancho de la FlexLayout .
Dentro de cada uno de los tres FlexLayout vistas, un espacio en blanco Label precede a la Button , pero tiene un
Grow de 1. Esto significa que todo el espacio vertical sobrante está asignado a este en blanco Label , que inserta
de forma eficaz el Button hasta la parte inferior.
Cada uno de los Label vistas tiene un fondo gris que muestra el espacio asignado a la que Label dentro de la
FlexLayout . El fondo de la FlexLayout es blanco azulado. Ocupa el área de la parte inferior de la página, excepto
un pequeño margen a la izquierda y derecha.
La propiedad Direction
El Direction propiedad es de tipo FlexDirection , una enumeración con cuatro miembros:
Column
ColumnReverse (o "columna-reverse" en XAML )
Row , el valor predeterminado
RowReverse (o "fila-reverse" en XAML )
En XAML, puede especificar el valor de esta propiedad mediante los nombres de miembro de enumeración en
minúsculas, mayúsculas, o mayúsculas y minúsculas mezcladas, o bien puede usar dos cadenas adicionales que se
muestra entre paréntesis que son los mismos que los indicadores CSS. (Las cadenas "columna-reverse" y "fila-
reverse" se definen en el FlexDirectionTypeConverter clase usada por el analizador XAML.)
Este es el experimento página que muestra (de izquierda a derecha), el Row dirección, Column dirección, y
ColumnReverse dirección:
Tenga en cuenta que para el Reverse opciones, los elementos a partir de la derecha o inferior.
La propiedad Wrap
El Wrap propiedad es de tipo FlexWrap , una enumeración con tres miembros:
NoWrap , el valor predeterminado
Wrap
Reverse (o "wrap-reverse" en XAML )
De izquierda a derecha, se muestran estas pantallas el NoWrap , Wrap y Reverse opciones para elementos
secundarios de 12:
Cuando el Wrap propiedad está establecida en NoWrap está restringido el eje principal (como se muestra en este
programa) y el eje principal no es amplia o lo suficientemente alto como para ajustarse a todos los elementos
secundarios, el FlexLayout intenta realizar los elementos más pequeños, como la captura de pantalla de iOS se
muestra. Puede controlar la shrinkness de los elementos de la Shrink propiedad enlazable adjunta.
La propiedad JustifyContent
El JustifyContent propiedad es de tipo FlexJustify , una enumeración con seis miembros:
Start (o "flex-start" en XAML ), el valor predeterminado
Center
End (o "flex-end" de XAML )
SpaceBetween (o "espacio entre" en XAML )
SpaceAround (o "espacio alrededor" en XAML )
SpaceEvenly
Esta propiedad especifica cómo se espacian los elementos en el eje principal, que es el eje horizontal en este
ejemplo:
En todas las capturas de pantalla de tres, el Wrap propiedad está establecida en Wrap . El Start predeterminado
se muestra en la captura de pantalla de Android anterior. La captura de pantalla de iOS aquí se muestra el Center
opción: todos los elementos se mueven al centro. Otras de las tres opciones a partir de la palabra Space asignar
el espacio adicional que no esté ocupado por los elementos. SpaceBetween asigna el espacio por igual entre los
elementos; SpaceAround coloca igual espacio alrededor de cada elemento, mientras que SpaceEvenly coloca igual
espacio entre cada elemento y antes del primer elemento y después del último elemento en la fila.
La propiedad AlignItems
El AlignItems propiedad es de tipo FlexAlignItems , una enumeración con cuatro miembros:
Stretch , el valor predeterminado
Center
Start (o "flex-start" en XAML )
End (o "flex-end" de XAML )
Esta es una de las dos propiedades (el otro es AlignContent ) que indica cómo se alinean los elementos
secundarios en el eje cruzado. Dentro de cada fila, los elementos secundarios se estira (como se muestra en la
captura de pantalla anterior) o alineados en el inicio, el centro o el final de cada elemento, como se muestra en las
siguientes capturas de pantalla de tres:
En la captura de pantalla de iOS, se alinean las partes superiores de todos los elementos secundarios. En las
capturas de pantalla de Android, los elementos se centran verticalmente según el elemento secundario más alto.
En la captura de pantalla UWP, la parte inferior de todos los elementos está alineada.
Para cualquier elemento individual, la AlignItems valor puede reemplazarse con el AlignSelf propiedad
enlazable adjunta.
La propiedad AlignContent
El AlignContent propiedad es de tipo FlexAlignContent , una enumeración con siete miembros:
Stretch , el valor predeterminado
Center
Start (o "flex-start" en XAML )
End (o "flex-end" de XAML )
SpaceBetween (o "espacio entre" en XAML )
SpaceAround (o "espacio alrededor" en XAML )
SpaceEvenly
Al igual que AlignItems , el AlignContent propiedad también se alinea los elementos secundarios en el eje
cruzado, pero afecta a todas las filas o columnas:
En la captura de pantalla de iOS, ambas filas están en la parte superior; en la captura de pantalla de Android que
están en el centro; y en la captura de pantalla UWP que están en la parte inferior. También se pueden espaciadas
las filas de varias maneras:
El AlignContent no tiene ningún efecto cuando hay solo una fila o columna.
FlexLayout.SetAlignSelf(label, FlexAlignSelf.Center);
Tenga en cuenta que no hay ninguna referencia a la FlexLayout primario de la Label . En XAML, establezca la
propiedad similar al siguiente:
La propiedad Order
El Order propiedad es de tipo int . El valor predeterminado es 0.
El Order propiedad le permite cambiar el orden que los elementos secundarios de la FlexLayout se organizan.
Normalmente, los elementos secundarios de un FlexLayout se organizan es el mismo orden que aparecen en la
Children colección. Este orden se puede invalidar estableciendo la Order propiedad enlazable se adjunta a un
valor entero distinto de cero en uno o más elementos secundarios. El FlexLayout , a continuación, organiza sus
elementos secundarios en función del valor de la Order propiedad en cada elemento secundario, pero los
elementos secundarios con el mismo Order configuración se organizan en el orden en que aparecen en la
Children colección.
La propiedad de base
El Basis propiedad enlazable adjunta indica la cantidad de espacio que se asigna a un elemento secundario de la
FlexLayout en el eje principal. El tamaño especificado por el Basis propiedad es el tamaño a lo largo del eje
principal del elemento primario FlexLayout . Por lo tanto, Basis indica el ancho de un elemento secundario
cuando los elementos secundarios se organizan en filas o el alto cuando los elementos secundarios se organizan
en columnas.
El Basis propiedad es de tipo FlexBasis , una estructura. Se puede especificar el tamaño en cualquier unidades
independientes del dispositivo o como un porcentaje del tamaño de la FlexLayout . El valor predeterminado de la
Basis es la propiedad estática FlexBasis.Auto , lo que significa que el elemento secundario solicitado se utiliza el
ancho o alto.
En el código, puede establecer el Basis propiedad para un Label denominado label a 40 unidades
independientes del dispositivo como esta:
El segundo argumento para el FlexBasis se denomina constructor isRelative e indica si el tamaño es relativo (
true ) o absoluta ( false ). El argumento tiene un valor predeterminado de false , por lo que también puede
usar el código siguiente:
Una conversión implícita de float a FlexBasis está definido, por lo que puede simplificar aún más:
FlexLayout.SetBasis(label, 40);
La captura de pantalla de iOS a la izquierda muestra los dos Label elementos determinados altos en unidades
independientes del dispositivo. Muestra la pantalla Android determinado altos que suponen una fracción de la
altura total del FlexLayout . Si el Basis se establece en 100%, entonces el elemento secundario es el alto de la
FlexLayout y se ajustan a la columna siguiente y ocupar el alto de esa columna, como se muestra en la captura de
pantalla UWP: Parece como si los elementos cinco secundarios se organizan en una fila, pero en realidad están
ordenados en cinco columnas.
La propiedad de crecimiento
El Grow propiedad enlazable adjunta es de tipo int . El valor predeterminado es 0 y el valor debe ser mayor o
igual que 0.
El Grow propiedad desempeña un rol cuando la Wrap propiedad está establecida en NoWrap y la fila de
elementos secundarios tiene un ancho total menor que el ancho de la FlexLayout , o la columna de elementos
secundarios tiene un alto más corto que el FlexLayout . El Grow propiedad indica la forma de distribuir el espacio
entre los elementos secundarios sobrante.
En el crecer experimento página cinco Label elementos de alternancia de colores se organizan en una columna
y dos Slider elementos le permiten ajustar la Grow propiedad de la segunda y cuarta Label . La captura de
pantalla de iOS en el extremo izquierdo muestra el valor predeterminado Grow propiedades 0:
Si cualquier un elemento secundario no se especifica un positivo Grow valor, a continuación, ese elemento
secundario ocupa todo el espacio restante, como se muestra en la captura de pantalla de Android. También se
puede asignar este espacio entre dos o más elementos secundarios. En la captura de pantalla UWP, la Grow
propiedad del segundo Label se establece en 0,5, mientras el Grow propiedad de la cuarta Label es la 1.5, que
proporciona el cuarto Label tres veces más el espacio como el segundo sobrantes Label .
Cómo la vista secundaria utiliza ese espacio depende del tipo específico de elemento secundario. Para un Label ,
el texto se puede colocar dentro del espacio total de la Label mediante las propiedades HorizontalTextAlignment
y VerticalTextAlignment .
La propiedad de reducción
El Shrink propiedad enlazable adjunta es de tipo int . El valor predeterminado es 1 y el valor debe ser mayor o
igual que 0.
El Shrink propiedad desempeña un papel cuando la Wrap propiedad está establecida en NoWrap y el ancho
agregado de una fila de elementos secundarios es mayor que el ancho de la FlexLayout , o el alto agregado de
una sola columna de elementos secundarios es mayor que el alto de la FlexLayout . Normalmente el FlexLayout
mostrará estos elementos secundarios por limitante sus tamaños. El Shrink propiedad puede indicar qué
elementos secundarios tienen prioridad en el que se muestra en su tamaño completo.
El reducir experimento página crea un FlexLayout con una sola fila de cinco Label elementos secundarios que
requieren más espacio que el FlexLayout ancho. La captura de pantalla de iOS en el lado izquierdo muestra
todas las Label elementos con los valores predeterminados de 1:
En la captura de pantalla de Android, el Shrink valor para el segundo Label se establece en 0 y que Label se
muestra en su formato completo. Además, la cuarta Label tiene un Shrink valor mayor que uno, y ha reducido.
Muestra la captura de pantalla UWP Label elementos que se concede un Shrink el valor 0 para que puedan
mostrarse en su tamaño completo, si eso es posible.
Puede establecer tanto el Grow y Shrink valores para adaptarse a situaciones donde los tamaños de agregados
secundarios a veces pueden ser menor que o a veces mayor que el tamaño de la FlexLayout .
<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=" • Doesn't make a lot of noise" />
<Label Text=" • Often smiles mysteriously" />
<Label Text=" • 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=" • More fun than a barrel of monkeys" />
<Label Text=" • 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=" • Cynical but not unfriendly" />
<Label Text=" • Seven varieties of grimaces" />
<Label Text=" • Doesn't laugh at your jokes" />
<Image Source="{local:ImageResource FlexLayoutDemos.Images.FacePalm.jpg}" />
<Label StyleClass="empty" />
<Button />
</FlexLayout>
</Frame>
</FlexLayout>
</ScrollView>
</ContentPage>
Observe también que se incluyen dos elementos en cada uno de los tres elementos StyleClass configuración:
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;
}
Varios FlexLayout adjuntadas propiedades enlazables se hace referencia aquí. En el label.empty selector, verá el
flex-grow atributo, que determina el estilo vacío Label para ofrecer algún espacio en blanco por encima del
Button . El image selector contiene un order atributo y un align-self atributo, que corresponden a FlexLayout
enlazables propiedades adjuntas.
Hemos visto que puede establecer propiedades directamente en el FlexLayout y puede establecer las
propiedades enlazables adjuntas en los elementos secundarios de un FlexLayout . O bien, puede establecer estas
propiedades forma indirecta, mediante los estilos tradicionales basado en XAML o los estilos CSS. Lo importante
es conocer y comprender estas propiedades. Estas propiedades son lo que hace que el FlexLayout realmente
flexible.
descargar el ejemplo
ScrollView contiene los diseños y les permite desplazamiento fuera de la pantalla. ScrollView También se utiliza
para permitir que las vistas se mueva automáticamente a la parte visible de la pantalla cuando se muestra el
teclado.
Propósito
ScrollView puede utilizarse para asegurarse de que se muestran vistas mayor bien en los teléfonos más
pequeños. Por ejemplo, un diseño que funciona en un iPhone 6s puede quedar cortado en un iPhone 4s.
Mediante un ScrollView permitirían las partes recortadas del diseño que se mostrará en la pantalla más
pequeña.
Uso
NOTE
ScrollView s no debería estar anidado. Además, ScrollView s no debería estar anidado con otros controles que
proporcionan el desplazamiento, como ListView y WebView .
ScrollView expone un Content propiedad que se puede establecer en un diseño o vista única. Considere este
ejemplo de un diseño con un gran boxView, seguido por un Entry :
<ContentPage.Content>
<ScrollView>
<StackLayout>
<BoxView BackgroundColor="Red" HeightRequest="600" WidthRequest="150" />
<Entry />
</StackLayout>
</ScrollView>
</ContentPage.Content>
En C#:
Antes de que el usuario se desplaza hacia abajo, solo el BoxView está visible:
Tenga en cuenta que cuando el usuario comienza a escribir texto en el Entry , la vista se desplaza para mantener
visible en pantalla:
Propiedades
ScrollView define las siguientes propiedades:
ContentSize Obtiene un Size valor que representa el tamaño del contenido.
Orientation Obtiene o establece un ScrollOrientation valor de enumeración que representa la dirección de
desplazamiento de la ScrollView .
ScrollX Obtiene un double que representa la actual posición de desplazamiento X.
ScrollY Obtiene un double que representa la posición de desplazamiento Y actual.
HorizontalScrollBarVisibility Obtiene o establece un ScrollBarVisibility valor que representa cuándo está
visible la barra de desplazamiento horizontal.
VerticalScrollBarVisibility Obtiene o establece un ScrollBarVisibility valor que representa el momento
de la barra de desplazamiento vertical está visible.
Métodos
ScrollView Proporciona un ScrollToAsync método, que se puede usar para desplazar la vista mediante
coordenadas o bien especificando una vista concreta que debe hacerse visible.
Cuando se usa coordenadas, especifique el x y y coordenadas, junto con un valor booleano que indica si el
desplazamiento debe animarse:
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
Al desplazarse a un elemento determinado, el ScrollToPosition especifica enumeración donde en la vista del
elemento aparecerá:
Centro de – desplaza el elemento en el centro de la parte visible de la vista.
End – desplaza el elemento al final de la parte visible de la vista.
MakeVisible – desplaza el elemento para que sea visible dentro de la vista.
Iniciar – desplaza el elemento al principio de la parte visible de la vista.
El IsAnimated propiedad especifica cómo se desplazará la vista. Cuando establece en true, una animación suave,
se usará, en lugar de pasar al instante el contenido en la vista.
Eventos
ScrollView define un solo evento Scrolled . Scrolled se produce cuando ha finalizado la vista de
desplazamiento. El controlador de eventos Scrolled toma ScrolledEventArgs , que tiene el ScrollX y ScrollY
propiedades. El siguiente ejemplo muestra cómo actualizar una etiqueta con la posición de desplazamiento actual
de un ScrollView :
Tenga en cuenta que las posiciones de desplazamiento pueden ser negativas, porque el efecto de rebote al
desplazarse al final de una lista.
Vínculos relacionados
Diseño (ejemplo)
Ejemplo de BusinessTumble (ejemplo)
Opciones de diseño de Xamarin.Forms
11/07/2019 • 10 minutes to read • Edit Online
descargar el ejemplo
Cada vista Xamarin.Forms tiene propiedades HorizontalOptions y VerticalOptions, del tipo LayoutOptions. En
este artículo se explica el efecto que tiene cada valor LayoutOptions en la alineación y la expansión de una vista.
Información general
El LayoutOptions estructura encapsula dos de las preferencias de diseño:
Alineación – preferido de la vista de la alineación, que determina su posición y tamaño en su diseño principal.
Expansión : se usa únicamente por un StackLayout e indica si la vista debe utilizar el espacio adicional, si está
disponible.
Estas preferencias de diseño se pueden aplicar a un View respecto a su elemento primario, estableciendo el
HorizontalOptions o VerticalOptions propiedad de la View a uno de los campos públicos de la LayoutOptions
estructura. Los campos públicos son los siguientes:
Start
Center
End
Fill
StartAndExpand
CenterAndExpand
EndAndExpand
FillAndExpand
El Start , Center , End ,y Fill campos se usan para definir la alineación de la vista del diseño del elemento
primario:
Para la alineación horizontal, Start posiciones el View en el lado izquierdo del diseño del elemento primario
y para la alineación vertical, coloca el View en la parte superior de la diseño del elemento primario.
Para la alineación horizontal y vertical, Center centra horizontalmente o verticalmente el View .
Para la alineación horizontal, End posiciones el View en el lado derecho del diseño del elemento primario y
para la alineación vertical, coloca el View en la parte inferior del diseño del elemento primario.
Para la alineación horizontal, Fill garantiza que el View rellena el ancho del diseño del elemento primario y
para la alineación vertical, garantiza que el View rellena el alto del diseño del elemento primario.
El StartAndExpand , CenterAndExpand , EndAndExpand , y FillAndExpand valores se usan para definir la preferencia de
alineación, y si la vista ocupan más espacio si está disponible dentro del elemento primario StackLayout .
NOTE
El valor predeterminado de una vista HorizontalOptions y VerticalOptions propiedades es LayoutOptions.Fill .
Alineación
Alineación controla cómo se coloca una vista en su diseño principal cuando el diseño del elemento primario
contiene espacio no utilizado (es decir, el diseño del elemento primario es mayor que el tamaño combinado de
todos sus elementos secundarios).
Un StackLayout solo respeta el Start , Center , End , y Fill LayoutOptions campos en las vistas secundarias
que se encuentran en la dirección opuesta para el StackLayout orientación. Por lo tanto, las vistas secundarias
dentro de una orientación vertical StackLayout puede establecer sus HorizontalOptions propiedades a uno de los
Start , Center , End , o Fill campos. De forma similar, las vistas secundarios dentro de una orientación
horizontal StackLayout puede establecer sus VerticalOptions propiedades a uno de los Start , Center , End , o
Fill campos.
Un StackLayout no respeta el Start , Center , End , y Fill LayoutOptions campos en las vistas secundarias que
se encuentran en la misma dirección que el StackLayout orientación. Por lo tanto, una orientación vertical
StackLayout omite el Start , Center , End , o Fill campos si están establecidos en el VerticalOptions
propiedades de vistas secundarias. De forma similar, una orientación horizontal StackLayout omite el Start ,
Center , End , o Fill campos si están establecidos en el HorizontalOptions propiedades de vistas secundarias.
NOTE
LayoutOptions.Fill por lo general invalidaciones cambiar el tamaño de las solicitudes que se especifican mediante el
HeightRequest y WidthRequest propiedades.
El ejemplo de código XAML siguiente muestra una orientación vertical StackLayout donde cada elemento
secundario Label establece su HorizontalOptions propiedad en uno de los campos de cuatro de alineación de la
LayoutOptions estructura:
<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>
El código da como resultado el diseño que se muestra en las capturas de pantalla siguiente:
Expansión
Expansión controla si una vista ocupa más espacio, si está disponible dentro de un StackLayout . Si el
StackLayout contiene espacio no utilizado (es decir, el StackLayout es mayor que el tamaño combinado de todos
sus elementos secundarios), el espacio no utilizado se comparte de forma equitativa todas las vistas secundarias
que solicitan expansión estableciendo sus HorizontalOptions o VerticalOptions propiedades para un
LayoutOptions campo que utiliza el AndExpand sufijo. Tenga en cuenta que, cuando todo el espacio en el
StackLayout es utilizado, las opciones de expansión no tienen ningún efecto.
Un StackLayout sólo se puede expandir vistas secundarias en la dirección de su orientación. Por lo tanto, una
orientación vertical StackLayout puede expandir las vistas secundarias que establecen sus VerticalOptions
propiedades a uno de los StartAndExpand , CenterAndExpand , EndAndExpand , o FillAndExpand campos, si la
StackLayout contiene espacio no utilizado. De forma similar, una orientación horizontal StackLayout puede
expandir las vistas secundarias que establecen sus HorizontalOptions propiedades a uno de los StartAndExpand ,
CenterAndExpand , EndAndExpand , o FillAndExpand campos, si la StackLayout contiene espacio no utilizado.
Un StackLayout no se puede expandir vistas secundarias en la dirección opuesta a la orientación. Por lo tanto, en
orientación vertical StackLayout , estableciendo el HorizontalOptions propiedad en una vista secundaria a
StartAndExpand tiene el mismo efecto que establecer la propiedad en Start .
NOTE
Tenga en cuenta que habilitar la expansión no cambia el tamaño de una vista a menos que lo use
LayoutOptions.FillAndExpand .
El ejemplo de código XAML siguiente muestra una orientación vertical StackLayout donde cada elemento
secundario Label establece su VerticalOptions propiedad en uno de los campos de cuatro de expansión desde
la LayoutOptions estructura:
<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>
El código da como resultado el diseño que se muestra en las capturas de pantalla siguiente:
Cada Label ocupa la misma cantidad de espacio en el StackLayout . Sin embargo, solo la última Label , que
establece su VerticalOptions propiedad FillAndExpand tiene un tamaño diferente. Además, cada Label
separados por una pequeña roja BoxView , lo que permite el espacio de la Label ocupa para verse fácilmente.
Resumen
En este artículo se explica el efecto que cada LayoutOptions tiene el valor de la estructura en la alineación y la
expansión de una vista, en relación con su elemento primario. El Start , Center , End , y Fill campos se usan
para definir la alineación de la vista del diseño del elemento primario y el StartAndExpand , CenterAndExpand ,
EndAndExpand , y FillAndExpand campos se usan para definir la preferencia de alineación y para determinar si la
vista ocupa más espacio, si está disponible dentro de un StackLayout .
Vínculos relacionados
LayoutOptions (ejemplo)
LayoutOptions
Margen y relleno
11/07/2019 • 3 minutes to read • Edit Online
Los márgenes y relleno de las propiedades de controlan el comportamiento de diseño cuando se procesa un
elemento en la interfaz de usuario. En este artículo se muestra la diferencia entre las dos propiedades y cómo
establecerlas.
Información general
Márgenes y relleno son conceptos de diseño relacionadas:
El Margin propiedad representa la distancia entre un elemento y sus elementos adyacentes y se usa para
controlar la posición del elemento representación y la posición de representación de sus vecinos. Margin se
pueden especificar valores en diseño y vista clases.
El Padding propiedad representa la distancia entre un elemento y sus elementos secundarios y se usa para
separar el control de su propio contenido. Padding se pueden especificar valores en diseño clases.
Tenga en cuenta que Margin los valores son aditivos. Por lo tanto, si dos elementos adyacentes especifican un
margen de 20 píxeles, la distancia entre los elementos será 40 píxeles. Además, márgenes y relleno son aditivos
cuando ambos se aplican, en que la distancia entre un elemento y cualquier contenido será el margen más
relleno.
Especifica un grosor
El Margin y Padding propiedades son de tipo Thickness . Existen tres posibilidades al crear un Thickness
estructura:
Crear un Thickness estructura definida por un único valor uniforme. El valor solo se aplica a la izquierda,
superior, derecha y lados de la parte inferior del elemento.
Crear un Thickness estructura definida por los valores horizontales y verticales. El valor horizontal
simétricamente se aplica a los lados izquierdo y derecho del elemento, con el valor vertical simétricamente
que se aplica a los lados superior e inferior del elemento.
Crear un Thickness estructura definida por cuatro valores distintos que se aplican a la izquierda, superior,
derecha y lados de la parte inferior del elemento.
El ejemplo de código XAML siguiente muestra las tres posibilidades:
<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>
NOTE
Thickness los valores pueden ser negativos, lo que normalmente recorta o el contenido de este.
Resumen
En este artículo se muestra la diferencia entre el Margin y Padding propiedades y cómo establecerlas. Las
propiedades controlan el comportamiento de diseño cuando se procesa un elemento en la interfaz de usuario.
Vínculos relacionados
Margen
Padding
Grosor
Orientación del dispositivo
11/07/2019 • 18 minutes to read • Edit Online
descargar el ejemplo
Es importante tener en cuenta cómo se utilizará la aplicación y cómo se puede incorporar la orientación horizontal
para mejorar la experiencia del usuario. Diseños individuales pueden diseñarse para dar cabida a varias
orientaciones y mejor usa el espacio disponible. En el nivel de aplicación, rotación puede habilitar o deshabilitar.
Controlar la orientación
Cuando se usa Xamarin.Forms, el método admitido para controlar la orientación del dispositivo es usar la
configuración para cada proyecto individual.
iOS
En iOS, la orientación del dispositivo está configurado para las aplicaciones que usan el Info.plist archivo. Este
archivo incluirá la configuración de orientación para iPhone y iPod, así como la configuración para iPad si la
aplicación incluye como un destino. Las siguientes son instrucciones específicas para su IDE. Use las opciones del
IDE en la parte superior de este documento para seleccionar qué instrucciones que gustaría ver:
Visual Studio
Visual Studio para Mac
En Visual Studio, abra el proyecto de iOS y abra Info.plist. El archivo se abrirá en un panel de configuración, a
partir de la pestaña de información de implementación de iPhone:
Para configurar la orientación de iPad, seleccione el iPad información sobre implementación ficha en la parte
superior izquierda del panel, a continuación, seleccione desde las orientaciones disponibles:
Android
Para controlar la orientación en Android, abra MainActivity.cs y establezca la orientación mediante el atributo
decorar el MainActivity clase:
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)
...
NOTE
Hay un paquete de NuGet existente y gratuito para recibir notificaciones de cambios de orientación en código compartido.
Consulte la repositorio de GitHub para obtener más información.
Como alternativa, es posible invalidar el OnSizeAllocated método en un Page , insertar cualquier diseño cambie la
lógica no existe. El OnSizeAllocated se llama al método cada vez que un Page se asigna un nuevo tamaño, lo que
sucede cada vez que se gira el dispositivo. Tenga en cuenta que la implementación base de OnSizeAllocated
realiza funciones de diseño importante, por lo que es importante llamar a la implementación base en la
invalidación:
Error al dar ese paso dará como resultado una página que no funciona.
Tenga en cuenta que el OnSizeAllocated método puede llamarse varias veces cuando se gira un dispositivo.
Cambiar el diseño cada vez es un desperdicio de recursos y puede provocar parpadeos. Considere el uso de una
variable de instancia dentro de la página para seguir si es la orientación en horizontal o vertical y solo vuelve a
dibujar cuando se produce un cambio:
y horizontal:
Tenga en cuenta que las aplicaciones aprovechar el espacio disponible mediante la adición de más funcionalidad
en horizontal.
Diseño dinámico
Es posible a las interfaces de diseño mediante los diseños integrados para que hagan el cambio correctamente
cuando se gira el dispositivo. Al diseñar las interfaces que seguirán siendo atractivo al responder a los cambios de
orientación, tenga en cuenta las siguientes reglas generales:
Preste atención a proporciones – cambios en la orientación pueden causar problemas cuando se realizan
determinadas suposiciones con respecto a la relación. Por ejemplo, una vista que tendría una gran cantidad de
espacio en 1/3 del espacio vertical de una pantalla en posición vertical no cabrá en 1/3 del espacio vertical en
horizontal.
Debe tener cuidado con los valores absolutos – valores absolutos (píxeles) que tengan sentido en vertical
pueden no tener sentido en horizontal. Cuando se necesitan valores absolutos, utilice los diseños anidados
para aislar su impacto. Por ejemplo, sería razonable utilizar valores absolutos en un TableView ItemTemplate
cuando la plantilla de elemento tiene un alto uniforme garantizado.
Las reglas anteriores también se aplican al implementar las interfaces para varios tamaños de pantalla y son
generalmente considera mejores prácticas. El resto de esta guía explica ejemplos específicos de diseños con
capacidad de respuesta con cada uno de los diseños principales en Xamarin.Forms.
NOTE
Para mayor claridad, las siguientes secciones muestran cómo implementar diseños con capacidad de respuesta con un solo
tipo de Layout a la vez. En la práctica, a menudo resulta más sencillo mezclar Layout s para lograr un diseño deseado con
la más sencilla o más intuitivo Layout para cada componente.
StackLayout
Tenga en cuenta la siguiente aplicación, se muestra en vertical:
y horizontal:
Que se logra con el XAML siguiente:
<?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>
Algunos C# se utiliza para cambiar la orientación de outerStack según la orientación del dispositivo:
</ScrollView>
y horizontal:
Que se logra con el XAML siguiente:
<?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>
Junto con el siguiente código de procedimientos para controlar los cambios de rotación:
private double width;
private double height;
Vínculos relacionados
Diseño (ejemplo)
Ejemplo de BusinessTumble (ejemplo)
Diseño dinámico (ejemplo)
Mostrar una imagen basada en la orientación de pantalla
Diseño para aplicaciones de tableta y escritorio
11/07/2019 • 5 minutes to read • Edit Online
Xamarin.Forms es compatible con todos los tipos de dispositivo disponibles en las plataformas compatibles, por lo
que los teléfonos, además de las aplicaciones también pueden ejecutar:
iPad,
Tabletas Android,
Tabletas de Windows y equipos de escritorio (que ejecutan Windows 10).
Esta página se describe brevemente:
admitidos tipos de dispositivo, y
cómo optimizar diseños para tabletas y teléfonos.
Tipos de dispositivos
Dispositivos de pantalla de mayor tamaño están disponibles para todas las plataformas compatibles con
Xamarin.Forms.
iPad (iOS )
La plantilla de Xamarin.Forms automáticamente incluye soporte técnico de iPad configurando el Info.plist >
dispositivos si se establece en Universal (lo que significa que se admiten iPhone y iPad).
Para proporcionar una experiencia de inicio agradable y asegúrese de que se usa la resolución de pantalla
completa en todos los dispositivos, debe asegurarse de que un pantalla de inicio específicas de iPad (utilizar un
guión gráfico) se proporciona. Esto garantiza que la aplicación se representa correctamente en dispositivos iPad
con mini, iPad y iPad Pro.
Antes de iOS 9 ocupaba todas las aplicaciones de la pantalla completa en el dispositivo, pero ahora pueden
realizar algunas iPad dividir la pantalla multitarea. Esto significa que la aplicación puede tardar hasta simplemente
una columna delgada en el lateral de la pantalla, 50% del ancho de la pantalla, o toda la pantalla.
Funcionalidad de pantalla dividida significa que debe diseñar la aplicación para funcionar bien con tan solo 320
píxeles de anchos o tanto como 1366 píxeles de ancho.
Tabletas Android
El ecosistema de Android tiene una gran variedad de tamaños de pantalla compatibles, desde teléfonos pequeños
hasta grandes tabletas. Xamarin.Forms puede admitir todos los tamaños de pantalla, pero como con las otras
plataformas que es posible que desea ajustar la interfaz de usuario para dispositivos de mayor tamaño.
Cuando se admiten muchas diferentes resoluciones de pantalla, puede proporcionar los recursos de imagen
nativa en diferentes tamaños para optimizar la experiencia del usuario. Revise el recursos de Android
documentación (y, en particular crear recursos en varios tamaños de pantalla) para obtener más información
sobre cómo estructurar las carpetas y los nombres de archivo en su aplicación Android proyecto para incluir los
recursos de la imagen optimizada de la aplicación.
Escritorios y tabletas de Windows
Para admitir las tabletas y equipos de escritorio con Windows, deberá usar compatibilidad con Windows UWP,
que compila las aplicaciones universales que se ejecutan en Windows 10.
Aplicaciones que se ejecutan en equipos de escritorio y tabletas de Windows que pueden ajustarse dimensiones
arbitrarias además al funcionamiento de pantalla completa.
Optimizar para tableta y escritorio
Puede ajustar la interfaz de usuario de Xamarin.Forms en función de si un teléfono o se usa el dispositivo de
escritorio o tableta. Esto significa que puede optimizar la experiencia del usuario para dispositivos con pantallas
grandes, como tabletas y equipos de escritorio.
Device.Idiom
Puede usar el Device clase para cambiar el comportamiento de la interfaz de usuario o aplicación. Mediante el
Device.Idiom enumeración puede
if (Device.Idiom == TargetIdiom.Phone)
{
HeroImage.Source = ImageSource.FromFile("hero.jpg");
} else {
HeroImage.Source = ImageSource.FromFile("herotablet.jpg");
}
Este enfoque se puede expandir para realizar cambios significativos en los diseños de página individuales, o
incluso para procesar completamente diferentes páginas en pantallas más grandes.
Aprovechamiento de MasterDetailPage
El MasterDetailPage es ideal para pantallas más grandes, especialmente en el iPad que utiliza el
UISplitViewController para proporcionar una experiencia de iOS nativo.
Revisión esta entrada de blog de Xamarin para ver cómo se puede adaptar la interfaz de usuario para que los
teléfonos usan un diseño y pantallas más grandes pueden utilizar otra (con el MasterDetailPage ).
Vínculos relacionados
Blog de Xamarin
Ejemplo de MyShoppe
Diseños enlazables en Xamarin.Forms
11/07/2019 • 8 minutes to read • Edit Online
descargar el ejemplo
Los diseños enlazables permiten que cualquier clase de diseño que deriva de la clase Layout<T> genere su
contenido al enlazarse a una colección de elementos, con la opción de establecer la apariencia de cada elemento
con una DataTemplate . Los diseños enlazables los proporciona la clase BindableLayout , que expone las siguientes
propiedades adjuntas:
ItemsSource : especifica la colección de elementos IEnumerable que va a mostrar el diseño.
ItemTemplate : especifica la DataTemplate que se aplicará a cada elemento de la colección de elementos que
muestra el diseño.
ItemTemplateSelector : especifica el DataTemplateSelector que se usará para elegir una DataTemplate para un
elemento en tiempo de ejecución.
Estas propiedades se pueden conectar a las clases AbsoluteLayout , FlexLayout , Grid , RelativeLayout y
StackLayout , que derivan de la clase Layout<T> .
NOTE
La propiedad ItemTemplate tiene prioridad cuando están establecidas ambas propiedades ItemTemplate e
ItemTemplateSelector .
La clase Layout<T> expone una colección Children , a la que se agregan los elementos secundarios de un diseño.
Cuando se establece la propiedad BinableLayout.ItemsSource en una colección de elementos y se adjunta a una
clase derivada de Layout<T> , cada elemento de la colección se agrega a la colección Layout<T>.Children para que
el diseño lo muestre. Después, la clase derivada de Layout<T> actualizará sus vistas secundarias cuando cambie la
colección subyacente. Para obtener más información sobre el ciclo de diseño de Xamarin.Forms, consulte Crear un
diseño personalizado.
Los diseños enlazables solo deben usarse cuando la colección de elementos que se mostrará es pequeña y no se
necesiten el desplazamiento ni la selección. Aunque el desplazamiento puede proporcionarse al encapsular un
diseño enlazable en un ScrollView , no se recomienda, ya que los diseños enlazables carecen de virtualización de
interfaz de usuario. Cuando se requiere desplazamiento, una vista desplazable que incluye virtualización de
interfaz de usuario, como ListView o CollectionView , se debe usar. Ignorar esta recomendación puede provocar
problemas de rendimiento.
IMPORTANT
Aunque es técnicamente posible adjuntar un diseño se puede enlazar a cualquier clase de diseño que se deriva de la
Layout<T> (clase), no siempre resulta práctico volver a hacerlo, especialmente para la AbsoluteLayout , Grid , y
RelativeLayout clases. Por ejemplo, considere el escenario de que se desean mostrar una colección de datos en un Grid
mediante un diseño enlazable, donde cada elemento de la colección es un objeto que contiene varias propiedades. Cada fila
de la Grid debe mostrar un objeto de la colección, con cada columna de la Grid mostrar una de las propiedades del
objeto. Dado que el DataTemplate para el diseño enlazable solo puede contener un único objeto, es necesario para ese
objeto sea una clase de diseño que contiene varias vistas que muestran una de las propiedades del objeto en un
determinado Grid columna. Aunque este escenario puede evaluarse con diseños enlazables, resulta en un elemento
primario Grid que contiene un elemento secundario Grid para cada elemento de la colección enlazada, que es un uso
muy ineficaz y problemático de la Grid diseño.
En este ejemplo, una vista CircleImage definida en la DataTemplate mostrará todos los elementos de la colección
TopFollowers :
Para obtener más información sobre las plantillas de datos, consulte Plantillas de datos de Xamarin.Forms.
Vínculos relacionados
Demostración de diseño enlazable (ejemplo)
Creación de un diseño personalizado
Plantillas de datos de Xamarin.Forms
Creación de un Xamarin.Forms DataTemplateSelector
Crear un diseño personalizado
11/07/2019 • 28 minutes to read • Edit Online
descargar el ejemplo
Xamarin.Forms define cuatro clases de diseño: StackLayout, AbsoluteLayout, RelativeLayout y cuadrícula, y cada
uno de ellos organiza a sus elementos secundarios de forma diferente. Sin embargo, a veces es necesario
organizar el contenido de la página con un diseño que no se proporciona mediante Xamarin.Forms. En este
artículo se explica cómo escribir una clase de diseño personalizado y se muestra una clase de WrapLayout
minúsculas orientación que sus elementos secundarios se organiza horizontalmente en la página y, a
continuación, ajusta la presentación de los elementos secundarios subsiguientes a las filas adicionales.
Información general
En Xamarin.Forms, se derivan todas las clases de diseño de la Layout<T> clase y restringir el tipo genérico a
View y sus tipos derivados. A su vez, el Layout<T> clase se deriva de la Layout (clase), que proporciona el
mecanismo para colocar y secundarios de ajuste de tamaño los elementos.
Todos los elementos visuales es responsable de determinar su propio tamaño preferido, que se conoce como el
solicitado tamaño. Page , Layout , y Layout<View> tipos derivados son responsables de determinar la ubicación
y el tamaño de sus secundarios o elementos secundarios, con respecto a ellos mismos. Por lo tanto, el diseño
implica una relación de elementos primarios y secundarios, donde el elemento primario determina cuál debe ser
el tamaño de sus elementos secundarios, pero intentará adaptarse al tamaño solicitado del elemento secundario.
Se requiere un conocimiento exhaustivo de los ciclos de diseño y la invalidación de Xamarin.Forms para crear un
diseño personalizado. Ahora se tratarán estos ciclos.
Diseño
Diseño comienza en la parte superior del árbol visual con una página y pasa a través de todas las ramas del
árbol visual para abarcar todos los elementos visuales en una página. Los elementos que son elementos
primarios a otros elementos son responsables de ajuste de tamaño y la posición de sus elementos secundarios
en relación con ellos mismos.
El VisualElementclase define un Measure método que mide un elemento para las operaciones de diseño, y un
Layout método que especifica el área rectangular que se representa en el elemento. Cuando se inicia una
aplicación y se muestra la primera página, un ciclo de diseño primero que consta de Measure llamadas y, a
continuación, Layout llama, se inicia en el Page objeto:
1. Durante el ciclo de diseño, cada elemento primario es responsable de llamar a la Measure método en sus
elementos secundarios.
2. Después de haberse medidos los elementos secundarios, cada elemento primario es responsable de llamar a
la Layout método en sus elementos secundarios.
Este ciclo garantiza que todos los elementos visuales en la página recibe las llamadas a la Measure y Layout
métodos. El proceso se muestra en el diagrama siguiente:
NOTE
Tenga en cuenta que los ciclos de diseño también pueden producirse en un subconjunto del árbol visual si algo cambia
para afectar al diseño. Esto incluye los elementos que se agregan o quitan de una colección, como en un StackLayout ,
un cambio en el IsVisible propiedad de un elemento o un cambio en el tamaño de un elemento.
Todas las clases de Xamarin.Forms que tiene un Content o un Children propiedad tiene un reemplazable
LayoutChildren método. Las clases de diseño personalizado que se derivan de Layout<View> debe invalidar este
método y asegúrese de que el Measure y Layout son métodos se llama en todos los elementos secundarios del
elemento, para proporcionar el diseño personalizado deseado.
Además, cada clase que derive de Layout o Layout<View> debe invalidar el OnMeasure método, que es donde
una clase de diseño Determina el tamaño que deba estar realizando llamadas a la Measure métodos de sus
elementos secundarios.
NOTE
Elementos determinan su tamaño según restricciones, que indican cuánto espacio hay disponible para un elemento dentro
primario del elemento. Las restricciones se pasan a la Measure y OnMeasure métodos pueden oscilar entre 0 y
Double.PositiveInfinity . Es un elemento restringida, o completamente restringida, cuando recibe una llamada a su
Measure método con argumentos no infinita - está restringido el elemento un tamaño determinado. Es un elemento sin
restricciones, o parcialmente restringida, cuando recibe una llamada a su Measure método con igual que al menos un
argumento Double.PositiveInfinity : puede ser la restricción infinita considerar que indica el ajuste automático de
tamaño.
Invalidación
Invalidación es el proceso por el cual un cambio en un elemento de una página desencadena un nuevo ciclo de
diseño. Los elementos se consideran no válidos cuando ya no tienen el tamaño correcto o la posición. Por
ejemplo, si la FontSize propiedad de un Button cambios, el Button se dice que es válida porque ya no tiene el
tamaño correcto. Cambiar el tamaño de la Button , a continuación, puede tener un efecto dominó de cambios
de diseño en el resto de una página.
Invalidarán elementos propios invocando el InvalidateMeasure método, por lo general cuando cambia una
propiedad del elemento que podría dar lugar a un nuevo tamaño del elemento. Este método desencadena el
MeasureInvalidated evento, que controla el primario elemento para desencadenar un nuevo ciclo de diseño.
El Layout clase establece un controlador para el MeasureInvalidated eventos en cada elemento secundario que
se agrega a su Content propiedad o Children colección y desasocia el controlador cuando el se quita el
elemento secundario. Por lo tanto, todos los elementos en el árbol visual que tiene elementos secundarios es una
alerta cuando uno de sus elementos secundarios cambia de tamaño. El siguiente diagrama ilustra cómo un
cambio en el tamaño de un elemento en el árbol visual puede producir cambios que ripple el árbol:
Sin embargo, la Layout clase intenta restringir el impacto de un cambio de tamaño de un elemento secundario
en el diseño de una página. Si el diseño es limitada de tamaño, a continuación, un cambio de tamaño del
elemento secundario no afecta a algo mayor que el diseño del elemento primario en el árbol visual. Sin
embargo, normalmente un cambio en el tamaño de un diseño afecta a cómo el diseño organiza a sus elementos
secundarios. Por lo tanto, cualquier cambio en el tamaño de un diseño se iniciará un ciclo de diseño para el
diseño y el diseño recibirán llamadas a su OnMeasure y LayoutChildren métodos.
El Layoutclase define también un InvalidateLayout método que tiene una finalidad similar a la
InvalidateMeasure método. El InvalidateLayout debe invocarse el método cada vez que se realiza un cambio
que afecta a cómo el diseño de posiciones y tamaños de sus elementos secundarios. Por ejemplo, el Layout
clase invoca el InvalidateLayout método cada vez que se agrega o quita de un diseño de un elemento
secundario.
El InvalidateLayout se puede invalidar para implementar una memoria caché para minimizar las llamadas
repetitivas de la Measure métodos de elementos secundarios del diseño. Reemplazar el InvalidateLayout
método proporcionará una notificación cuando se agregan o se quita del diseño los elementos secundarios. De
forma similar, el OnChildMeasureInvalidated se puede invalidar el método para proporcionar una notificación
cuando uno de los elementos secundarios del diseño cambia de tamaño. Para los reemplazos de método debe
responder un diseño personalizado al borrar la caché. Para obtener más información, consulte calcular y
almacenar en caché datos.
NOTE
Al enumerar los elementos secundarios en el OnMeasure y LayoutChildren invalidaciones, omitir cualquier elemento
secundario cuyo IsVisible propiedad está establecida en false . Esto garantizará que el diseño personalizado no deja
espacio para elementos secundarios visibles.
1. [opcional] invalidar el InvalidateLayout método para recibir notificaciones cuando los elementos
secundarios se agregan o se quita del diseño. Para obtener más información, consulte invalidación del
método InvalidateLayout.
2. [opcional] invalidar el OnChildMeasureInvalidated método para recibir una notificación cuando uno de los
elementos secundarios del diseño cambia de tamaño. Para obtener más información, consulte invalidación
del método OnChildMeasureInvalidated.
NOTE
Tenga en cuenta que el OnMeasure override no se invoca si el tamaño del diseño se rige por su elemento primario, en
lugar de sus elementos secundarios. Sin embargo, se invocará la invalidación si una o ambas de las restricciones son
infinitos, o bien, si la clase de diseño no predeterminado HorizontalOptions o VerticalOptions los valores de
propiedad. Por este motivo, el LayoutChildren invalidación no puede depender de tamaños secundarios obtenidos
durante el OnMeasure llamada al método. En su lugar, LayoutChildren debe invocar el Measure método en elementos
secundarios del diseño, antes de invocar el Layout método. Como alternativa, el tamaño de los elementos secundarios se
obtuvo en el OnMeasure invalidación puede almacenarse en caché para evitar más adelante Measure invocaciones en el
LayoutChildren invalidación, pero la clase de diseño deberá saber cuándo es necesario volver a obtener los tamaños.
Para obtener más información, consulte calcular y almacenar en caché datos de diseño.
La clase de diseño puede utilizarse, a continuación, agregándolo a un Page y mediante la adición de elementos
secundarios para el diseño. Para obtener más información, consulte consumiendo el WrapLayout.
Creación de un WrapLayout
La aplicación de ejemplo muestra una orientación distinción WrapLayout clase que sus elementos secundarios se
organiza horizontalmente en la página y, a continuación, ajusta la presentación de los elementos secundarios
subsiguientes a las filas adicionales.
El WrapLayout clase asigna la misma cantidad de espacio para cada elemento secundario, conocido como el
tamaño de la celda, según el tamaño máximo de los elementos secundarios. Los elementos secundarios más
pequeños que el tamaño de celda se puede colocar dentro de la celda según sus HorizontalOptions y
VerticalOptions los valores de propiedad.
El layoutDataCache campo se utiliza para almacenar varios LayoutData valores. Cuando se inicia la aplicación,
dos LayoutData se almacenarán en caché de objetos en el layoutDataCache diccionario para la orientación
actual: uno para los argumentos de restricción a la OnMeasure invalidación y otra para el width y height
argumentos para el LayoutChildren invalidar. Al girar el dispositivo en orientación horizontal, el OnMeasure
invalidar y LayoutChildren se invocará nuevo reemplazo, lo que producirá dos otro LayoutData objetos que se
va a almacenar en caché en el diccionario. Sin embargo, cuando el dispositivo se vuelve a la orientación vertical,
ningún cálculo adicional es necesario porque el layoutDataCache ya tiene los datos necesarios.
El siguiente ejemplo de código muestra la GetLayoutData método, que calcula las propiedades de la LayoutData
estructurados según un tamaño determinado:
int visibleChildCount = 0;
Size maxChildSize = new Size();
int rows = 0;
int columns = 0;
LayoutData layoutData = new LayoutData();
if (visibleChildCount != 0)
{
// Calculate the number of rows and columns.
if (Double.IsPositiveInfinity(width))
{
columns = visibleChildCount;
rows = 1;
}
else
else
{
columns = (int)((width + ColumnSpacing) / (maxChildSize.Width + ColumnSpacing));
columns = Math.Max(1, columns);
rows = (visibleChildCount + columns - 1) / columns;
}
if (Double.IsPositiveInfinity(width))
cellSize.Width = maxChildSize.Width;
else
cellSize.Width = (width - ColumnSpacing * (columns - 1)) / columns;
if (Double.IsPositiveInfinity(height))
cellSize.Height = maxChildSize.Height;
else
cellSize.Height = (height - RowSpacing * (rows - 1)) / rows;
layoutDataCache.Add(size, layoutData);
return layoutData;
}
Invoca el controlador de cambio de propiedad de cada propiedad enlazable el InvalidateLayout invalidación del
método para desencadenar un nuevo diseño de pasar el WrapLayout . Para obtener más información, consulte
invalidación del método InvalidateLayout y invalidación del método OnChildMeasureInvalidated.
Invalidación del método OnMeasure
El OnMeasure invalidación se muestra en el ejemplo de código siguiente:
Invoca la invalidación del GetLayoutData método y construcciones un SizeRequest objeto a partir de los datos
devueltos, teniendo en cuenta también la RowSpacing y ColumnSpacing los valores de propiedad. Para obtener
más información sobre la GetLayoutData método, consulte calcular y almacenar en caché datos.
IMPORTANT
El Measure y OnMeasure métodos nunca deben solicitar una dimensión infinita devolviendo un SizeRequest valor con
una propiedad establecida en Double.PositiveInfinity . Sin embargo, al menos uno de los argumentos de restricción
OnMeasure puede ser Double.PositiveInfinity .
if (layoutData.VisibleChildCount == 0)
{
return;
}
double xChild = x;
double yChild = y;
int row = 0;
int column = 0;
La invalidación comienza con una llamada a la GetLayoutData método y, a continuación, enumera todos los
elementos secundarios para el tamaño y colocarlos dentro de la celda de cada elemento secundario. Esto se
logra invocando el LayoutChildIntoBoundingRegion método, que se usa para colocar un elemento secundario
dentro de un rectángulo en función de su HorizontalOptions y VerticalOptions los valores de propiedad. Esto
equivale a hacer una llamada a la secundaria Layout método.
NOTE
Tenga en cuenta que el rectángulo que se pasó a la LayoutChildIntoBoundingRegion método incluye el área completa
en el que puede residir el elemento secundario.
Para obtener más información sobre la GetLayoutData método, consulte calcular y almacenar en caché datos.
Invalidación del método InvalidateLayout
El InvalidateLayout invalidación se invoca cuando los elementos secundarios se agregan o quitan del diseño, o
cuando una de las WrapLayout Propiedades cambie el valor, como se muestra en el ejemplo de código siguiente:
La invalidación invalida el diseño del elemento secundario y descarta toda la información de diseño almacenado
en caché.
Consumir el WrapLayout
El WrapLayout clase puede utilizarse colocando en un Page tipo derivado, como se muestra en el ejemplo de
código XAML siguiente:
public ImageWrapLayoutPageCS()
{
wrapLayout = new WrapLayout();
Los elementos secundarios, a continuación, se pueden agregar a la WrapLayout según sea necesario. El siguiente
ejemplo de código muestra Image elementos que se agrega a la WrapLayout :
protected override async void OnAppearing()
{
base.OnAppearing();
return null;
}
Cuando la página que contiene el WrapLayout aparece, la aplicación de ejemplo de forma asincrónica obtiene
acceso a un archivo remoto de JSON que contiene una lista de fotos, crea un Image de fotografías para cada
elemento y lo agrega a la WrapLayout . El resultado es el aspecto que se muestra en las capturas de pantalla
siguiente:
Capturas de pantalla siguientes se muestra el WrapLayout después de se ha girado en orientación horizontal:
El número de columnas en cada fila depende del tamaño de fotografía, el ancho de pantalla y el número de
píxeles independientes del dispositivo unitario. El Image elementos cargar las fotos, de forma asincrónica y, por
tanto, el WrapLayout clase recibirán llamadas frecuentes a su LayoutChildren método cada Image elemento
recibe un nuevo tamaño en función de la fotografía cargada.
Vínculos relacionados
WrapLayout (ejemplo)
Diseños personalizados
Creación de los diseños personalizados en Xamarin.Forms (vídeo)
Diseño
Diseño
VisualElement
Compresión de diseño
11/07/2019 • 8 minutes to read • Edit Online
descargar el ejemplo
Compresión de diseño quita diseños especificados del árbol visual en un intento de mejorar el rendimiento de
representación de página. En este artículo se explica cómo habilitar la compresión de diseño y los beneficios que
puede ofrecer.
Información general
Xamarin.Forms se realiza mediante dos series de llamadas al método recursiva del diseño:
Diseño comienza en la parte superior del árbol visual con una página y pasa a través de todas las ramas del
árbol visual para abarcar todos los elementos visuales en una página. Los elementos que son elementos
primarios a otros elementos son responsables de ajuste de tamaño y la posición de sus elementos secundarios
en relación con ellos mismos.
Invalidación es el proceso por el cual un cambio en un elemento de una página desencadena un nuevo ciclo de
diseño. Los elementos se consideran no válidos cuando ya no tienen el tamaño correcto o la posición. Todos
los elementos en el árbol visual que tiene elementos secundarios es una alerta cuando cambia uno de sus
elementos secundarios tamaños. Por lo tanto, un cambio en el tamaño de un elemento en el árbol visual puede
provocar cambios que ripple el árbol.
Para obtener más información acerca de cómo realiza el diseño Xamarin.Forms, consulte crear un diseño
personalizado.
El resultado del proceso de diseño es una jerarquía de controles nativos. Sin embargo, esta jerarquía incluye los
representadores de contenedor adicional y contenedores de los representadores de plataforma, lo que infla aún
más la jerarquía de vistas de anidamiento. La profundidad del nivel de anidamiento, mayor será la cantidad de
trabajo que Xamarin.Forms tiene que realizar para mostrar una página. Para diseños complejos, la jerarquía de
vistas puede ser profunda y amplia, con varios niveles de anidamiento.
Por ejemplo, considere el siguiente botón desde la aplicación de ejemplo para iniciar sesión en Facebook:
Este botón se especifica como un control personalizado con la jerarquía de vistas XAML siguiente:
<ContentView ...>
<StackLayout>
<StackLayout ...>
<AbsoluteLayout ...>
<Button ... />
<Image ... />
<Image ... />
<BoxView ... />
<Label ... />
<Button ... />
</AbsoluteLayout>
</StackLayout>
<Label ... />
</StackLayout>
</ContentView>
Se puede examinar la jerarquía resultante de la vista anidada con Xamarin Inspector. En Android, la jerarquía de la
vista anidada contiene 17 vistas:
Compresión de diseño, que está disponible para las aplicaciones de Xamarin.Forms en las plataformas iOS y
Android, tiene como objetivo simplificar el anidamiento quitando diseños especificados del árbol visual, lo que
puede mejorar el rendimiento de la representación de la página de vistas. La ventaja de rendimiento que se
entrega varía según la complejidad de una página, la versión del sistema operativo que se va a usar y el
dispositivo en el que se ejecuta la aplicación. Sin embargo, las mejoras de rendimiento más importantes se
apreciarán en los dispositivos más antiguos.
NOTE
Aunque en este artículo se centra en los resultados de aplicar la compresión de diseño en Android, es igualmente aplicable a
iOS.
Compresión de diseño
En XAML, se puede habilitar la compresión de diseño estableciendo el CompressedLayout.IsHeadless propiedad
adjunta true en una clase de diseño:
<StackLayout CompressedLayout.IsHeadless="true">
...
</StackLayout>
Como alternativa, se puede habilitar en C# mediante la especificación de la instancia de diseño como el primer
argumento para el CompressedLayout.SetIsHeadless método:
CompressedLayout.SetIsHeadless(stackLayout, true);
IMPORTANT
Dado que la compresión de diseño quita un diseño el árbol visual, no es adecuado para los diseños que tienen una
apariencia visual, o que obtener la entrada táctil. Por lo tanto, los diseños que establezca VisualElement propiedades
(como BackgroundColor , IsVisible , Rotation , Scale , TranslationX y TranslationY o que aceptar
movimientos, no son candidatos para el diseño compresión. Sin embargo, habilitar la compresión de diseño en un diseño
que establece las propiedades de apariencia visual, o que acepta los gestos, no se producirá un error de compilación o en
tiempo de ejecución. En su lugar, se aplicará la compresión de diseño y las propiedades de apariencia visual y reconocimiento
de gestos, fallarán en modo silencioso.
Para el botón de Facebook, se puede habilitar la compresión de diseño en las clases de tres diseño:
<StackLayout CompressedLayout.IsHeadless="true">
<StackLayout CompressedLayout.IsHeadless="true" ...>
<AbsoluteLayout CompressedLayout.IsHeadless="true" ...>
...
</AbsoluteLayout>
</StackLayout>
...
</StackLayout>
En comparación con la jerarquía de vistas anidadas original de 17 vistas, esto representa una reducción en el
número de vistas de un 17%. Aunque esta reducción puede parecer insignificante, la reducción de la vista a través
de una página entera puede ser más importante.
Representadores rápidos
Los representadores rápidos reducen la inflación y los costos de representación de controles de Xamarin.Forms
en Android mediante la reducción de la jerarquía de vistas nativas resultante. Esto mejora aún más el rendimiento
porque crea menos objetos, lo que a su vez resulta en un árbol visual menos complejo y menos uso de memoria.
Para obtener más información sobre los representadores rápidos, consulte representadores rápidos.
Para el botón de Facebook en la aplicación de ejemplo, combinación de compresión de diseño y representadores
rápidos genera una jerarquía de vistas anidadas de 8 vistas:
En comparación con la jerarquía de vistas anidadas original de 17 vistas, esto representa una reducción de 52%.
La aplicación de ejemplo contiene una página que se extraen de una aplicación real. Sin compresión de diseño y
representadores rápidos, la página genera una jerarquía de vistas anidadas de 130 vistas en Android. Habilitación
de representadores rápidos y compresión de diseño en las clases de diseño apropiado, reduce la jerarquía de
vistas anidadas a 70 vistas, una reducción del 46%.
Resumen
Compresión de diseño quita diseños especificados del árbol visual en un intento de mejorar el rendimiento de
representación de página. La ventaja de rendimiento que esto ofrece varía según la complejidad de una página, la
versión del sistema operativo que se va a usar y el dispositivo en el que se ejecuta la aplicación. Sin embargo, las
mejoras de rendimiento más importantes se apreciarán en los dispositivos más antiguos.
Vínculos relacionados
Creación de un diseño personalizado
Representadores rápidos
LayoutCompression (ejemplo)
ListView de Xamarin.Forms
11/07/2019 • 5 minutes to read • Edit Online
descargar el ejemplo
ListView es una vista para presentar las listas de datos, especialmente las listas largas que requieren el
desplazamiento.
IMPORTANT
CollectionView es una vista para presentar las listas de datos mediante las especificaciones de diseño diferente. Su
objetivo es proporcionar una forma más flexible y una alternativa de alto rendimiento ListView . Para obtener más
información, consulte Xamarin.Forms CollectionView.
Casos de uso
Asegúrese de que ListView es el control adecuado para sus necesidades. ListView puede usarse en cualquier
situación donde se va a mostrar desplazables listas de datos. ListView admite acciones de contexto y enlace de
datos.
ListView no debe confundirse con TableView. El control de TableView es una mejor opción cada vez que tenga
una lista no enlazada de opciones o datos. Por ejemplo, la aplicación de configuración de iOS, que tiene un
conjunto de opciones predefinido en su mayoría, es más adecuada usar TableView que ListView.
También tenga en cuenta que es mejor un ListView adecuado para datos homogéneos – es decir, todos los
datos deben ser del mismo tipo. Esto es porque se puede usar un único tipo de celda para cada fila de la lista.
TableViews puede admitir varios tipos de celda, por lo que son una mejor opción cuando necesite combinar las
vistas.
Componentes
ListView tiene una serie de componentes disponibles para ejercer la funcionalidad nativa de cada plataforma.
Cada uno de estos componentes se describe a continuación:
Encabezados y pies de página – texto o vista para mostrar al principio y al final de una lista, separar de los
datos de la lista. Encabezados y pies de página se pueden enlazar a un origen de datos independientemente
del origen de datos del ListView.
Grupos – datos en un ListView se pueden agrupar para navegar más fácilmente. Normalmente, los grupos
están enlazados a datos:
Las celdas – datos en un ListView se presentan en las celdas. Cada celda corresponde a una fila de datos.
Hay celdas integradas que puede elegir, o puede definir su propia celda personalizada. Las celdas integradas
y personalizadas pueden ser usa/definido en XAML o código.
Integrada – integrada en las celdas, especialmente TextCell y ImageCell, puede ser bueno para el
rendimiento, puesto que corresponden a los controles nativos en cada plataforma.
TextCell – muestra una cadena de texto, opcionalmente con detalle. Texto de detalle se
representa como una segunda línea en una fuente menor con un color de énfasis.
ImageCell – muestra una imagen con texto. Aparece como un TextCell con una imagen de la
izquierda.
Las celdas personalizadas – celdas personalizado son excelentes cuando se necesita para presentar
datos complejos. Por ejemplo, se podría usar una vista personalizada para presentar una lista de
canciones, incluido el álbum y el intérprete:
Para más información acerca de cómo personalizar las celdas de un ListView, consulte personalizar la
apariencia de una celda ListView.
Funcionalidad
ListView es compatible con un número de estilos de interacción, incluidos:
Incorporación de cambios para actualizar – ListView es compatible con la incorporación de cambios
para actualizar en cada plataforma.
Acciones de contexto – ListView admite tomar las medidas en elementos individuales en una lista. Por
ejemplo, puede implementar la acción de pasar el dedo en iOS, o mantenga pulsado acciones en Android.
Selección – puede escuchar las selecciones y deselections para realizar una acción cuando se pulsa una fila.
Para obtener más información acerca de las características de interactividad de ListView, vea acciones &
interactividad con ListView.
Vínculos relacionados
Trabajar con ListView (ejemplo)
Enlaces bidireccionales (ejemplo)
Integrado en las celdas (ejemplo)
Celdas personalizadas (ejemplo)
GROUPING (ejemplo)
Vista de representador personalizado (ejemplo)
Interactividad de ListView (ejemplo)
Orígenes de datos de ListView
11/07/2019 • 5 minutes to read • Edit Online
descargar el ejemplo
Un ListView se utiliza para mostrar listas de datos. Aprenderemos acerca de cómo rellenar un ListView con datos
y cómo podemos enlazar al elemento seleccionado.
ItemsSource
Un ListView se rellena con datos mediante el ItemsSource propiedad, que puede aceptar cualquier colección que
implementa IEnumerable . La manera más sencilla para rellenar un ListView implica el uso de una matriz de
cadenas:
<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>
Enlace de datos
Enlace de datos es la "adherencia" que enlaza las propiedades de un objeto de interfaz de usuario a las propiedades
de un objeto CLR, como una clase en ViewModel. Enlace de datos es útil porque simplifica el desarrollo de
interfaces de usuario mediante la sustitución mucha aburrido código reutilizable.
Enlace de datos funciona manteniendo los objetos sincronizados a medida que cambian sus valores enlazados. En
lugar de tener que escribir controladores de eventos para cada vez que cambia el valor de un control, establecer el
enlace y habilitar el enlace en ViewModel.
Para obtener más información sobre el enlace de datos, vea conceptos básicos del enlace de datos que es la cuarta
parte de la serie de artículos de conceptos básicos de XAML de Xamarin.Forms.
Enlazar celdas
Propiedades de celdas (y elementos secundarios de las celdas) se pueden enlazar a propiedades de objetos en el
ItemsSource . Por ejemplo, podría usarse un ListView para presentar una lista de empleados.
La clase employee:
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"});
}
Tenga en cuenta que el enlace es el programa de instalación en el código por motivos de simplicidad, aunque
podría haber enlazado en XAML.
El bit de XAML anterior define un ContentPage que contiene un ListView . El origen de datos de la ListView se
establece a través de la ItemsSource atributo. El diseño de cada fila de la ItemsSource se define dentro el
ListView.ItemTemplate elemento.
Éste es el resultado:
Enlace SelectedItem
A menudo conveniente enlazar con el elemento seleccionado de un ListView , en lugar de usar un controlador de
eventos para responder a cambios. Para hacer esto en XAML, enlazar la SelectedItem propiedad:
<ListView x:Name="listView"
SelectedItem="{Binding Source={x:Reference SomeLabel},
Path=Text}">
…
</ListView>
Suponiendo que listView del ItemsSource es una lista de cadenas, SomeLabel tendrán su propiedad text enlazada
a la SelectedItem .
Vínculos relacionados
Enlaces bidireccionales (ejemplo)
Personalizar la apariencia de una celda de ListView
11/07/2019 • 10 minutes to read • Edit Online
descargar el ejemplo
ListView presenta listas desplazables, que se pueden personalizar mediante el uso de ViewCell s. ViewCells
puede usarse para mostrar texto e imágenes, que indica un estado verdadero/falso y recibir datos de entrada del
usuario.
Integrado en celdas
Xamarin.Forms incluye celdas integradas que funcionan para muchas aplicaciones simples:
TextCell – para mostrar texto
ImageCell – para mostrar una imagen con texto.
Las otras dos celdas SwitchCell y EntryCell están disponibles, pero no se usan habitualmente con ListView .
Consulte TableView para obtener más información acerca de estas celdas.
TextCell
TextCell es una celda para mostrar texto, opcionalmente con una segunda línea como texto de detalle.
TextCells se representan como controles nativos en tiempo de ejecución, por lo que es muy buen rendimiento en
comparación con una personalizada ViewCell . TextCells son personalizables, lo que permite establecer:
Text – el texto que se muestra en la primera línea, en el tamaño de fuente.
Detail – el texto que se muestra debajo de la primera línea, en una fuente menor.
TextColor – el color del texto.
DetailColor – el color del texto de detalle
ImageCell
ImageCell , como TextCell , se puede usar para mostrar texto y texto de detalles secundario y ofrece un
excelente rendimiento mediante el uso de controles nativos de cada plataforma. ImageCell difiere de TextCell
que muestra una imagen a la izquierda del texto.
ImageCell es útil cuando se necesita mostrar una lista de los datos con un aspecto visual, como una lista de
contactos o películas. ImageCells son personalizables, lo que permite establecer:
Text – el texto que se muestra en la primera línea, en el tamaño de fuente
Detail – el texto que se muestra debajo de la primera línea, en una fuente menor
TextColor – el color del texto
DetailColor – el color del texto de detalle
ImageSource – la imagen que se muestra al lado del texto
Celdas personalizadas
Cuando las celdas integradas no proporcionan el diseño necesarias, celdas personalizadas implementan el
diseño necesarias. Por ejemplo, desea presentar una celda con dos etiquetas que tengan el mismo peso. Un
TextCell sería suficiente porque la TextCell tiene una etiqueta que sea más pequeña. La mayoría de las
personalizaciones de celda agregan datos adicionales de solo lectura (por ejemplo, etiquetas adicionales,
imágenes u otra información de presentación).
Todas las celdas personalizadas deben derivarse de ViewCell , la misma clase base que todos los de la celda
integrada tipos de uso.
Xamarin.Forms 2 presentó un nuevo comportamiento de almacenamiento en caché en el ListView control que
se puede establecer para mejorar el rendimiento de desplazamiento para algunos tipos de celdas
personalizadas.
Este es un ejemplo de una celda personalizada:
XAML
El XAML para crear el diseño anterior está por debajo:
//set bindings
left.SetBinding (Label.TextProperty, "title");
right.SetBinding (Label.TextProperty, "subtitle");
image.SetBinding (Image.SourceProperty, "image");
Tenga en cuenta que el constructor de DataTemplate toma un tipo. El operador typeof Obtiene el tipo CLR para
CustomCell .
Cambios de contexto de enlace
Al enlazar a un tipo de celda personalizado BindableProperty instancias, los controles de interfaz de usuario
mostrar el BindableProperty valores deben usar el OnBindingContextChanged invalide para establecer los datos
que se mostrará en cada celda, en lugar de al constructor de la celda, como se muestra en el ejemplo de código
siguiente:
if (BindingContext != null) {
nameLabel.Text = Name;
ageLabel.Text = Age.ToString ();
locationLabel.Text = Location;
}
}
}
NOTE
Cuando se reemplaza OnBindingContextChanged , asegúrese de que la clase base OnBindingContextChanged se llama al
método para que los delegados registrados reciban el BindingContextChanged eventos.
En XAML, el tipo de celda personalizado de enlace a datos puede lograrse tal como se muestra en el ejemplo de
código siguiente:
<ListView x:Name="listView">
<ListView.ItemTemplate>
<DataTemplate>
<local:CustomCell Name="{Binding Name}" Age="{Binding Age}" Location="{Binding Location}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Esto enlaza el Name , Age , y Location propiedades enlazables en el CustomCell instancia, el Name , Age ,y
Location las propiedades de cada objeto de la colección subyacente.
Vínculos relacionados
Integrado en las celdas (ejemplo)
Celdas personalizadas (ejemplo)
Cambiar de contexto de enlace (ejemplo)
Personalizar la apariencia de ListView
11/07/2019 • 11 minutes to read • Edit Online
descargar el ejemplo
ListView tiene la capacidad para controlar la presentación de la lista, además del ViewCell instancias para cada
fila de la lista.
Agrupar
A menudo, grandes conjuntos de datos pueden ser difícil de manejar cuando se presentan en una lista desplazable
continuamente. Habilitar agrupación puede mejorar la experiencia del usuario en estos casos organizar mejor el
contenido y activando controles específicos de la plataforma que facilitan la navegación de datos.
Cuando se activa la agrupación por una ListView , se agrega una fila de encabezado para cada grupo.
Para habilitar la agrupación:
Crear una lista de listas (una lista de grupos, cada grupo que se va a obtener una lista de elementos).
Establecer el ListView del ItemsSource a dicha lista.
Establecer IsGroupingEnabled en true.
Establecer GroupDisplayBinding para enlazar a la propiedad de los grupos que se usa como el título del grupo.
[Opcional] Establecer GroupShortNameBinding para enlazar a la propiedad de los grupos que se usa como el
nombre corto para el grupo. El nombre corto se utiliza para las listas de salto (columna derecha en iOS ).
Empiece por crear una clase para los grupos:
En el código anterior, All es la lista que se asignará a nuestra ListView como origen de enlace. Title y
ShortName son las propiedades que se usará para los encabezados de grupo.
En esta fase, All es una lista vacía. Agregue un constructor estático para que se rellenará la lista en el inicio del
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
}
En el código anterior, también lo llamemos Add en elementos de groups , que son instancias del tipo
PageTypeGroup . Esto es posible porque PageTypeGroup hereda de List<PageModel> . Este es un ejemplo de la lista de
patrón de listas que se ha indicado anteriormente.
Este es el XAML para mostrar la lista agrupada:
En XAML:
<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>
Visibilidad de la barra de desplazamiento
ListView tiene HorizontalScrollBarVisibility y VerticalScrollBarVisibility propiedades, que obtención o
establece un ScrollBarVisibility valor que representa el momento de la barra de desplazamiento horizontal o
vertical, está visible. Ambas propiedades se pueden establecer en los siguientes valores:
Default indica el comportamiento de barra de desplazamiento predeterminado para la plataforma, y es el valor
predeterminado para el HorizontalScrollBarVisibility y VerticalScrollBarVisibility propiedades.
Always indica que las barras de desplazamiento serán visibles, incluso cuando el contenido se ajusta en la vista.
Never indica que las barras de desplazamiento no serán visibles, incluso si el contenido no se ajusta en la vista.
Separadores de fila
Se muestran las líneas de separación entre ListView elementos de forma predeterminada en iOS y Android. Si
prefiere ocultar las líneas de separación en iOS y Android, establezca el SeparatorVisibility propiedad en el
ListView. Las opciones para SeparatorVisibility son:
Default -muestra una línea de separación en iOS y Android.
Ninguno -oculta el separador en todas las plataformas.
Visibilidad predeterminada:
C#:
SepratorDemoListView.SeparatorVisibility = SeparatorVisibility.Default;
XAML:
<ListView x:Name="SeparatorDemoListView" SeparatorVisibility="Default" />
Ninguno:
C#:
SepratorDemoListView.SeparatorVisibility = SeparatorVisibility.None;
XAML:
SepratorDemoListView.SeparatorColor = Color.Green;
XAML:
Alto de fila
Todas las filas en una ListView tienen el mismo alto de forma predeterminada. ListView tiene dos propiedades que
pueden usarse para cambiar este comportamiento:
HasUnevenRows – true / false valor, las filas tienen diferentes alturas si establece en true . Tiene como valor
predeterminado false .
RowHeight – establece el alto de cada fila cuando HasUnevenRows es false .
Puede establecer el alto de todas las filas estableciendo el RowHeight propiedad en el ListView .
Alto de fila fijo personalizado
C#:
RowHeightDemoListView.RowHeight = 100;
XAML:
RowHeightDemoListView.HasUnevenRows = true;
XAML:
El OnImageTapped controlador de eventos se ejecuta en respuesta a una Image en una celda que se pulsa y
aumenta el tamaño de la Image mostrada en la celda para que lo esté viendo fácilmente.
Tenga en cuenta que hay grandes posibilidades de degradación del rendimiento si esta característica está
sobreutilizada.
Vínculos relacionados
GROUPING (ejemplo)
Vista de representador personalizado (ejemplo)
Cambiar el tamaño de las filas dinámicas (ejemplo)
notas de la versión 1.4
notas de la versión 1.3
Interactividad de ListView
11/07/2019 • 9 minutes to read • Edit Online
descargar el ejemplo
ListView admite la interacción con los datos que presenta.
Single indica que se puede seleccionar un solo elemento con el elemento seleccionado se resalta. Este es el
valor predeterminado.
None indica que no se pueden seleccionar elementos.
NOTE
El ItemTappedEventArgs (clase), que contiene los argumentos de evento para el ItemTapped evento tiene Group y
Item propiedades y un ItemIndex propiedad cuyo valor representa el índice de la ListView del elemento derivado. De
forma similar, el SelectedItemChangedEventArgs (clase), que contiene los argumentos de evento para el ItemSelected
evento, tiene un SelectedItem propiedad y un SelectedItemIndex propiedad cuyo valor representa el índice de la
ListView del elemento seleccionado.
Cuando el SelectionMode propiedad está establecida en Single , los elementos de la ListView puede
seleccionarse el ItemSelected y ItemTapped se desencadena eventos y el SelectedItem propiedad se establecerá
en el valor del elemento seleccionado.
Cuando el SelectionMode propiedad está establecida en None , los elementos de la ListView no puede
seleccionarse el ItemSelected no se desencadenará el evento y el SelectedItem propiedad permanecerá null .
Sin embargo, ItemTapped todavía se desencadena eventos y el elemento punteado aparecerán resaltado
brevemente durante la derivación.
Cuando se selecciona un elemento y el SelectionMode se cambia la propiedad de Single a None , SelectedItem
propiedad se establecerá en null y ItemSelected se desencadenará el evento con un null elemento.
El siguientes capturas de pantalla se muestra un ListView con el modo de selección predeterminado:
Deshabilitar selección
Para deshabilitar ListView selección conjunto el SelectionMode propiedad None :
Acciones de contexto
A menudo, los usuarios deseen realizar acciones en un elemento en un ListView . Por ejemplo, considere la
posibilidad de obtener una lista de mensajes de correo electrónico en la aplicación de correo. En iOS, puede
deslizar para eliminar un mensaje::
Acciones de contexto se pueden implementar en C# y XAML. A continuación encontrará guías específicas para
ambos, pero primero vamos a Eche un vistazo a algunos detalles de implementación clave para ambos.
Acciones de contexto se crean mediante MenuItem s. Los eventos TAP para MenuItems generados por el
MenuItem, no el ListView. Esto es diferente de cómo se controlan los eventos tap para las celdas, donde el
ListView provoca el evento en lugar de la celda. Dado que el ListView está provocando el evento, su controlador
de eventos tiene información de clave, al igual que el elemento se ha seleccionado o pulsa.
De forma predeterminada, un elemento de menú no tiene ninguna manera de saber qué celda pertenece.
CommandParameter está disponible en MenuItem para almacenar objetos, como el objeto subyacente ViewCell de
MenuItem. CommandParameter se puede establecer en XAML y C#.
C#
Acciones de contexto se pueden implementar en cualquier Cell subclase (siempre y cuando no se use como un
encabezado de grupo) mediante la creación de MenuItem s y agregarlas a la ContextActions colección para la
celda. Tiene las siguientes propiedades se pueden configurar para la acción de contexto:
Texto – la cadena que aparece en el elemento de menú.
Hacer clic en – el evento cuando se hace clic en el elemento.
IsDestructive – (opcional) cuando sea true el elemento se representa de forma diferente, en iOS.
Se pueden agregar varias acciones de contexto a una celda, pero solo uno debe tener IsDestructive establecido
en true . El código siguiente muestra cómo las acciones de contexto se agregarían a un ViewCell :
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 también se pueden crear mediante declaración en una colección de XAML. El XAML siguiente muestra
una celda personalizada con dos acciones 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>
NOTE
El NavigationPageRenderer para Android tiene una reemplazable UpdateMenuItemIcon método que se puede usar para
cargar los iconos de un personalizado Drawable . Esta invalidación permite usar las imágenes SVG como iconos en
MenuItem instancias en Android.
<ListView ...
IsPullToRefreshEnabled="true" />
listView.IsPullToRefreshEnabled = true;
Aparece un indicador giratorio durante la actualización, que es el negra de forma predeterminada. Sin embargo, se
puede cambiar el color del indicador giratorio en iOS y Android estableciendo el RefreshControlColor propiedad a
un Color :
<ListView ...
IsPullToRefreshEnabled="true"
RefreshControlColor="Red" />
listView.RefreshControlColor = Color.Red;
Las capturas de pantalla siguientes muestran Deslizar para actualizar tal y como se extrae el usuario:
Las capturas de pantalla siguientes muestran Deslizar para actualizar después de que el usuario ha soltado la
incorporación de cambios, con el control de número que se muestra mientras el ListView se está actualizando:
NOTE
Al definir un RefreshCommand , el CanExecute se puede especificar el método del comando para habilitar o deshabilitar el
comando.
Vínculos relacionados
Interactividad de ListView (ejemplo)
Rendimiento de ListView
11/07/2019 • 15 minutes to read • Edit Online
descargar el ejemplo
Al escribir aplicaciones móviles, es importante el rendimiento. Los usuarios han llegado a esperar el
desplazamiento suave y tiempos de carga rápida. No se puede satisfacer las expectativas de los usuarios de costo
que las clasificaciones en el almacén de aplicaciones o en el caso de una aplicación de línea de negocio, costo de su
organización tiempo y dinero.
Aunque ListView es una eficaz vista para mostrar los datos, tiene algunas limitaciones. El rendimiento del
desplazamiento puede verse afectado cuando se usa celdas personalizadas, especialmente cuando contienen
jerarquías de vista profundamente anidadas o utilicen algunos diseños que requieren una gran cantidad de
medida. Afortunadamente, hay técnicas que puede usar para evitar un rendimiento deficiente.
NOTE
La plataforma Universal de Windows (UWP) pasa por alto el RetainElement almacenamiento en caché de estrategia,
porque siempre usa almacenamiento en caché para mejorar el rendimiento. Por lo tanto, de forma predeterminada se
comporta como si la RecycleElement se aplica la estrategia de almacenamiento en caché.
RetainElement
El RetainElement estrategia de almacenamiento en caché especifica que el ListView generará una celda para cada
elemento en la lista y el valor predeterminado es ListView comportamiento. Por lo general debe utilizarse en las
siguientes circunstancias:
Cuando cada celda tiene un gran número de enlaces (20-30 +).
Cuando la plantilla de celda cambia con frecuencia.
Cuando las pruebas revelan que el RecycleElement almacenamiento en caché de resultados de la estrategia
una velocidad de ejecución reducida.
Es importante tener en cuenta las consecuencias de la RetainElement estrategia de almacenamiento en caché
cuando se trabaja con celdas personalizadas. Cualquier código de inicialización de la celda tendrá que ejecutar
para la creación de cada celda, que puede ser varias veces por segundo. En este caso, las técnicas de diseño que
eran aceptables en una página, como uso de varios anidados StackLayout instancias, se convierten en los cuellos
de botella de rendimiento cuando se programa de instalación y se destruye en tiempo real como el usuario se
desplaza.
RecycleElement
El RecycleElement estrategia de almacenamiento en caché especifica que el ListView intentará minimizar su
velocidad de consumo y la ejecución de memoria mediante el reciclado de celdas de la lista. Este modo no siempre
ofrece una mejora del rendimiento y las pruebas deben realizarse para determinar las mejoras. Sin embargo, suele
ser la opción preferida y debe usarse en las siguientes circunstancias:
Cuando cada celda tiene un pequeño o un número moderado de enlaces.
Cuando cada celda BindingContext define todos los datos de celda.
Cuando cada celda es similar en gran medida, con la plantilla de celda que no cambian.
Durante la virtualización de la celda tendrá su contexto de enlace que se actualiza y, por lo que si una aplicación
utiliza este modo debe asegurarse de que las actualizaciones de contexto de enlace se controlan apropiadamente.
Todos los datos sobre la celda deben proceder del contexto de enlace o se pueden producir errores de coherencia.
Esto puede realizarse mediante el uso de enlace de datos para mostrar datos de la celda. Como alternativa, se
deben establecer los datos de la celda la OnBindingContextChanged invalidar, en lugar de en el constructor de la
celda personalizada, como se muestra en el ejemplo de código siguiente:
public CustomCell ()
{
image = new Image();
View = image;
}
NOTE
El RecycleElement estrategia de almacenamiento tiene un requisito previo, introducido en 2.4 de Xamarin.Forms, que,
cuando un DataTemplateSelector se le pide que seleccione un DataTemplate que cada DataTemplate debe devolver el
mismo ViewCell tipo. Por ejemplo, dada una ListView con un DataTemplateSelector que puede devolver
MyDataTemplateA (donde MyDataTemplateA devuelve un ViewCell typu MyViewCellA ), o MyDataTemplateB (donde
MyDataTemplateB devuelve un ViewCell typu MyViewCellB ), cuando MyDataTemplateA devuelto debe devolver
MyViewCellA o se producirá una excepción.
RecycleElementAndDataTemplate
El RecycleElementAndDataTemplate estrategia de almacenamiento en caché se basa en el RecycleElement estrategia
de almacenamiento en caché asegurándose además que, cuando un ListView usa un DataTemplateSelector para
seleccionar un DataTemplate , DataTemplate s se almacenan en caché por el tipo de elemento de la lista. Por lo
tanto, DataTemplate s se seleccionan una vez por cada tipo de elemento, en lugar de una vez por cada instancia del
elemento.
NOTE
El RecycleElementAndDataTemplate estrategia de almacenamiento tiene un requisito previo que la DataTemplate s
devuelto por la DataTemplateSelector debe utilizar el DataTemplate constructor que toma un Type .
<ListView CachingStrategy="RecycleElement">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
...
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Esto tiene el mismo efecto que establecer el argumento de estrategia de almacenamiento en caché en el
constructor en C# Tenga en cuenta que no hay ningún CachingStrategy propiedad ListView .
Establecimiento de la estrategia de almacenamiento en caché en un ListView crean Subclase
Establecer el CachingStrategy atributo de XAML en una subclase ListView no producirá el comportamiento
deseado, porque no hay ningún CachingStrategy propiedad ListView . Además, si XAMLC está habilitado, se
producirá el siguiente mensaje de error: Ninguna propiedad, propiedad enlazable o evento encontrado
para 'CachingStrategy'
La solución a este problema consiste en especificar un constructor de subclases ListView que acepta un
ListViewCachingStrategy parámetro y lo pasa a la clase base:
public class CustomListView : ListView
{
public CustomListView (ListViewCachingStrategy strategy) : base (strategy)
{
}
...
}
<local:CustomListView>
<x:Arguments>
<ListViewCachingStrategy>RecycleElement</ListViewCachingStrategy>
</x:Arguments>
</local:CustomListView>
Vínculos relacionados
Vista de representador personalizado (ejemplo)
ViewCell de representador personalizado (ejemplo)
ListViewCachingStrategy
Mapa de Xamarin.Forms
11/07/2019 • 16 minutes to read • Edit Online
descargar el ejemplo
Xamarin.Forms utiliza la asignación nativa API en cada plataforma.
Xamarin.Forms.Maps para utiliza la asignación nativa API en cada plataforma. Esto proporciona una
experiencia rápida, familiar mapas para los usuarios, pero significa que algunos pasos de configuración son
necesarias para cumplir con requisitos de cada API de plataformas. Una vez configurado, el Map funciona igual
que cualquier otro elemento de Xamarin.Forms en el código común de control.
Se ha utilizado el control de mapa en el MapsSample ejemplo, que se muestra a continuación.
Funcionalidad de asignación se puede mejorar aún más mediante la creación de un asignar un representador
personalizado.
Xamarin.FormsMaps.Init();
Xamarin.FormsMaps.Init(this, bundle);
Xamarin.FormsMaps.Init("INSERT_AUTHENTICATION_TOKEN_HERE");
Agregue esta llamada en los siguientes archivos para cada plataforma:
iOS -archivo AppDelegate.cs en el FinishedLaunching método.
Android -archivo MainActivity.cs, en el OnCreate método.
UWP -archivo MainPage.xaml.cs, en el MainPage constructor.
Una vez que se ha agregado el paquete de NuGet y llama al método de inicialización dentro de cada aplicación,
Xamarin.Forms.Maps API pueden usarse en el proyecto de biblioteca estándar de .NET común o el código de
proyecto compartido.
Configuración de la plataforma
Se requieren pasos de configuración adicional en algunas plataformas antes de que se mostrará el mapa.
iOS
Para obtener acceso a servicios de ubicación en iOS, debe establecer las siguientes claves Info.plist:
iOS 11
NSLocationWhenInUseUsageDescription : para usar los servicios de ubicación cuando la aplicación está
en uso
NSLocationAlwaysAndWhenInUseUsageDescription : para usar los servicios de ubicación en todo
momento
iOS 10 y versiones anteriores
NSLocationWhenInUseUsageDescription : para usar los servicios de ubicación cuando la aplicación está
en uso
NSLocationAlwaysUsageDescription : para usar los servicios de ubicación en todo momento
Para admitir iOS 11 y versiones anteriores, puede incluir estas tres claves:
NSLocationWhenInUseUsageDescription , NSLocationAlwaysAndWhenInUseUsageDescription , y
NSLocationAlwaysUsageDescription .
La representación XML de estas claves en Info.plist se muestra a continuación. Debe actualizar el string
valores para que reflejen cómo la aplicación está utilizando la información de ubicación:
<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>
El Info.plist también se pueden agregar entradas en origen vista mientras edita el Info.plist archivo:
Android
Para usar el v2 de la API de Google Maps en Android debe generar una clave de API y agregarlo al proyecto
Android. Siga las instrucciones de la documentación de Xamarin obtención de una clave de API de Google
Maps v2. Después de seguir estas instrucciones, pegue la clave de API en el
Properties/Androidmanifest.XML archivo (ver código fuente y buscar o actualizar el elemento siguiente):
<application ...>
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="YOUR_API_KEY" />
</application>
Sin una clave de API válida, el control de mapas se mostrará como un cuadro gris en Android.
NOTE
Tenga en cuenta que, en orden para el APK tener acceso a Google Maps, debe incluir las huellas digitales de SHA-1 y
empaquetar los nombres para cada almacén de claves (debug y release) que usó para firmar el APK. Por ejemplo, si usa
un equipo para depuración y otro equipo para generar el APK de lanzamiento, debe incluir la huella digital de certificado
de SHA-1 desde el almacén de claves de depuración del primer equipo y la huella digital de certificado de SHA-1 desde el
almacén de claves de la versión de el segundo equipo. Recuerde también que modificar las credenciales de clave si la
aplicación nombre del paquete cambios. Consulte obtención de una clave de API de Google Maps v2.
También deberá habilitar los permisos adecuados, con el botón secundario en el proyecto de Android y
seleccione Opciones > compilar > aplicación de Android y funciona a la perfección lo siguiente:
AccessCoarseLocation
AccessFineLocation
AccessLocationExtraCommands
AccessMockLocation
AccessNetworkState
AccessWifiState
Internet
Los dos últimos son necesarios porque las aplicaciones requieren una conexión de red para descargar datos
del mapa. Obtenga información sobre Android permisos para obtener más información.
Además, 9 Android quitó la biblioteca de cliente Apache HTTP desde el bootclasspath, y por lo que no está
disponible para las aplicaciones destinadas a API 28 o superior. Se debe agregar la siguiente línea a la
application nodo de su AndroidManifest.xml archivo seguir usando el cliente HTTP de Apache en las
aplicaciones destinadas a API 28 o superior:
<application ...>
...
<uses-library android:name="org.apache.http.legacy" android:required="false" />
</application>
Tipo de mapa
También se puede cambiar el contenido del mapa estableciendo el MapType propiedad para mostrar un mapa
de calle normal (predeterminado), imágenes de satélite o una combinación de ambos.
map.MapType == MapType.Street;
PinType puede establecerse en uno de los valores siguientes, que pueden afectar a la manera en que se
procesa el pin (según la plataforma):
Genérico
Lugar
SavedPin
SearchResult
Clics de mapa
Map define un MapClicked evento que se desencadena cuando se pulsa el mapa. El MapClickedEventArgs
objeto que acompaña a la MapClicked el evento tiene una propiedad única denominada Position , del tipo
Position . Cuando se desencadena el evento, el valor de la Position propiedad está establecida en la
ubicación del mapa que se ha punteado.
En el ejemplo de código siguiente se muestra un controlador de eventos para el MapClicked eventos:
map.MapClicked += OnMapClicked;
En este ejemplo, el OnMapClicked controlador de eventos genera la latitud y longitud que representa la
ubicación del mapa derivados.
Crear un mapa en XAML
MAPS también se pueden crear en XAML, como se muestra en este ejemplo:
<?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 x:Name="MyMap"
Clicked="OnMapClicked"
WidthRequest="320"
HeightRequest="200"
IsShowingUser="true"
MapType="Hybrid" />
</StackLayout>
</ContentPage>
NOTE
Más xmlns definición de espacio de nombres es necesario para hacer referencia a los controles de xamarin.Forms.Maps
para.
El MapRegion y Pins se puede establecer en el código mediante la referencia con nombre para el Map :
MyMap.MoveToRegion(
MapSpan.FromCenterAndRadius(
new Position(37,-122), Distance.FromMiles(1)));
NOTE
La propiedad ItemTemplate tiene prioridad cuando están establecidas ambas propiedades ItemTemplate e
ItemTemplateSelector .
Un Map se pueden rellenar con datos mediante el uso de enlace de datos para enlazar su ItemsSource
propiedad a un IEnumerable colección:
<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>
El ItemsSource datos de la propiedad se enlaza a la Locations propiedad del modelo de vista conectada, que
devuelve un ObservableCollection de Location objetos, que es un tipo personalizado. Cada Location objeto
define Address y Description propiedades de tipo string y un Position propiedad de tipo Position .
La apariencia de cada elemento de la IEnumerable colección se define estableciendo la ItemTemplate
propiedad a un DataTemplate que contiene un Pin objeto que se enlaza a datos propiedades adecuadas.
El siguientes capturas de pantalla se muestra un Map mostrando un Pin colección utilizando el enlace de
datos:
<Grid>
...
<maps:Map x:Name="map"
ItemsSource="{Binding Locations}"
ItemTemplateSelector="{StaticResource MapItemTemplateSelector}" />
...
</Grid>
</ContentPage>
Vínculos relacionados
MapsSample
Asignar a un representador personalizado
Xamarin.Forms Samples (Ejemplos de Xamarin.Forms)
Creación de un Xamarin.Forms DataTemplateSelector
Selector de Xamarin.Forms
11/07/2019 • 3 minutes to read • Edit Online
La vista de selector es un control para seleccionar un elemento de texto en una lista de datos.
Xamarin.Forms Picker muestra una breve lista de elementos, desde el que el usuario puede seleccionar un
elemento. Picker define las siguientes propiedades:
Title de tipo string , cuyo valor predeterminado es null .
TitleColor de tipo Color , el color utilizado para mostrar el Title texto.
ItemsSource de tipo IList , la lista de origen de elementos para mostrar, cuyo valor predeterminado es null .
SelectedIndex de tipo int , el índice del elemento seleccionado, cuyo valor predeterminado es -1.
SelectedItem de tipo object , el elemento seleccionado, cuyo valor predeterminado es null .
TextColor de tipo Color , el color utilizado para mostrar el texto, cuyo valor predeterminado es
Color.Default .
FontAttributes de tipo FontAttributes , cuyo valor predeterminado es FontAtributes.None .
FontFamily de tipo string , cuyo valor predeterminado es null .
FontSize de tipo double , que de forma predeterminada va de -1,0.
Todas las propiedades están respaldados por BindableProperty objetos, lo que significa que puede cambiar el
estilo y las propiedades pueden ser destinos de enlaces de datos. El SelectedIndex y SelectedItem propiedades
tienen un modo de enlace predeterminada de BindingMode.TwoWay , lo que significa que pueden ser destinos de
enlaces de datos en una aplicación que utiliza el Model-View -ViewModel (MVVM ) arquitectura. Para obtener
información sobre cómo establecer las propiedades de fuente, consulte fuentes.
Un Picker no muestra ningún dato al que se muestra por primera vez. En su lugar, el valor de su Title
propiedad se muestra como un marcador de posición en las plataformas iOS y Android:
Cuando el Picker se muestra el enfoque de ganancias, sus datos y el usuario puede seleccionar un elemento:
El Picker se activa un SelectedIndexChanged eventos cuando el usuario selecciona un elemento. Después de
selección, se muestra el elemento seleccionado por el Picker :
Vínculos relacionados
Selector
Establecer la propiedad ItemsSource de un selector
11/07/2019 • 7 minutes to read • Edit Online
descargar el ejemplo
La vista de selector es un control para seleccionar un elemento de texto en una lista de datos. En este artículo se
explica cómo rellenar un selector de datos estableciendo la propiedad ItemsSource y cómo responder a la
selección de elementos por el usuario.
Xamarin.Forms 2.3.4 mejoró la Picker vista agregando la capacidad para rellenarlo con datos estableciendo sus
ItemsSource propiedad y para recuperar el elemento seleccionado de la SelectedItem propiedad. Además, se
puede cambiar el color del texto del elemento seleccionado estableciendo el TextColor propiedad a un Color .
<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
Tenga en cuenta que el x:Array elemento requiere un Type atributo que indica el tipo de los elementos de la matriz.
NOTE
Elemento de comportamiento de la selección en un Picker puede personalizarse en iOS con una plataforma específica.
Para obtener más información, consulte selección de elementos de control de selector de.
El ejemplo de código siguiente muestra cómo recuperar el SelectedItem valor de propiedad de la Picker en
XAML:
Además, puede ser un controlador de eventos se ejecuta cuando el SelectedIndexChanged desencadena el evento:
if (selectedIndex != -1)
{
monkeyNameLabel.Text = (string)picker.ItemsSource[selectedIndex];
}
}
Este método obtiene la SelectedIndex valor de propiedad y el valor se utiliza para recuperar el elemento
seleccionado de la ItemsSource colección. Esto es funcionalmente equivalente a recuperar el elemento
seleccionado de la SelectedItem propiedad. Tenga en cuenta que cada elemento de la ItemsSource colección es de
tipo object por lo que debe convertirse a un string para su presentación.
NOTE
Un Picker puede inicializarse para mostrar un elemento específico mediante el establecimiento del SelectedIndex o
SelectedItem propiedades. Sin embargo, estas propiedades deben establecerse después de inicializar el ItemsSource
colección.
El ItemsSource datos de la propiedad se enlaza a la Monkeys propiedad del modelo de vista conectada, que
devuelve un IList<Monkey> colección. El siguiente ejemplo de código muestra la Monkey (clase), que contiene
cuatro propiedades:
Cuando se enlaza a una lista de objetos, el Picker se le debe indicar qué propiedad para mostrar de cada objeto.
Esto se consigue estableciendo la ItemDisplayBinding propiedad a la propiedad necesaria de cada objeto. En los
ejemplos de código anteriores, el Picker está establecido para mostrar cada Monkey.Name valor de propiedad.
Responder a la selección de elemento
Enlace de datos puede usarse para establecer un objeto con el SelectedItem valor de propiedad cuando cambia:
El SelectedItem datos de la propiedad se enlaza a la SelectedMonkey propiedad del modelo de vista conectada,
que es de tipo Monkey . Por lo tanto, cuando el usuario selecciona un elemento en el Picker , SelectedMonkey se
establecerá la propiedad seleccionada Monkey objeto. El SelectedMonkey datos de objeto se muestran en la
interfaz de usuario Label y Image vistas:
NOTE
Tenga en cuenta que el SelectedItem y SelectedIndex ambas propiedades admiten enlaces bidireccionales de forma
predeterminada.
Vínculos relacionados
Demostración de selector (ejemplo)
Monkey App (ejemplo)
Selector de enlazable (ejemplo)
Selector de API
Adición de datos a la colección de elementos de un
selector
11/07/2019 • 3 minutes to read • Edit Online
descargar el ejemplo
La vista de selector es un control para seleccionar un elemento de texto en una lista de datos. En este artículo se
explica cómo rellenar un selector de datos, éste se agrega a la colección de elementos y cómo responder a la
selección de elementos por el usuario.
Además de agregar datos utilizando el Items.Add método, datos también se pueden insertar en la colección
utilizando el Items.Insert método.
if (selectedIndex != -1)
{
monkeyNameLabel.Text = picker.Items[selectedIndex];
}
}
Este método obtiene la SelectedIndex valor de propiedad y el valor se utiliza para recuperar el elemento
seleccionado de la Items colección. Dado que cada elemento de la Items colección es un string , se pueden
mostrar mediante un Label sin necesidad de realizar una conversión.
NOTE
Un Picker puede inicializarse para mostrar un elemento específico mediante el establecimiento del SelectedIndex
propiedad. Sin embargo, el SelectedIndex propiedad debe establecerse después de inicializar el Items colección.
Vínculos relacionados
Demostración de selector (ejemplo)
Selector
Xamarin.Forms ProgressBar
12/07/2019 • 4 minutes to read • Edit Online
Descargar el ejemplo
Xamarin.Forms ProgressBar es un control que se representa visualmente el progreso como una barra horizontal
que se rellena a un porcentaje representado por un float valor. El ProgressBar clase hereda de View .
La siguiente captura de pantalla muestra un ProgressBar en iOS y Android:
Estas propiedades están respaldadas por BindableProperty objetos, lo que significa que el ProgressBar puede
cambiar el estilo y ser el destino de los enlaces de datos.
El ProgressBar control también define un ProgressTo método que anima la barra de su valor actual en un valor
especificado. Para obtener más información, consulte animar un ProgressBar.
NOTE
El ProgressBar no acepta manipulación del usuario, por lo que se ha omitido al usar la tecla Tab para seleccionar los
controles.
Animar un ProgressBar
El ProgressTo método anima la ProgressBar desde su actual Progress valor a un valor proporcionado con el
tiempo. El método acepta un float progreso valor, un uint duración en milisegundos, un Easing valor enum y
devuelve un Task<bool> . El código siguiente muestra cómo animar una ProgressBar :
Para obtener más información sobre la Easing enumeración, consulte funciones de aceleración en
Xamarin.Forms.
Vínculos relacionados
Demostraciones de ProgressBar
Control deslizante de Xamarin.Forms
11/07/2019 • 22 minutes to read • Edit Online
descargar el ejemplo
Usar un control deslizante para seleccionar un intervalo de valores continuos.
Xamarin.Forms Slider es una barra horizontal que se puede manipular por el usuario para seleccionar un
double valor desde un intervalo continuo.
WARNING
Internamente, el Slider garantiza que Minimum es menor que Maximum . Si Minimum o Maximum nunca se establecen
para que Minimum es menos Maximum , se produce una excepción. Consulte la precauciones sección para obtener más
información sobre cómo el Minimum y Maximum propiedades.
El Slider convierte la Value propiedad para que esté entre Minimum y Maximum , ambos inclusive. Si el Minimum
propiedad se establece en un valor mayor que el Value propiedad, el Slider establece la Value propiedad
Minimum . De forma similar, si Maximum está establecido en un valor menor que Value , a continuación, Slider
establece la Value propiedad a Maximum .
Slider define un ValueChanged evento que se desencadena cuando el Value cambios, ya sea a través de la
manipulación del usuario de la Slider o cuando el programa establece la Value propiedad directamente. Un
ValueChanged evento se desencadena cuando el Value propiedad se convierte como se describe en el párrafo
anterior.
El ValueChangedEventArgs objeto que acompaña a la ValueChanged eventos tiene dos propiedades, ambos de tipo
double : OldValue y NewValue . En el momento en el evento se desencadena, el valor de NewValue es el mismo
que el Value propiedad de la Slider objeto.
Slider También define DragStarted y DragCompleted eventos, que se activan al principio y al final de la acción de
arrastrar. A diferencia de la ValueChanged eventos, el DragStarted y DragCompleted solo se desencadenan los
eventos mediante la manipulación de usuario de la Slider . Cuando el DragStarted desencadena el evento, el
DragStartedCommand , del tipo ICommand , se ejecuta. De forma similar, cuando el DragCompleted desencadena el
evento, el DragCompletedCommand , del tipo ICommand , se ejecuta.
WARNING
No utilice opciones de diseño horizontal sin restricciones de Center , Start , o End con Slider . En Android y UWP, la
Slider contrae a una barra de longitud cero y en iOS, la barra es muy breve. Mantenga el valor predeterminado
HorizontalOptions de Fill y no use un ancho de Auto al poner Slider en un Grid diseño.
NOTE
El ThumbColor y ThumbImageSource propiedades son mutuamente excluyentes. Si se establecen ambas propiedades, la
ThumbImageSource propiedad tendrá prioridad.
El Sliderse inicializa para tener un Maximum propiedad de 360. El ValueChanged controlador de la Slider usa el
Value propiedad de la slider objeto para establecer el Rotation propiedad de la primera Label y usa el
String.Format método con el NewValue propiedad de la argumentos de evento para establecer el Text
propiedad del segundo Label . Estos dos enfoques para obtener el valor actual de la Slider son intercambiables.
Este es el programa que se ejecutan en iOS, Android y plataforma Universal de Windows (UWP ) dispositivos:
El segundo Label muestra el texto "(no inicializado)" hasta que el Slider se manipula, lo que hace que la
primera ValueChanged eventos se activen. Tenga en cuenta que el número de posiciones decimales que se
muestran es diferente para cada plataforma. Estas diferencias están relacionadas con las implementaciones de la
plataforma de la Slider y se describen más adelante en este artículo en la sección diferencias de implementación
de la plataforma.
Creación de un control deslizante en XAML
El XAML básica de control deslizante página funcionalmente es igual a código básico de control deslizante
pero se implementan principalmente en 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>
También es posible que el controlador de eventos obtener el Slider que está desencadenando el evento a través
de la sender argumento. El Value propiedad contiene el valor actual:
Si el Slider objeto se asignó un nombre en el archivo XAML con un x:Name atributo (por ejemplo, "slider") y, a
continuación, el controlador de eventos podría hacer referencia a ese objeto directamente:
<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>
El Rotation propiedad de la primera Label está enlazado a la Value propiedad de la Slider , ya que es el Text
propiedad del segundo Label con un StringFormat especificación. El enlaces básicos de control deslizante
página funciones un poco diferente de las dos páginas anteriores: Cuando aparece la página por primera vez, el
segundo Label muestra la cadena de texto con el valor. Esta es una ventaja del uso de enlace de datos. Para
mostrar texto sin el enlace de datos, deberá inicializar específicamente el Text propiedad de la Label o simular
una activación de la ValueChanged eventos llamando al controlador de eventos desde el constructor de clase.
Precauciones
El valor de la Minimum propiedad siempre debe ser menor que el valor de la Maximum propiedad. Causas de
fragmento de código siguiente el Slider para generar una excepción:
// Throws an exception!
Slider slider = new Slider
{
Minimum = 10,
Maximum = 20
};
El compilador de C# genera código que establece estas dos propiedades en la secuencia, y cuándo el Minimum
propiedad se establece en 10, es mayor que el valor predeterminado Maximum valor 1. Puede evitar la excepción
en este caso, establezca el Maximum propiedad primera:
Establecer Maximum a 20 no es un problema porque es mayor que el valor predeterminado Minimum el valor 0.
Cuando Minimum está establecido, el valor es menor que el Maximum valor de 20.
El mismo problema existe en XAML. Establecer las propiedades en un orden que garantiza que Maximum siempre
es mayor que Minimum :
<Slider Maximum="20"
Minimum="10" ... />
Puede establecer el Minimum y Maximum valores para números negativos, pero solo en un orden donde Minimum
es siempre menor que Maximum :
<Slider Minimum="-20"
Maximum="-10" ... />
El Value propiedad siempre es mayor o igual que el Minimum valor y menor o igual que Maximum . Si Value se
establece en un valor fuera de ese intervalo, el valor se convertirán para que se encuentran dentro del intervalo,
pero no se produce ninguna excepción. Por ejemplo, este código le no genere una excepción:
<Slider ValueChanged="OnSliderValueChanged"
Maximum="20"
Minimum="10" />
Cuando Minimum se establece en 10, Value también se establece en 10 y el ValueChanged desencadena el evento.
Esto puede ocurrir antes de que se ha construido el resto de la página y el controlador puede intentar hacer
referencia a otros elementos en la página que todavía no se han creado. Es posible que desea agregar algún
código para el ValueChanged controlador que busca null valores de otros elementos en la página. O bien, puede
establecer el ValueChanged controlador de eventos después de la Slider valores se hayan inicializado.
<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" />
<Slider x:Name="greenSlider"
ValueChanged="OnSliderValueChanged" />
<Slider x:Name="blueSlider"
ValueChanged="OnSliderValueChanged" />
Un ofrece tres Slider elementos de un intervalo de 0 a 255. El Slider elementos comparten el mismo
Style
ValueChanged controlador, que se implementa en el archivo de código subyacente:
public partial class RgbColorSlidersPage : ContentPage
{
public RgbColorSlidersPage()
{
InitializeComponent();
}
boxView.Color = Color.FromRgb((int)redSlider.Value,
(int)greenSlider.Value,
(int)blueSlider.Value);
}
}
Los primeros conjuntos de sección la Text propiedad de uno de los Label instancias en una cadena de texto
breve que indica el valor de la Slider en formato hexadecimal. A continuación, las tres Slider se tiene acceso a
las instancias para crear un Color valor de los componentes RGB:
<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" />
Como el Slider se manipulan elementos, el BoxView y Label elementos se actualizan desde el ViewModel:
El StringFormat componente de la Binding extensión de marcado está establecida para un formato de "F2" para
mostrar dos posiciones decimales. (Cadena de formato en los enlaces de datos se describe en el artículo aplicarles
un formato.) Sin embargo, la versión de UWP del programa se limita a los valores de 0, 0.1, 0.2... 0.9 y 1.0. Se
trata de un resultado directo de la implementación de la UWP Slider como se describió anteriormente en la
sección diferencias de implementación de la plataforma.
Vínculos relacionados
Ejemplo de demostraciones de control deslizante
API de control deslizante
Motor Xamarin.Forms paso a paso
11/07/2019 • 13 minutes to read • Edit Online
descargar el ejemplo
Use un motor paso a paso para seleccionar un valor numérico de un intervalo de valores.
Xamarin.Forms Stepper consta de dos botones etiquetados con menos y signos más. Estos botones pueden ser
manipulados por el usuario para seleccionar de forma incremental un double valor desde un intervalo de
valores.
El Stepper define cuatro propiedades de tipo double :
Increment es la cantidad para cambiar el valor seleccionado, su valor predeterminado de 1.
Minimum es el mínimo del intervalo, con un valor predeterminado de 0.
Maximum es el máximo del intervalo, con un valor predeterminado de 100.
Value es el valor del componente, que puede oscilar entre Minimum y Maximum y tiene un valor
predeterminado de 0.
Todas estas propiedades están respaldados por BindableProperty objetos. El Value propiedad tiene un modo de
enlace predeterminada de BindingMode.TwoWay , lo que significa que es adecuado como origen de enlace en una
aplicación que utiliza el Model-View -ViewModel (MVVM ) arquitectura.
WARNING
Internamente, el Stepper garantiza que Minimum es menor que Maximum . Si Minimum o Maximum nunca se
establecen para que Minimum es menos Maximum , se produce una excepción. Para obtener más información sobre cómo
el Minimum y Maximum propiedades, consulte precauciones sección.
El convierte la Value propiedad para que esté entre Minimum y Maximum , ambos inclusive. Si el
Stepper
Minimum propiedad se establece en un valor mayor que el Value propiedad, el Stepper establece la Value
propiedad Minimum . De forma similar, si Maximum está establecido en un valor menor que Value , a continuación,
Stepper establece la Value propiedad a Maximum .
Stepper define un ValueChanged evento que se desencadena cuando el Value cambios, ya sea a través de la
manipulación del usuario de la Stepper o cuando la aplicación establece el Value propiedad directamente. Un
ValueChanged evento se desencadena cuando el Value propiedad se convierte como se describe en el párrafo
anterior.
El objeto que acompaña a la ValueChanged eventos tiene dos propiedades, ambos de tipo
ValueChangedEventArgs
double : OldValue y NewValue . En el momento en el evento se desencadena, el valor de NewValue es el mismo
que el Value propiedad de la Stepper objeto.
El Stepperse inicializa para tener un Maximum propiedad de 360 y un Increment propiedad de 30. Manipular el
Stepper cambia el valor seleccionado de forma incremental entre Minimum a Maximum según el valor de la
Increment propiedad. El ValueChanged controlador de la Stepper usa el Value propiedad de la stepper objeto
para establecer el Rotation propiedad de la primera Label y usa el string.Format método con el NewValue
propiedad de los argumentos de evento para establecer el Text propiedad de la segundo Label . Estos dos
enfoques para obtener el valor actual de la Stepper son intercambiables.
Capturas de pantalla siguientes se muestra el motor paso a paso de código básico página:
El segundo Label muestra el texto "(no inicializado)" hasta que el Stepper se manipula, lo que hace que la
primera ValueChanged eventos en activarse.
Creación de un motor paso a paso en XAML
El XAML básica de motor paso a paso página funcionalmente es igual a motor paso a paso de código
básico pero se implementan principalmente en 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>
También es posible que el controlador de eventos obtener el Stepper que está desencadenando el evento a
través de la sender argumento. El Value propiedad contiene el valor actual:
Si el Stepper objeto se asignó un nombre en el archivo XAML con un x:Name atributo (por ejemplo,
"componente") y, a continuación, el controlador de eventos podría hacer referencia a ese objeto directamente:
<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>
El Rotation propiedad de la primera Label está enlazado a la Value propiedad de la Stepper , ya que es el
Text propiedad del segundo Label con un StringFormat especificación. El enlaces básicos de motor paso a
paso página funciones un poco diferente de las dos páginas anteriores: Cuando aparece la página por primera
vez, el segundo Label muestra la cadena de texto con el valor. Esta es una ventaja del uso de enlace de datos.
Para mostrar texto sin el enlace de datos, deberá inicializar específicamente el Text propiedad de la Label o
simular una activación de la ValueChanged eventos llamando al controlador de eventos desde el constructor de
clase .
Precauciones
El valor de la Minimum propiedad siempre debe ser menor que el valor de la Maximum propiedad. Causas de
fragmento de código siguiente el Stepper para generar una excepción:
// Throws an exception!
Stepper stepper = new Stepper
{
Minimum = 180,
Maximum = 360
};
El C# compilador genera código que establece estas dos propiedades en la secuencia, y cuándo el Minimum
propiedad está establecida en 180, es mayor que el valor predeterminado Maximum valor de 100. Puede evitar la
excepción en este caso, establezca el Maximum propiedad primera:
Establecer Maximum a 360 no es un problema porque es mayor que el valor predeterminado Minimum el valor 0.
Cuando Minimum está establecido, el valor es menor que el Maximum valor de 360.
El mismo problema existe en XAML. Establecer las propiedades en un orden que garantiza que Maximum siempre
es mayor que Minimum :
<Stepper Maximum="360"
Minimum="180" ... />
Puede establecer el Minimum y Maximum valores para números negativos, pero solo en un orden donde Minimum
es siempre menor que Maximum :
<Stepper Minimum="-360"
Maximum="-180" ... />
El Value propiedad siempre es mayor o igual que el Minimum valor y menor o igual a Maximum . Si Value se
establece en un valor fuera de ese intervalo, el valor se convertirán para que se encuentran dentro del intervalo,
pero no se produce ninguna excepción. Por ejemplo, este código le no genere una excepción:
Cuando Minimum está establecido en 180, a continuación, Value también está establecido en 180.
Si un ValueChanged se ha adjuntado el controlador de eventos en el momento en que el Value propiedad se
convierte en algo distinto de su valor predeterminado de 0, entonces un ValueChanged desencadena el evento.
Este es un fragmento de XAML:
<Stepper ValueChanged="OnStepperValueChanged"
Maximum="360"
Minimum="180" />
Cuando Minimum está establecido en 180, Value también está establecido en 180 y el ValueChanged
desencadena el evento. Esto puede ocurrir antes de que se ha construido el resto de la página y el controlador
puede intentar hacer referencia a otros elementos en la página que todavía no se han creado. Es posible que
desea agregar algún código para el ValueChanged controlador que busca null valores de otros elementos en la
página. O bien, puede establecer el ValueChanged controlador de eventos después de la Stepper valores se hayan
inicializado.
Vínculos relacionados
Ejemplo de demostraciones de motor paso a paso
API de motor paso a paso
Aplicaciones de Xamarin.Forms de estilo
11/07/2019 • 2 minutes to read • Edit Online
Introducción
A menudo, las aplicaciones de Xamarin.Forms contienen varios controles que tienen una apariencia idéntica.
Establecer la apariencia de cada control individual puede ser repetitiva y propensas a errores. En su lugar, se
pueden crear estilos que personalizar la apariencia del control mediante la agrupación y establecer las
propiedades disponibles en el tipo de control.
Estilos explícitos
Un explícita estilo es aquel que se aplica de manera selectiva a los controles estableciendo sus Style
propiedades.
Estilos implícitos
Un implícita estilo es aquella que se usa por todos los controles del mismo TargetType , sin necesidad de cada
control para hacer referencia al estilo.
Estilos globales
Los estilos pueden estar disponibles globalmente agregándolos a la aplicación ResourceDictionary . Esto ayuda a
evitar la duplicación de estilos a través de las páginas o controles.
Herencia de estilo
Los estilos pueden heredar de otros estilos para reducir la duplicación y habilitar la reutilización.
Estilos dinámicos
Los estilos no responder a los cambios de propiedad y permanecen sin cambios para la duración de una
aplicación. Sin embargo, las aplicaciones pueden responder a cambios de estilo dinámicamente en tiempo de
ejecución mediante el uso de recursos dinámicos.
Estilos de dispositivo
Xamarin.Forms incluye seis dinámica estilos, conocidos como dispositivo estilos, en el Devices.Styles clase.
Todos los seis estilos pueden aplicarse a Label solo instancias.
Clases de estilo
Las clases de estilo de Xamarin.Forms permiten varios estilos para aplicarse a un control, sin tener que recurrir a
la herencia de estilo.
Introducción a los estilos de Xamarin.Forms
11/07/2019 • 7 minutes to read • Edit Online
Los estilos permiten la apariencia de los elementos visuales para personalizarse. Los estilos se definen para un tipo
específico y contienen valores para las propiedades disponibles en ese tipo.
A menudo, las aplicaciones de Xamarin.Forms contienen varios controles que tienen una apariencia idéntica. Por
ejemplo, una aplicación puede tener varios Label instancias que tienen las mismas opciones de fuente y las
opciones de diseño, como se muestra en el ejemplo de código XAML siguiente:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Styles.NoStylesPage"
Title="No Styles"
IconImageSource="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>
Cada Label instancia tiene valores idénticos de propiedad para controlar la apariencia del texto mostrado por el
Label . El resultado es el aspecto que se muestra en las capturas de pantalla siguientes:
Establecer la apariencia de cada control individual puede ser repetitiva y propensas a errores. En su lugar, puede
crearse un estilo que define la apariencia y, a continuación, se aplica a los controles necesarios.
Crear un estilo
El Style clase agrupa una colección de valores de propiedad en un objeto que, a continuación, se puede aplicar a
varias instancias del elemento visual. Esto ayuda a reducir el marcado repetitivo y permite una apariencia de las
aplicaciones a cambiarse más fácilmente.
Aunque los estilos se han diseñado principalmente para aplicaciones basadas en XAML, también se pueden crear
en C#:
Style las instancias creadas en XAML se definen normalmente en un ResourceDictionary que se asigna a la
Resources colección de un control, página, o a la Resources recolección de la aplicación.
Style las instancias creadas en C# normalmente se definen en la clase de página o en una clase que se puede
acceder de forma global.
La elección de dónde se puede definir una instancia de Style afecta a dónde se puede usar:
Style las instancias definidas en el nivel de control solo pueden aplicarse al control y a sus elementos
secundarios.
Style las instancias definidas en el nivel de página sólo pueden aplicarse a la página y a sus elementos
secundarios.
Style las instancias definidas en el nivel de aplicación se pueden aplicar a lo largo de la aplicación.
Cada Style instancia contiene una colección de uno o varios Setter objetos, con cada Setter tener un
Property y un Value . El Property es el nombre de la propiedad enlazable del elemento que se aplica el estilo, y el
Value es el valor que se aplica a la propiedad.
Para aplicar un Style , el objeto de destino debe ser un VisualElement que coincide con el TargetType valor de
propiedad de la Style , tal y como se muestra en el ejemplo de código XAML siguiente:
Estilos de más abajo en la jerarquía de vistas tienen prioridad sobre las define mayor seguridad. Por ejemplo, si se
establece un Style que establece Label.TextColor a Red en la aplicación de nivel serán reemplazado por un
estilo de nivel de página establece Label.TextColor a Green . De forma similar, un estilo de nivel de página se
reemplazará por un estilo de nivel de control. Además, si Label.TextColor se establece directamente en una
propiedad de control, esto tiene prioridad sobre los estilos.
Los artículos de esta sección se muestran y se explica cómo crear y aplicar explícita y implícita estilos, cómo crear
estilos globales, aplicar el estilo de herencia, cómo responder a los cambios de estilo en tiempo de ejecución y
cómo usar los estilos integrados incluidos en Xamarin.Forms.
NOTE
¿Qué es StyleId?
Anteriores a Xamarin.Forms 2.2, el StyleId propiedad se utiliza para identificar los elementos individuales de una aplicación
para la identificación en las pruebas de interfaz de usuario y en los motores de temas como Pixate. Sin embargo,
Xamarin.Forms 2.2 introdujo el AutomationId propiedad, que reemplazó el StyleId propiedad.
Vínculos relacionados
Extensiones de marcado XAML
Estilo
Establecedor
Estilos explícitos en Xamarin.Forms
11/07/2019 • 6 minutes to read • Edit Online
descargar el ejemplo
Un estilo explícito es aquella que se aplica de manera selectiva a los controles estableciendo sus propiedades de
estilo.
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.ExplicitStylesPage" Title="Explicit"
IconImageSource="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>
El ResourceDictionary define tres explícita estilos que se aplican a la página Label instancias. Cada Style se
utiliza para mostrar texto en un color diferente, y también establece la fuente de las opciones de diseño de tamaño
y horizontales y verticales. Cada Style se aplica a otro Label estableciendo su Style propiedades mediante el
StaticResource extensión de marcado. El resultado es el aspecto que se muestra en las capturas de pantalla
siguiente:
Además, el último Label tiene un Style aplicado a él, pero también invalida la TextColor propiedad a una
diferente Color valor.
Crear un estilo explícito en el nivel de control
Además de crear explícita estilos en el nivel de página, también pueden crearse en el nivel de control, tal como se
muestra en el ejemplo de código siguiente:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.ExplicitStylesPage" Title="Explicit"
IconImageSource="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>
En este ejemplo, el explícita Style instancias se asignan a la Resources colección de la StackLayout control. Los
estilos, a continuación, se aplican al control y sus elementos secundarios.
Para obtener información sobre cómo crear estilos en una aplicación ResourceDictionary , consulte estilos
globales.
El constructor define tres explícita estilos que se aplican a la página Label instancias. Cada explícita Style se
agrega a la ResourceDictionary utilizando el Add método, especifica un key cadena para hacer referencia a la
Style instancia. Cada Style se aplica a otro Label estableciendo sus Style propiedades.
Sin embargo, no hay ninguna ventaja en utilizar un ResourceDictionary aquí. En su lugar, Style instancias pueden
asignarse directamente a la Style las propiedades de los elementos visuales necesarios y el ResourceDictionary
puede quitarse, como se muestra en la siguiente ejemplo 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 }
}
};
}
}
El constructor define tres explícita estilos que se aplican a la página Label instancias. Cada Style se utiliza para
mostrar texto en un color diferente, y también establece la fuente de las opciones de diseño de tamaño y
horizontales y verticales. Cada Style se aplica a otro Label estableciendo su Style propiedades. Además, el
último Label tiene un Style aplicado a él, pero también invalida la TextColor propiedad en otro Color valor.
Vínculos relacionados
Extensiones de marcado XAML
Estilos básicos (ejemplo)
Trabajar con estilos (ejemplo)
ResourceDictionary
Estilo
Establecedor
Estilos implícitos en Xamarin.Forms
11/07/2019 • 7 minutes to read • Edit Online
descargar el ejemplo
Un estilo implícito es aquella que se usa por todos los controles de la mismo TargetType, sin necesidad de cada
control para hacer referencia al estilo.
El siguiente ejemplo de código muestra un implícita estilo declarado en XAML en una página ResourceDictionary y
se aplica a la página Entry instancias:
<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" IconImageSource="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>
El ResourceDictionary define una sola implícita estilo que se aplica a la página Entry instancias. El Style se usa
para mostrar el texto azul sobre un fondo amarillo, y también establece otras opciones de apariencia. El Style se
agrega a la página ResourceDictionary sin especificar un x:Key atributo. Por lo tanto, el Style se aplica a todas la
Entry implícitamente instancias que coinciden con el TargetType propiedad de la Style exactamente. Sin
embargo, el Style no se aplica a la CustomEntry instancia, que es una subclase Entry . El resultado es el aspecto
que se muestra en las capturas de pantalla siguiente:
Además, la cuarta Entry invalida la BackgroundColor y TextColor propiedades del estilo implícito a diferentes
Color valores.
<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" IconImageSource="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>
En este ejemplo, el implícita Style se asigna a la Resources colección de la StackLayout control. El implícita , a
continuación, se puede aplicar estilo al control y sus elementos secundarios.
Para obtener información sobre cómo crear estilos en una aplicación ResourceDictionary , consulte estilos
globales.
...
Resources = new ResourceDictionary ();
Resources.Add (entryStyle);
El constructor define una sola implícita estilo que se aplica a la página Entry instancias. El Style se usa para
mostrar el texto azul sobre un fondo amarillo, y también establece otras opciones de apariencia. El Style se
agrega a la página ResourceDictionary sin especificar un key cadena. Por lo tanto, el Style se aplica a todas la
Entry implícitamente instancias que coinciden con el TargetType propiedad de la Style exactamente. Sin
embargo, el Style no se aplica a la CustomEntry instancia, que es una subclase Entry .
El ejemplo siguiente muestra un estilo implícito que establece el color de fondo Button instancias a rojo:
<Style TargetType="Button"
ApplyToDerivedTypes="True">
<Setter Property="BackgroundColor"
Value="Red" />
</Style>
Colocación de este estilo en un nivel de página ResourceDictionary dará como resultado lo que se aplica a todos
los Button instancias en la página así como todos los controles que derivan de Button . Sin embargo, si la
ApplyToDerivedTypes permaneció sin establecer la propiedad, el estilo se aplicaría solo a Button instancias.
Vínculos relacionados
Extensiones de marcado XAML
Estilos básicos (ejemplo)
Trabajar con estilos (ejemplo)
ResourceDictionary
Estilo
Establecedor
Estilos globales en Xamarin.Forms
11/07/2019 • 5 minutes to read • Edit Online
descargar el ejemplo
Los estilos pueden estar disponibles globalmente agregándolas al diccionario de recursos de la aplicación. Esto
ayuda a evitar la duplicación de estilos a través de las páginas o controles.
<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>
Esto ResourceDictionary define una sola explícita estilo, buttonStyle , que se usará para establecer el aspecto de
Button instancias. Sin embargo, pueden ser estilos globales explícita o implícita.
En el ejemplo de código siguiente se muestra una aplicación de página XAML el buttonStyle a la página Button
instancias:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.ApplicationStylesPage"
Title="Application" IconImageSource="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>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.ApplicationStylesPage"
Title="Application" IconImageSource="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>
La versión original buttonStyle , definido en el nivel de aplicación, se reemplaza por la buttonStyle instancia
definida en el nivel de página. Además, el estilo de nivel de página se haya reemplazado por el nivel de control
buttonStyle . Por lo tanto, el Button se muestran las instancias con texto azul, como se muestra en las capturas de
pantalla siguiente:
El constructor define una sola explícita estilo para aplicar a Button instancias a lo largo de la aplicación. Explícita
Style instancias se agregan a la ResourceDictionary utilizando el Add método, especificando un key cadena
para hacer referencia a la Style instancia. El Style instancia, a continuación, se puede aplicar a todos los
controles del tipo correcto en la aplicación. Sin embargo, pueden ser estilos globales explícita o implícita.
El ejemplo de código siguiente muestra un C# página aplicando el buttonStyle a la página Button instancias:
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"]
}
}
};
}
}
El buttonStyle se aplica a la Button instancias estableciendo sus Style propiedades y controla la apariencia de la
Button instancias.
Vínculos relacionados
Extensiones de marcado XAML
Estilos básicos (ejemplo)
Trabajar con estilos (ejemplo)
ResourceDictionary
Estilo
Establecedor
Herencia de estilo en Xamarin.Forms
11/07/2019 • 6 minutes to read • Edit Online
descargar el ejemplo
Los estilos pueden heredar de otros estilos para reducir la duplicación y habilitar la reutilización.
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.StyleInheritancePage"
Title="Inheritance" IconImageSource="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>
NOTE
Un estilo implícito se puede derivar de un estilo explícito, pero no puede derivar un estilo explícito de un estilo implícito.
En este ejemplo, labelStyle y buttonStyle son los recursos de nivel de control mientras baseStyle es un recurso
de nivel de página. Sin embargo, mientras labelStyle y buttonStyle heredar baseStyle , no es posible que
baseStyle va a heredar labelStyle o buttonStyle , debido a sus respectivas ubicaciones en la jerarquía de vistas.
Herencia de estilo de C#
La página C# equivalente, donde Style instancias se asignan directamente a la Style propiedades de los
controles necesarios, se muestra en el ejemplo de código siguiente:
public class StyleInheritancePageCS : ContentPage
{
public StyleInheritancePageCS ()
{
var baseStyle = new Style (typeof(View)) {
Setters = {
new Setter {
Property = View.HorizontalOptionsProperty, Value = LayoutOptions.Center },
...
}
};
Vínculos relacionados
Extensiones de marcado XAML
Estilos básicos (ejemplo)
Trabajar con estilos (ejemplo)
ResourceDictionary
Estilo
Establecedor
Estilos dinámicos en Xamarin.Forms
11/07/2019 • 7 minutes to read • Edit Online
descargar el ejemplo
Los estilos no responder a los cambios de propiedad y permanecen sin cambios para la duración de una
aplicación. Por ejemplo, después de asignar un estilo a un elemento visual, si se modifica una de las instancias de
establecedor, quitar, o una nueva instancia de establecedor agregado, los cambios no se aplicará al elemento
visual. Sin embargo, las aplicaciones pueden responder a cambios de estilo dinámicamente en tiempo de ejecución
mediante el uso de recursos dinámicos.
El DynamicResource extensión de marcado es similar a la StaticResource extensión de marcado en ambos utilizan
una clave de diccionario para capturar un valor desde un ResourceDictionary . Sin embargo, mientras el
StaticResource realiza una búsqueda de diccionario único, el DynamicResource mantiene un vínculo a la clave del
diccionario. Por lo tanto, si se reemplaza la entrada del diccionario asociada con la clave, el cambio se aplica al
elemento visual. Esto permite que los cambios de estilo en tiempo de ejecución que se realiza en una aplicación.
En el ejemplo de código siguiente se muestra dinámica estilos en una 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"
IconImageSource="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>
El SearchBar instancias uso el DynamicResource extensión de marcado para hacer referencia a un Style
denominado searchBarStyle , que no está definido en el XAML. Sin embargo, dado que el Style propiedades de
la SearchBar instancias se establecen mediante un DynamicResource , falta la clave del diccionario no se produce
una excepción.
En su lugar, en el archivo de código subyacente, el constructor crea un ResourceDictionary entrada con la clave
searchBarStyle , tal y como se muestra en el ejemplo de código siguiente:
public partial class DynamicStylesPage : ContentPage
{
bool originalStyle = true;
public DynamicStylesPage ()
{
InitializeComponent ();
Resources ["searchBarStyle"] = Resources ["blueSearchBarStyle"];
}
[
] (dynamic-images/dynamic-style-green-
large.png#lightbox "Verde ejemplo estilo dinámico")
En el ejemplo de código siguiente se muestra la página equivalente en C#:
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"];
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.DynamicStylesInheritancePage"
Title="Dynamic Inheritance" IconImageSource="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>
El SearchBar instancias uso el StaticResource extensión de marcado para hacer referencia a un Style
denominado tealSearchBarStyle . Esto Style establece algunas propiedades adicionales y utiliza el
BaseResourceKey propiedad para hacer referencia a searchBarStyle . El DynamicResource extensión de marcado no
es necesaria porque tealSearchBarStyle no cambiará, excepto para el Style deriva de. Por lo tanto,
tealSearchBarStyle mantiene un vínculo a searchBarStyle y se modifica cuando cambia el estilo de base.
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"];
Vínculos relacionados
Extensiones de marcado XAML
Estilos dinámicos (ejemplo)
Trabajar con estilos (ejemplo)
ResourceDictionary
Estilo
Establecedor
Vídeo relacionado
Encuentre más vídeos de Xamarin en Channel 9 y YouTube.
Estilos de dispositivo en Xamarin.Forms
11/07/2019 • 4 minutes to read • Edit Online
descargar el ejemplo
Xamarin.Forms incluye seis estilos dinámicos, conocidos como estilos de dispositivo, en la clase Device.Styles.
El dispositivo estilos son:
BodyStyle
CaptionStyle
ListItemDetailTextStyle
ListItemTextStyle
SubtitleStyle
TitleStyle
Solo pueden aplicarse a todos los seis estilos Label instancias. Por ejemplo, un Label que muestra el cuerpo de
un párrafo puede establecer su Style propiedad BodyStyle .
En el ejemplo de código siguiente se muestra cómo utilizar el dispositivo estilos en una 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"
IconImageSource="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>
Los estilos de dispositivo están enlazados a usar el DynamicResource extensión de marcado. La naturaleza dinámica
de los estilos se puede ver en iOS cambiando el accesibilidad configuración para el tamaño del texto. La
apariencia de la dispositivo estilos es diferente en cada plataforma, como se muestra en las capturas de pantalla
siguiente:
Dispositivo estilos también se pueden derivar de estableciendo el BaseResourceKey propiedad para el nombre de
clave para el estilo del dispositivo. En el ejemplo de código anterior, myBodyStyle hereda BodyStyle y establece un
color de texto acentuados. Para obtener más información sobre la herencia de estilo dinámico, consulte herencia de
estilo dinámico.
En el ejemplo de código siguiente se muestra la página equivalente en C#:
Title = "Device";
IconImageSource = "csharp.png";
Padding = new Thickness (0, 20, 0, 0);
El Style propiedad de cada uno Label instancia se establece en la propiedad adecuada de la Devices.Styles
clase.
Accesibilidad
El dispositivo estilos respetan las preferencias de accesibilidad, por lo que cambiarán los tamaños de fuente que se
modifiquen las preferencias de accesibilidad en cada plataforma. Por lo tanto, para admitir texto accesible,
asegúrese de que el dispositivo estilos se usan como base para los estilos de texto dentro de la aplicación.
Las capturas de pantalla siguientes muestran los estilos de dispositivo en cada plataforma, con el menor tamaño
de fuente accesible:
Las capturas de pantalla siguientes muestran los estilos de dispositivo en cada plataforma, con el mayor tamaño de
fuente accesible:
Vínculos relacionados
Estilos de texto
Extensiones de marcado XAML
Estilos dinámicos (ejemplo)
Trabajar con estilos (ejemplo)
Device.Styles
ResourceDictionary
Estilo
Establecedor
Clases de estilo de Xamarin.Forms
11/07/2019 • 5 minutes to read • Edit Online
descargar el ejemplo
Las clases de estilo de Xamarin.Forms permiten varios estilos para aplicarse a un control, sin tener que recurrir a la
herencia de estilo.
IMPORTANT
Varios estilos pueden compartir el mismo nombre de clase, siempre se dirigen a distintos tipos. Esto permite que varias clases
de estilo, que son con el mismo nombre, a distintos tipos de destino.
El ejemplo siguiente muestra tres BoxView de estilo de las clases y un VisualElement clase 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>
El Separator , Rounded ,y Circle cada conjunto de clases de estilo BoxView propiedades con valores específicos.
El Rotatedestilo clase tiene un TargetType de VisualElement , lo que significa que sólo puede aplicarse a
VisualElement instancias. Sin embargo, su ApplyToDerivedTypes propiedad está establecida en true , lo que
garantiza que se puede aplicar a todos los controles que derivan de VisualElement , tales como BoxView . Para
obtener más información sobre cómo aplicar un estilo a un tipo derivado, consulte aplicar un estilo a los tipos
derivados.
El código de C# equivalente es:
<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>
En este ejemplo, la primera BoxView se ha adaptado para que sea un separador de línea, mientras que el tercer
BoxView es circular. El segundo BoxView dos clases de estilo aplicado a él, que asigne a TI redondeada esquinas y
giremoslo en 45 grados:
IMPORTANT
Varias clases de estilo se pueden aplicar a un control porque el StyleClass propiedad es de tipo IList<string> . Cuando
esto ocurre, las clases de estilo se aplican de forma ascendente de la lista. Por lo tanto, cuando varias clases de estilo
establecen unas propiedades idénticas, la propiedad en la clase de estilo que se encuentra en la posición de la lista más alta
tendrá prioridad.
...
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" } }
}
};
Vínculos relacionados
Estilos básicos (ejemplo)
Aplicar estilos a las aplicaciones de Xamarin.Forms
con hojas de estilos en cascada (CSS)
12/07/2019 • 24 minutes to read • Edit Online
descargar el ejemplo
Xamarin.Forms es compatible con los elementos de estilo visual con hojas de estilos en cascada (CSS ).
Las aplicaciones de Xamarin.Forms pueden cambiar el estilo mediante CSS. Una hoja de estilos consta de una
lista de reglas, con cada regla que consta de uno o varios de los selectores y un bloque de declaración. Un bloque
de declaración consta de una lista de declaraciones de llaves, con cada declaración que consta de una propiedad,
un signo de dos puntos y un valor. Cuando hay varias declaraciones en un bloque, se inserta un punto y coma
como separador. El ejemplo de código siguiente muestra algunas CSS compatibles con 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;
}
En Xamarin.Forms, hojas de estilo CSS se analizan y se evalúan en tiempo de ejecución, en lugar de tiempo de
compilación y las hojas de estilo son volver a analizar en uso.
NOTE
Actualmente, todos los estilos que es posible con estilos XAML no se puede realizar con CSS. Sin embargo, estilos XAML se
pueden utilizar para complementar CSS para las propiedades que actualmente no son compatibles con Xamarin.Forms. Para
obtener más información sobre los estilos XAML, vea aplicar estilos a las aplicaciones de Xamarin.Forms con estilos XAML.
El MonkeyAppCSS ejemplo muestra cómo utilizar CSS para aplicar estilo a una aplicación simple y se muestra en
las capturas de pantalla siguiente:
Consumo de una hoja de estilos
El proceso para agregar una hoja de estilos a una solución es como sigue:
1. Agregue un archivo CSS vacío al proyecto de biblioteca .NET Standard.
2. Establezca la acción de compilación del archivo CSS para EmbeddedResource.
Cargar una hoja de estilos
Hay varios enfoques que puede utilizarse para cargar una hoja de estilos.
XAML
Una hoja de estilos se puede cargar y analizar con el StyleSheet clase antes de que se agrega a un
ResourceDictionary :
<Application ...>
<Application.Resources>
<StyleSheet Source="/Assets/styles.css" />
</Application.Resources>
</Application>
El StyleSheet.Source propiedad especifica la hoja de estilos como un URI relativo a la ubicación del archivo
XAML envolvente o en relación con la raíz del proyecto si el URI comienza con un / .
WARNING
El archivo CSS no se cargará si su acción de compilación no está establecido en EmbeddedResource.
Como alternativa, puede cargar y analizar con una hoja de estilos el StyleSheet (clase), antes de que se agrega a
un ResourceDictionary , por inserción en un CDATA sección:
<ContentPage ...>
<ContentPage.Resources>
<StyleSheet>
<![CDATA[
^contentpage {
background-color: lightgray;
}
]]>
</StyleSheet>
</ContentPage.Resources>
...
</ContentPage>
Para obtener más información acerca de los diccionarios de recursos, consulte los diccionarios de recursos.
C#
En C#, una hoja de estilos puede cargarse como recurso incrustado y agregarse a un ResourceDictionary :
this.Resources.Add(StyleSheet.FromAssemblyResource(
IntrospectionExtensions.GetTypeInfo(typeof(MyPage)).Assembly,
"MyProject.Assets.styles.css"));
}
}
stacklayout {
margin: 20;
}
Este selector identifica cualquier StackLayout elementos en las páginas que consumen la hoja de estilos y
establecen sus márgenes para un grosor uniforme de 20.
NOTE
El element selector no identifica las subclases del tipo especificado.
^contentpage {
background-color: lightgray;
}
Este selector identifica cualquier ContentPage elementos que consumen la hoja de estilos y establece su fondo de
color a lightgray .
NOTE
El ^base selector es específico de Xamarin.Forms y no forma parte de la especificación de CSS.
#listView {
background-color: lightgray;
}
Este selector identifica el elemento cuyo StyleId propiedad está establecida en listView . Sin embargo, si la
StyleId no está establecida la propiedad, el selector se vuelven a usar el x:Name del elemento. Por lo tanto, en el
siguiente ejemplo XAML, el #listView selector identificará la ListView cuyo x:Name atributo está establecido en
listView y establece su color de fondo en lightgray .
<ContentPage ...>
<ContentPage.Resources>
<StyleSheet Source="/Assets/styles.css" />
</ContentPage.Resources>
<StackLayout>
<ListView x:Name="listView" ...>
...
</ListView>
</StackLayout>
</ContentPage>
.detailPageTitle {
font-style: bold;
font-size: medium;
text-align: center;
}
.detailPageSubtitle {
text-align: center;
font-style: italic;
}
Una clase CSS que puede asignarse a un elemento XAML estableciendo el StyleClass propiedad del elemento
en el nombre de clase CSS. Por lo tanto, en el siguiente ejemplo XAML, los estilos definidos por el
.detailPageTitle clase se asignan a la primera Label , mientras que los estilos definidos por el
.detailPageSubtitle clase se asignan a la segunda Label .
<ContentPage ...>
<ContentPage.Resources>
<StyleSheet Source="/Assets/styles.css" />
</ContentPage.Resources>
<ScrollView>
<StackLayout>
<Label ... StyleClass="detailPageTitle" />
<Label ... StyleClass="detailPageSubtitle"/>
...
</StackLayout>
</ScrollView>
</ContentPage>
listview image {
height: 60;
width: 60;
}
Este selector identifica cualquier Image elementos secundarios de ListView elementos y su alto y ancho se
establece en 60. Por lo tanto, en el siguiente ejemplo XAML, el listview image selector identificará la Image que
es un elemento secundario de la ListView y su alto y ancho se establece en 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
El element element selector no requiere el elemento secundario sea un directo secundario del miembro primario: el
elemento secundario puede tener un elemento primario diferente. Selección se produce siempre que un nodo primario es el
primer elemento especificado.
stacklayout>image {
height: 200;
width: 200;
}
Este selector identifica cualquier Image directa de los elementos que son elementos secundarios de StackLayout
elementos y su alto y ancho se establece en 200. Por lo tanto, en el siguiente ejemplo XAML, el
stacklayout>image selector identificará la Image que es un elemento secundario directo de la StackLayout y
establece el alto y ancho en 200.
<ContentPage ...>
<ContentPage.Resources>
<StyleSheet Source="/Assets/styles.css" />
</ContentPage.Resources>
<ScrollView>
<StackLayout>
...
<Image ... />
...
</StackLayout>
</ScrollView>
</ContentPage>
NOTE
El element>element selector requiere que el elemento secundario es un directo secundario del miembro primario.
Referencia de selector
Xamarin.Forms admite los siguientes selectores de CSS:
Estilos con coincidencia de los selectores se aplican de forma consecutiva, en orden de definición. Los estilos
definidos en un elemento específico siempre se aplican en último lugar.
TIP
Los selectores se pueden combinar sin limitación, tales como StackLayout>ContentView>label.email .
NOTE
No se admiten especificidad e invalidaciones de especificidad.
Referencia de propiedad
Las siguientes propiedades CSS son compatibles con Xamarin.Forms (en el valores son de tipos de columna,
cursiva, mientras que los literales de cadena son gray ):
spacebetween |
spacearound |
spaceevenly |
flex-start | flex-end |
space-between |
space-around | initial
flex-start | flex-end |
initial
PROPERTY SE APLICA A VALORES EJEMPLO
row-reverse |
column-reverse |
initial
initial
PROPERTY SE APLICA A VALORES EJEMPLO
spacearound |
spaceevenly |
flex-start | flex-end |
space-between |
space-around | initial
scaleX , scaleY ,
translate , translateX ,
translateY , initial
Además, no hay ningún inherit herencia del valor de modo que no se admite. Por lo tanto, por ejemplo, no es
posible, establezca el font-size propiedad en un diseño y esperar que todos los Label instancias en el diseño
para heredar el valor. La única excepción es el direction propiedad, que tiene un valor predeterminado de
inherit .
solo se admite en un
ScrollView .
Color
La siguiente color se admiten valores:
X11 colores, que coincide con los colores CSS, los colores predefinidos de UWP y Xamarin.Forms colores.
Tenga en cuenta que estos valores de color distinguen mayúsculas de minúsculas.
hex colores: #rgb , #argb , #rrggbb , #aarrggbb
los colores RGB: rgb(255,0,0) , rgb(100%,0%,0%) . Los valores son en el intervalo 0-255, o 0-100%.
los colores RGBA: rgba(255, 0, 0, 0.8) , rgba(100%, 0%, 0%, 0.8) . Es el valor de opacidad en el intervalo de
0,0 a 1,0.
colores HSL: hsl(120, 100%, 50%) . El valor h está en el intervalo 0-360, mientras s y l están en el intervalo 0-
100%.
colores de HSLA: hsla(120, 100%, 50%, .8) . Es el valor de opacidad en el intervalo de 0,0 a 1,0.
Thickness
Uno, dos, tres o cuatro thickness se admiten valores, separados por espacios en blanco:
Un único valor indica el grosor uniforme.
Dos valores indican grosor vertical y horizontal.
Estos tres valores indican la parte superior, horizontal (izquierda y derecha) y, luego, grosor de la parte inferior.
Cuatro valores indican la parte superior, derecha y, a continuación, inferior y, luego, grosor de la izquierda.
NOTE
CSS thickness valores difieren XAML Thickness valores. Por ejemplo, en XAML, un valor de dos Thickness indica el
grosor horizontal y vertical, mientras que un valor de cuatro Thickness indica izquierda, superior y, luego, derecha, abajo,
a continuación, grosor. Además, XAML Thickness valores están delimitados por comas.
NamedSize
Lo siguiente entre mayúsculas y minúsculas namedsize se admiten valores:
default
micro
small
medium
large
Vínculos relacionados
MonkeyAppCSS (ejemplo)
Diccionarios de recursos
Aplicación de estilos para aplicaciones Xamarin.Forms con estilos XAML
Conmutador de Xamarin.Forms
11/07/2019 • 6 minutes to read • Edit Online
descargar el ejemplo
Xamarin.Forms Switch es un botón de alternancia horizontal que se puede manipular por el usuario para
alternar entre activar y desactivar los Estados, que se representan mediante un boolean valor. El Switch clase
hereda de View .
La siguiente captura de pantalla muestra un Switch en controlar su en y desactivar alternar los Estados en iOS
y Android:
Crear un conmutador
Un Switch se pueden crear instancias en XAML. Su IsToggled propiedad puede establecerse para activar o
desactivar el Switch . De forma predeterminada, el IsToggled propiedad es false . El ejemplo siguiente muestra
cómo crear una instancia de un Switch en XAML con el elemento opcional IsToggled conjunto de propiedades:
<Switch IsToggled="true"/>
La siguiente captura de pantalla muestra la Switch en su en y desactivar alternar los Estados, con el OnColor
propiedad establecida en Color.Orange en iOS y Android:
El sender argumento en el controlador de eventos es el Switch responsable de activar este evento. Puede usar
el sender propiedad para tener acceso a la Switch objeto, o para distinguir entre varias Switch objetos que
comparten el mismo Toggled controlador de eventos.
El Toggled también se puede asignar el controlador de eventos en el código:
En este ejemplo, el Label utiliza una expresión de enlace en un DataTrigger para supervisar la IsToggled
propiedad de la Switch denominado styleSwitch . Cuando esta propiedad se convierte en true ,
FontAttributes y FontSize propiedades de la Label cambian. Cuando el IsToggled propiedad devuelve al
false , el FontAttributes y FontSize propiedades de la Label se restablecen a su estado inicial.
Deshabilitar un conmutador
Una aplicación puede entrar en un estado donde el Switch no es una operación válida que se va a activar o
desactivar. En tales casos, el Switch puede deshabilitarse estableciendo su IsEnabled propiedad false . Esto
impedirá que los usuarios puedan manipular la Switch .
Vínculos relacionados
Demostraciones de conmutador
Desencadenadores de Xamarin.Forms
Xamarin.Forms TableView
11/07/2019 • 10 minutes to read • Edit Online
descargar el ejemplo
TableView es una vista para mostrar listas desplazables de datos o las opciones que hay filas que no comparten
la misma plantilla. A diferencia de ListView, TableView no tiene el concepto de un ItemsSource , por lo que se
deben agregar manualmente elementos como elementos secundarios.
Casos de uso
TableView resulta útil cuando:
presentar una lista de configuración,
recopilación de datos en un formulario, o
mostrando datos que se presentan diferente de la fila a fila (por ejemplo, números, porcentajes e imágenes).
TableView Controla el desplazamiento y el diseño de filas en las secciones atractivas, una necesidad común
para los escenarios anteriores. El TableView utiliza control de la plataforma subyacente de vista equivalente
cuando esté disponible para crear una apariencia nativa para cada plataforma.
Estructura
Elementos de un TableView se organiza en secciones. En la raíz de la TableView es el TableRoot , que es
primario a uno o varios TableSection instancias. Cada TableSection consta de un encabezado y uno o más
ViewCell instancias:
<TableView Intent="Settings">
<TableRoot>
<TableSection Title="Ring">
<SwitchCell Text="New Voice Mail" />
<SwitchCell Text="New Mail" On="true" />
</TableSection>
</TableRoot>
</TableView>
El código de C# equivalente es:
Apariencia
TableView expone el Intent propiedad, que se puede establecer en cualquiera de los TableIntent miembros
de enumeración:
Data : para su uso al mostrar las entradas de datos. Tenga en cuenta que ListView puede ser una mejor
opción para el desplazamiento de listas de datos.
Form : para su uso cuando la TableView está actuando como un formulario.
Menu : para su uso cuando se presenta un menú de las selecciones.
Settings : para su uso cuando se muestra una lista de valores de configuración.
El TableIntent valor que elija puede afectar a cómo el TableView aparece en cada plataforma. Incluso si hay no
borrar las diferencias, es una práctica recomendada para seleccionar el TableIntent que más acerque cómo
piensa usar la tabla.
Además, se muestra el color del texto para cada TableSection se puede cambiar estableciendo la TextColor
propiedad a un Color .
Celdas integradas
Xamarin.Forms incluye celdas integradas para recopilar y mostrar información. Aunque ListView y TableView
puede usar todas las celdas de la mismas, SwitchCell y EntryCell son las más relevantes para un TableView
escenario.
Consulte aspecto de la celda de ListView para obtener una descripción detallada de TextCell y ImageCell.
SwitchCell
SwitchCell es el control que se utilizará para presentar y capturar un activado/desactivado o true / false
estado. Define las siguientes propiedades:
Text : texto que se muestra al lado del conmutador.
On : determina si se muestra el conmutador como activado o desactivado.
OnColor – el Color del conmutador cuando se encuentra en la posición de encendido.
NOTE
A diferencia de ListView , TableView no requiere ese personalizado (o ninguno) se definen las celdas en una
ItemTemplate .
Alto de fila
El TableView clase tiene dos propiedades que pueden usarse para cambiar el alto de fila de celdas:
RowHeight : establece el alto de cada fila a una int .
HasUnevenRows : las filas tienen diferentes alturas si establece en true . Tenga en cuenta que al establecer
esta propiedad en true , automáticamente se calcula y aplicada por Xamarin.Forms alto de las filas.
Cuando el alto del contenido en una celda de un TableView se cambia la fila se actualiza implícitamente alto en
la plataforma Universal de Windows (UWP ) y Android. Sin embargo, en iOS debe obligársele a actualizar
mediante el establecimiento la HasUnevenRows propiedad true y mediante una llamada a la
Cell.ForceUpdateSize método.
Las capturas de pantalla siguientes muestran la celda después de que se puntea en:
IMPORTANT
Si esta característica está sobreutilizada, hay grandes posibilidades de degradación del rendimiento.
Vínculos relacionados
TableView (ejemplo)
Texto en Xamarin.Forms
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Uso de Xamarin.Forms para escribir o mostrar texto.
Xamarin.Forms tiene tres vistas principales para trabajar con texto:
Etiqueta — para presentar un o varias líneas de texto. Puede mostrar texto con varias opciones de formato en
la misma línea.
Entrada — para escribir texto que es solo una línea. Entrada tiene un modo de contraseña.
Editor — para escribir texto que podría tardar más de una línea.
Apariencia del texto se puede cambiar mediante integradas o personalizadas estilos y algunos controles admiten
personalizado fuentes.
Label
El Label vista se utiliza para mostrar texto. Puede mostrar varias líneas de texto o una sola línea de texto. Label
puede presentar el texto con varias opciones de formato usadas en línea. La vista de la etiqueta puede ajustar o
truncar el texto cuando no caben en una sola línea.
Editor
Editor se usa para aceptar la entrada de texto de varias líneas. Editor ofrece el control sobre los colores y
fuentes.
Consulte la Editor artículo para obtener más información.
Fuentes
Muchos controles admiten la configuración de fuente diferente utilizando las fuentes integradas en cada
plataforma, o fuentes personalizadas que se incluye con la aplicación. Consulte la fuentes artículo para obtener
más información.
Estilos
Consulte trabajar con estilos para obtener información sobre cómo configurar la fuente, colory otras propiedades
de presentación que se aplican a través de varios controles.
Vínculos relacionados
Texto (ejemplo)
Etiqueta de Xamarin.Forms
11/07/2019 • 19 minutes to read • Edit Online
descargar el ejemplo
Mostrar texto en Xamarin.Forms
El Label vista se utiliza para mostrar texto, único y varias líneas. Las etiquetas pueden tener decoraciones de
texto, texto de color y usar las fuentes personalizadas (familias de tamaños y opciones).
Decoraciones de texto
Se pueden aplicar las decoraciones de texto subrayado y tachado a Label instancias estableciendo el
Label.TextDecorations propiedad a uno o varios TextDecorations miembros de enumeración:
None
Underline
Strikethrough
NOTE
También se pueden aplicar las decoraciones de texto a Span instancias. Para obtener más información sobre la Span de
clases, vea texto con formato.
Colores
Las etiquetas se pueden establecer para usar un color de texto personalizado a través de la enlazable TextColor
propiedad.
Atención especial es necesaria para asegurarse de que los colores se podrán usar en cada plataforma. Dado que
cada plataforma tiene distintos valores predeterminados para los colores de texto y fondo, deberá tener cuidado
al elegir un valor predeterminado que funciona en cada uno.
En el siguiente ejemplo XAML establece el color del texto de un 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>
Fuentes
Para obtener más información acerca de cómo especificar las fuentes en un Label , consulte fuentes.
Truncamiento y ajuste
Se pueden establecer etiquetas para controlar el texto que no cabe en una sola línea en una de varias maneras,
expuestos por la LineBreakMode propiedad. LineBreakMode es una enumeración con los valores siguientes:
HeadTruncation – trunca el encabezado del texto, que muestra el extremo.
CharacterWrap – ajusta el texto en una nueva línea en un límite de caracteres.
MiddleTruncation – muestra el principio y al final del texto, con el reemplazo intermedio mediante puntos
suspensivos.
NoWrap – no ajusta el texto, mostrar solo mayor cantidad de texto que puede cabe en una sola línea.
TailTruncation – muestra el principio del texto, truncar final.
WordWrap – ajusta el texto en el límite de palabras.
Mostrar un número específico de líneas
El número de líneas muestra un Label se puede especificar estableciendo el Label.MaxLines propiedad a un
int valor:
Cuando MaxLines es 0, el Label respeta el valor de la LineBreakMode propiedad que se va a mostrar ya sea
una sola línea, posiblemente truncada, o todas las líneas con todo el texto.
Cuando MaxLines es 1, el resultado es idéntico al valor de la LineBreakMode propiedad NoWrap ,
HeadTruncation , MiddleTruncation , o TailTruncation . Sin embargo, el Label respetará el valor de la
LineBreakMode propiedad con respecto a la selección de ubicación de puntos suspensivos, si procede.
Cuando MaxLines es mayor que 1, el Label mostrará hasta el número especificado de líneas, respetando el
valor de la LineBreakMode propiedad con respecto a la selección de ubicación de puntos suspensivos, si
procede. Sin embargo, establecer el MaxLines propiedad a un valor mayor que 1 no tiene ningún efecto si la
LineBreakMode propiedad está establecida en NoWrap .
<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" />
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
};
Las capturas de pantalla siguientes muestran el resultado de establecer el MaxLines propiedad en 2, cuando el
texto es lo suficientemente largo para ocupar más de 2 líneas:
NOTE
El BackgroundColor , Text , y Text propiedades enlazables tienen un modo de enlace predeterminada de OneWay .
Para obtener más información acerca de este modo de enlace, consulte el modo de enlace predeterminada en el modo de
enlace guía.
Además, el GestureRecognizers propiedad puede usarse para definir una colección de los reconocedores de
gestos que responderá a los movimientos en el Span .
En el ejemplo de XAML siguiente se muestra un FormattedText propiedad que consta de tres Span instancias:
<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>
IMPORTANT
El Text propiedad de un Span puede establecerse mediante enlace de datos. Para obtener más información, consulte
enlace de datos.
Tenga en cuenta que un Span también puede responder a los gestos que se agregan en el intervalo
GestureRecognizers colección. Por ejemplo, un TapGestureRecognizer se ha agregado a la segunda Span en los
ejemplos de código anteriores. Por lo tanto, cuando esto Span se pulsa la TapGestureRecognizer responderá
mediante la ejecución de la ICommand definido por el Command propiedad. Para obtener más información acerca
de los reconocedores de gestos, vea Xamarin.Forms gestos.
Las capturas de pantalla siguientes muestran el resultado de la configuración de la FormattedString propiedad a
tres Span instancias:
Alto de línea
La altura vertical de un Label y un Span puede personalizarse configurando el Label.LineHeight propiedad o
Span.LineHeight a un double valor. En iOS y Android, estos valores son multiplicadores del alto de línea original
y en la plataforma Universal de Windows (UWP ) la Label.LineHeight valor de propiedad es un multiplicador del
tamaño de fuente de etiqueta.
NOTE
En iOS, el Label.LineHeight y Span.LineHeight propiedades cambian el alto de línea de texto que encaja en una
sola línea y el texto que se ajusta en varias líneas.
En Android, el Label.LineHeight y Span.LineHeight propiedades sólo cambian el alto de línea de texto que se
ajusta en varias líneas.
En UWP, la Label.LineHeight propiedad cambia el alto de línea de texto que se ajusta en varias líneas, y el
Span.LineHeight propiedad no tiene ningún efecto.
<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" />
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
};
<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>
Hipervínculos
El texto mostrado por Label y Span instancias se pueden convertir en hipervínculos con el siguiente enfoque:
1. Establecer el TextColor y TextDecoration propiedades de la Label o Span .
2. Agregar un TapGestureRecognizer a la GestureRecognizers colección de la Label o Span , cuya Command
propiedad se enlaza a un ICommand y cuyo CommandParameter propiedad contiene la dirección URL para abrir.
3. Definir la ICommand que ejecutará el TapGestureRecognizer .
4. Escribir el código que se ejecutará por la ICommand .
En este ejemplo, la primera y tercera Span instancias comprenden el texto, mientras que el segundo Span
representa un hipervínculo tappable. Tiene el color del texto establecido en azul, y tiene una decoración de texto
subrayado. Esto crea la apariencia de un hipervínculo, como se muestra en las capturas de pantalla siguiente:
public MainPage()
{
InitializeComponent();
BindingContext = this;
}
public HyperlinkSpan()
{
TextDecorations = TextDecorations.Underline;
TextColor = Color.Blue;
GestureRecognizers.Add(new TapGestureRecognizer
{
Command = new Command(() => Device.OpenUri(new Uri(Url)))
});
}
}
Etiquetas de estilo
Las secciones anteriores tratan la configuración Label y Span las propiedades de por instancia. Sin embargo,
los conjuntos de propiedades se pueden agrupar en un estilo que se aplica de manera coherente a una o varias
vistas. Esto puede mejorar la legibilidad del código y realizar cambios de diseño sea más fácil de implementar.
Para obtener más información, consulte estilos.
Vínculos relacionados
Texto (ejemplo)
Hipervínculos (ejemplo)
Creación de aplicaciones móviles con Xamarin.Forms, capítulo 3
API de etiqueta
Intervalo de API
Entrada de Xamarin.Forms
11/07/2019 • 17 minutes to read • Edit Online
descargar el ejemplo
Texto de una línea o la contraseña de entrada
Xamarin.Forms Entry se usa para la entrada de texto de una línea. El Entry , como el Editor ver, admite varios
tipos de teclado. Además, el Entry puede usarse como un campo de contraseña.
Personalización de la presentación
Establecimiento y lectura de texto
El Entry , al igual que otras vistas de presentación de texto, expone el Text propiedad. Esta propiedad se puede
utilizar para establecer y leer el texto presentado por el Entry . El ejemplo siguiente se muestra cómo establecer
el Text propiedad en XAML:
En C#:
NOTE
El ancho de un Entry puede definirse estableciendo su WidthRequest propiedad. No dependen del ancho de un Entry
que se define en función del valor de su Text propiedad.
var entry = new Entry { Text = "This is a read-only Entry", IsReadOnly = true });
NOTE
El IsReadonly propiedad no modifica la apariencia visual de un Entry , a diferencia el IsEnabled propiedad que
también cambia la apariencia visual de la Entry a gris.
Un MaxLength valor de propiedad de 0 indica que no se permitirá ninguna entrada y un valor de int.MaxValue ,
que es el valor predeterminado para un Entry , indica que no hay ninguna límite real del número de caracteres
que pueden especificarse.
Campos de contraseña
Entry proporciona el IsPassword propiedad. Cuando IsPassword es true , se mostrará el contenido del campo
como círculos negros:
En XAML:
En C#:
En C#:
El valor predeterminado de la CursorPosition propiedad es 0, lo que indica que se insertará el texto al principio
de la Entry .
Además, el SelectionLength propiedad puede usarse para devolver o establecer la longitud de selección de texto
dentro de la 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 };
El valor predeterminado de la SelectionLength propiedad es 0, lo que indica que no hay texto seleccionado.
Personalizar el teclado
El teclado que aparece cuando los usuarios interactúan con un Entry se puede establecer mediante
programación a través de la Keyboard propiedad a una de las siguientes propiedades desde el Keyboard clase:
Chat : se usa para el texto y los lugares donde emoji son útiles.
Default : el teclado predeterminado.
Email : se usa al especificar direcciones de correo electrónico.
Numeric : se usa al escribir números.
Plain : se usa al escribir texto, sin ningún KeyboardFlags especificado.
Telephone : se usa al escribir números de teléfono.
Text : se usa al escribir texto.
Url : se usa para especificar las rutas de acceso de archivo y direcciones web.
Default : indica que se requiere ninguna clave de valor devuelta concreta y que se usará el valor
predeterminado de la plataforma.
Done : indica una clave de valor devuelta "Done".
Go : indica una clave de valor devuelta "Ir".
Next : indica una clave de valor devuelta "Siguiente".
Search : indica una clave de valor devuelta de "Búsqueda".
Send : indica una tecla de retorno del "Envío".
NOTE
El aspecto exacto de la clave de valor devuelto depende de la plataforma. En iOS, la clave de valor devuelta es un botón
basado en texto. Sin embargo, en plataformas de Windows Universal y Android, la clave devuelta es un botón de icono.
Cuando se presiona la tecla ENTRAR, el Completed desencadena el evento y cualquier ICommand especificado
por el ReturnCommand se ejecuta la propiedad. Además, cualquier object especificado por el
ReturnCommandParameter propiedad se pasará a la ICommand como un parámetro. Para obtener más información
acerca de los comandos, consulte la interfaz de comandos.
Habilitar y deshabilitar el corrector ortográfico
El IsSpellCheckEnabled propiedad controla si corrector ortográfico está habilitado. De forma predeterminada, la
propiedad se establece en true . Cuando el usuario escriba texto, se indican los errores de ortografía.
Sin embargo, para algunos escenarios de entrada de texto, como escribir un nombre de usuario, corrector
ortográfico proporciona una experiencia negativa y debe deshabilitarse estableciendo el IsSpellCheckEnabled
propiedad false :
NOTE
Cuando el IsTextPredictionEnabled propiedad está establecida en false , y un teclado personalizado no es que se va
a usar, la predicción de texto y automática se deshabilita la corrección de texto. Sin embargo, si un Keyboard se ha
establecido que deshabilita la predicción de texto, el IsTextPredictionEnabled se omite. Por lo tanto, no se puede usar la
propiedad para habilitar la predicción de texto para un Keyboard que deshabilita de forma explícita.
Colores
Puede establecerse una entrada para usar un fondo personalizado y los colores de texto a través de las
propiedades enlazables siguientes:
TextColor – establece el color del texto.
BackgroundColor – establece el color que aparece detrás del texto.
Atención especial es necesaria para asegurarse de que los colores se podrán usar en cada plataforma. Dado que
cada plataforma tiene distintos valores predeterminados para los colores de texto y fondo, a menudo deberá
establecer ambos si establece uno.
Use el código siguiente para establecer el color del texto de una entrada:
En XAML:
En C#:
En C#:
Eventos e interactividad
Entrada expone dos eventos:
TextChanged – se genera cuando cambia el texto en la entrada. Proporciona el texto antes y después del
cambio.
Completed – se genera cuando el usuario ha finalizado la entrada presionando la tecla ENTRAR del teclado.
NOTE
El VisualElement (clase), desde el que Entry hereda, también tiene Focused y Unfocused eventos.
Completada
El Completed evento sirve para reaccionar a la finalización de una interacción con una entrada. Completed se
produce cuando el usuario finaliza la entrada con un campo presionando la tecla ENTRAR del teclado (o
presionando la tecla Tab en UWP ). El controlador para el evento es un controlador de eventos genéricos,
tomando el remitente y EventArgs :
y C#:
Después de la Completed evento se activa, cualquier ICommand especificado por el ReturnCommand se ejecuta la
propiedad, con el object especificado por el ReturnCommandParameter propiedad que se pasan a la ICommand .
TextChanged
El TextChanged evento sirve para reaccionar ante un cambio en el contenido de un campo.
TextChanged se produce cada vez que el Text de la Entry cambios. El controlador para el evento toma una
instancia de TextChangedEventArgs . TextChangedEventArgs proporciona acceso a los valores antiguos y nuevos de
la Entry Text a través de la OldTextValue y NewTextValue propiedades:
y C#:
Vínculos relacionados
Texto (ejemplo)
Entrada de API
Editor de Xamarin.Forms
11/07/2019 • 14 minutes to read • Edit Online
descargar el ejemplo
Entrada de texto multilínea
El Editor control se usa para aceptar la entrada de varias líneas. En este artículo se tratan los aspectos
siguientes:
Personalización – opciones de color y el teclado.
Interactividad – eventos que se pueden escuchar para proporcionar interactividad.
Personalización
Establecimiento y lectura de texto
El Editor , al igual que otras vistas de presentación de texto, expone el Text propiedad. Esta propiedad se
puede utilizar para establecer y leer el texto presentado por el Editor . El ejemplo siguiente se muestra cómo
establecer el Text propiedad en XAML:
En C#:
var editor = new Editor { Placeholder = "Enter text here", PlaceholderColor = Color.Olive };
var editor = new Editor { Text = "This is a read-only Editor", IsReadOnly = true });
NOTE
El IsReadonly propiedad no modifica la apariencia visual de un Editor , a diferencia el IsEnabled propiedad que
también cambia la apariencia visual de la Editor a gris.
Un MaxLength valor de propiedad de 0 indica que no se permitirá ninguna entrada y un valor de int.MaxValue ,
que es el valor predeterminado para un Editor , indica que no hay ninguna límite real del número de caracteres
que pueden especificarse.
Un Editor de tamaño automático
Un Editor pueden realizarse en el ajuste de tamaño automático a su contenido estableciendo el
Editor.AutoSize propiedad TextChanges , que es un valor de la EditoAutoSizeOption enumeración. Esta
enumeración tiene dos valores:
Disabled indica que el cambio de tamaño automático está deshabilitado y es el valor predeterminado.
TextChanges indica que el cambio de tamaño automático está habilitado.
var editor = new Editor { Text = "Enter text here", AutoSize = EditorAutoSizeOption.TextChanges };
Cuando el cambio de tamaño automático está habilitado, el alto de la Editor aumentará cuando el usuario lo
rellena con texto y se reducirá el alto como el usuario elimina el texto.
NOTE
Un Editor le if no redimensionar el HeightRequest se estableció la propiedad.
Personalizar el teclado
El teclado que aparece cuando los usuarios interactúan con un Editor se puede establecer mediante
programación a través de la Keyboard propiedad a una de las siguientes propiedades desde el Keyboard clase:
Chat : se usa para el texto y los lugares donde emoji son útiles.
Default : el teclado predeterminado.
Email : se usa al especificar direcciones de correo electrónico.
Numeric : se usa al escribir números.
Plain : se usa al escribir texto, sin ningún KeyboardFlags especificado.
Telephone : se usa al escribir números de teléfono.
Text : se usa al escribir texto.
Url : se usa para especificar las rutas de acceso de archivo y direcciones web.
<Editor>
<Editor.Keyboard>
<Keyboard x:FactoryMethod="Create">
<x:Arguments>
<KeyboardFlags>Suggestions,CapitalizeCharacter</KeyboardFlags>
</x:Arguments>
</Keyboard>
</Editor.Keyboard>
</Editor>
NOTE
Cuando el IsSpellCheckEnabled propiedad está establecida en false y no se usa un teclado personalizado, se
deshabilitará el corrector ortográfico nativo. Sin embargo, si un Keyboard ha sido conjunto que deshabilita el corrector
comprobación, como Keyboard.Chat , el IsSpellCheckEnabled se omite. Por lo tanto, no se puede usar la propiedad
para habilitar el corrector ortográfico para un Keyboard que deshabilita de forma explícita.
NOTE
Cuando el IsTextPredictionEnabled propiedad está establecida en false , y un teclado personalizado no es que se va
a usar, la predicción de texto y automática se deshabilita la corrección de texto. Sin embargo, si un Keyboard se ha
establecido que deshabilita la predicción de texto, el IsTextPredictionEnabled se omite. Por lo tanto, no se puede usar la
propiedad para habilitar la predicción de texto para un Keyboard que deshabilita de forma explícita.
Colores
Editor puede establecerse para usar un color de fondo a través de la BackgroundColor propiedad. Atención
especial es necesaria para asegurarse de que los colores se podrán usar en cada plataforma. Dado que cada
plataforma tiene distintos valores predeterminados para el color de texto, deberá establecer un color de fondo
personalizado para cada plataforma. Consulte trabajar con ajustes de la plataforma para obtener más
información sobre la optimización de la interfaz de usuario para cada plataforma.
En C#:
En XAML:
Interactividad
Editor expone dos eventos:
TextChanged – se genera cuando cambia el texto en el editor. Proporciona el texto antes y después del cambio.
Completado – se genera cuando el usuario ha finalizado la entrada presionando la tecla ENTRAR del teclado.
NOTE
El VisualElement (clase), desde el que Entry hereda, también tiene Focused y Unfocused eventos.
Completada
El Completed evento sirve para reaccionar a la finalización de una interacción con un Editor . Completed se
produce cuando el usuario finaliza la entrada con un campo especificando la tecla ENTRAR del teclado (o
presionando la tecla Tab en UWP ). El controlador para el evento es un controlador de eventos genéricos,
tomando el remitente y EventArgs :
En XAML:
TextChanged
El TextChanged evento sirve para reaccionar ante un cambio en el contenido de un campo.
TextChanged se produce cada vez que el Text de la Editor cambios. El controlador para el evento toma una
instancia de TextChangedEventArgs . TextChangedEventArgs proporciona acceso a los valores antiguos y nuevos de
la Editor Text a través de la OldTextValue y NewTextValue propiedades:
Vínculos relacionados
Texto (ejemplo)
Editor de API
Fuentes de Xamarin.Forms
11/07/2019 • 12 minutes to read • Edit Online
descargar el ejemplo
Este artículo describe cómo Xamarin.Forms le permite especificar atributos de fuente (incluidas peso y
tamaño) en los controles que muestran texto. Puede ser información de fuente especificado en el código o
especificado en XAML. Tiene ' también es posible utilizar un fuente personalizada, y mostrar iconos de fuente.
Este código muestra cómo crear una etiqueta y especifique el tamaño de fuente y el peso para mostrar:
Tamaño de fuente
El FontSize propiedad puede establecerse en un valor double, por ejemplo:
label.FontSize = 24;
Xamarin.Forms también define los campos de la NamedSize enumeración que representan los tamaños de
fuente específico. Para obtener más información acerca de los tamaños de fuente con nombre, vea
denominado tamaños de fuente.
Atributos de fuente
Estilos de fuente como negrita y cursiva se pueden establecer en el FontAttributes propiedad. Actualmente
se admiten los siguientes valores:
Ninguno
Negrita
Cursiva
El FontAttribute enumeración se puede usar como sigue (se puede especificar un atributo único o OR
juntarlas):
Hay un convertidor de tipos integrado para el FontSize propiedad que permite que todos los valores de
fuente se exprese como un valor de cadena en XAML. Además, el FontAttributes propiedad puede utilizarse
para especificar atributos de fuente:
Device.RuntimePlatform También se puede utilizar en XAML para representar una fuente diferente en cada
plataforma. El ejemplo siguiente utiliza un nombre de fuente personalizados en iOS (MarkerFelt Thin) y
especifica solo tamaño y atributos en las otras plataformas:
Al especificar un nombre de fuente personalizada, siempre es una buena idea usar OnPlatform , ya que es
difícil encontrar una fuente que está disponible en todas las plataformas.
Default 16 14 14
Micro 11 10 15.667
Small 13 14 18.667
Medium 16 17 22.667
Large 20 22 32
Body 17 16 14
Header 17 96 46
Title 28 24 24
Subtitle 22 16 20
Caption 12 12 12
Los tamaños de fuente con nombre se pueden establecer mediante XAML y código. Además, el
Device.GetNamedSize se puede llamar el método para devolver un double que representa el tamaño de fuente
con nombre:
NOTE
En iOS y Android, tamaños de fuente con nombre realizará el escalado automático en función de las opciones de
accesibilidad del sistema operativo. Este comportamiento se puede deshabilitar en iOS con una plataforma específica.
Para obtener más información, consulte accesibilidad escalado denominada tamaños de fuente en iOS.
A continuación, se describen los pasos necesarios para cada plataforma. Cuando se incluyen archivos de
fuente personalizada con una aplicación, asegúrese de comprobar que permite la licencia de la fuente de
distribución.
iOS
Es posible mostrar una fuente personalizada en primer lugar, lo que garantiza que se carga y, luego, que hace
referencia a él por su nombre mediante Xamarin.Forms Font métodos. Siga las instrucciones de esta entrada
de blog:
1. Agregar el archivo de fuentes con acción de compilación: BundleResource, y
2. Actualización de la Info.plist archivo (fuentes proporcionadas por la aplicación, o UIAppFonts , key), a
continuación,
3. Hacer referencia al mismo nombre siempre que defina una fuente de Xamarin.Forms.
new Label
{
Text = "Hello, Forms!",
FontFamily = Device.RuntimePlatform == Device.iOS ? "Lobster-Regular" : null // set only for iOS
}
Android
Xamarin.Forms para Android puede hacer referencia a una fuente personalizada que se ha agregado al
proyecto siguiendo un estándar de nomenclatura. Primero agregue el archivo de fuente a la activos carpeta
en el proyecto de aplicación y establezca acción de compilación: AndroidAsset. A continuación, utilice la ruta de
acceso completa y nombre de la fuente separados por una almohadilla (#) como el nombre de fuente en
Xamarin.Forms, como se muestra en el siguiente fragmento de código:
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 de Windows puede hacer referencia a una fuente personalizada que se ha
agregado al proyecto siguiendo un estándar de nomenclatura. Primero agregue el archivo de fuente a la
/Assets/fuentes/ carpeta en el proyecto de aplicación y establezca el compilar: contenido de la acción. A
continuación, utilice la fuente y la ruta de acceso de nombre de archivo completo, seguido por una almohadilla
(#) y el nombre de la fuente, tal y como se muestra el siguiente fragmento de código:
new Label
{
Text = "Hello, Forms!",
FontFamily = Device.RuntimePlatform == Device.UWP ? "Assets/Fonts/Lobster-Regular.ttf#Lobster" : null
// set only for UWP apps
}
NOTE
Tenga en cuenta que el nombre de archivo de fuente y el nombre de fuente pueden ser diferentes. Para conocer el
nombre de fuente en Windows, haga clic en el archivo .ttf y seleccione Preview. A continuación, se puede determinar el
nombre de fuente desde la ventana Vista previa.
El código común de la aplicación ya está completo. El código del marcador de teléfono específico de la
plataforma se implementará como DependencyService.
XAML
También puede usar Device.RuntimePlatform en XAML para representar una fuente 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>
Estos datos se usan para crear un archivo PNG, que puede mostrarse en cualquier vista que puede mostrar un
ImageSource . Este enfoque permite que los iconos de la fuente, como los emojis, que va a mostrar varias
vistas, en lugar de limitar la presentación de iconos de fuente para un solo texto, ya que presenta la vista, como
un Label .
IMPORTANT
Actualmente solo se pueden especificar iconos de la fuente por su representación de caracteres unicode.
En el siguiente ejemplo XAML tiene un icono de única fuente mostrado por un Image vista:
<Image BackgroundColor="#D1D1D1">
<Image.Source>
<FontImageSource Glyph=""
FontFamily="{OnPlatform iOS=Ionicons, Android=ionicons.ttf#}"
Size="44" />
</Image.Source>
</Image>
Este código muestra un icono de XBox, desde la familia de fuentes Ionicons, en un Image vista. Tenga en
cuenta que mientras el unicode de caracteres de este icono es \uf30c , tiene que ser caracteres de escape en
XAML y por lo que se convierte en  . El código de C# equivalente es:
Las siguientes capturas de pantalla, desde el diseños enlazable de ejemplo, se muestran varios iconos de
fuente mostrados por un diseño enlazable:
Vínculos relacionados
FontsSample
Texto (ejemplo)
Diseños enlazables (ejemplo)
Diseños enlazables
Estilos de texto de Xamarin.Forms
11/07/2019 • 4 minutes to read • Edit Online
descargar el ejemplo
Estilos de texto en Xamarin.Forms
Los estilos se pueden usar para ajustar la apariencia de las etiquetas, las entradas y editores. Estilos pueden
definirse una vez y utilizados por muchas vistas, pero solo puede usarse un estilo con vistas de un tipo. Los estilos
se pueden proporcionar un Key y aplicar selectivamente mediante un control específico Style propiedad.
Estilos integrados
Xamarin.Forms incluye varios integrada estilos para escenarios comunes:
BodyStyle
CaptionStyle
ListItemDetailTextStyle
ListItemTextStyle
SubtitleStyle
TitleStyle
Para aplicar uno de los estilos integrados, use el DynamicResource extensión de marcado para especificar el estilo:
label.Style = Device.Styles.TitleStyle;
Estilos personalizados
Estilos constan de establecedores y constan de establecedores de propiedades y los valores de las propiedades se
establecerá en.
En C#, un estilo personalizado para una etiqueta con texto rojo de tamaño 30 se definiría como sigue:
var label = new Label { Text = "Check out my style.", Style = LabelStyle };
En 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>
Tenga en cuenta que los recursos (incluidos todos los estilos) se definen dentro de ContentPage.Resources , que es
un elemento relacionado de cuanto más se familiarice ContentPage.Content elemento.
Aplicar estilos
Una vez que se ha creado un estilo, se puede aplicar a cualquier coincidencia de vista su TargetType .
En XAML, los estilos personalizados se aplican a vistas proporcionando sus Style propiedad con un
StaticResource el estilo deseado de referencia de extensión de marcado:
En C#, estilos pueden se aplican directamente a una vista o agrega a y recuperarse de una página
ResourceDictionary . Para agregar directamente:
var label = new Label { Text = "Check out my style.", Style = LabelStyle };
Estilos integrados se aplican de forma diferente, ya que se deben responder a la configuración de accesibilidad.
Para aplicar los estilos integrados en XAML, el DynamicResource se utiliza la extensión de marcado:
label.Style = Device.Styles.TitleStyle;
Accesibilidad
Los estilos integrados existen para que sea más fácil respetar las preferencias de accesibilidad. Al utilizar
cualquiera de los estilos integrados, los tamaños de fuente aumentará automáticamente si un usuario establece
las preferencias de accesibilidad en consecuencia.
Considere el siguiente ejemplo de la misma página de vistas de un estilo con los estilos integrados con la
configuración de accesibilidad habilitados y deshabilitados:
Deshabilitado:
Habilitado:
Para garantizar la accesibilidad, asegúrese de que los estilos integrados se utilizan como base para cualquier estilo
relacionada con el texto dentro de la aplicación y que está utilizando estilos de forma coherente. Consulte estilos
para obtener más detalles sobre la extensión y trabajar con estilos en general.
Vínculos relacionados
Creación de aplicaciones móviles con Xamarin.Forms, capítulo 12
Estilos
Texto (ejemplo)
Estilo
Temas de Xamarin.Forms
12/07/2019 • 3 minutes to read • Edit Online
descargar el ejemplo
Los temas de Xamarin.Forms se anunciaron en Evolve 2016 y están disponibles como una vista previa para
clientes probar y proporcionar comentarios.
Un tema se agrega a una aplicación de Xamarin.Forms mediante la inclusión de la
Xamarin.Forms.Theme.Base de paquetes de Nuget, además de un paquete adicional que define un tema
concreto (p ej. Xamarin.Forms.Theme.Light) o de lo contrario, se puede definir un tema local para la aplicación.
Hacer referencia a la el tema claro y tema oscuro páginas para obtener instrucciones sobre cómo agregarlos a
una aplicación, o visite el tema personalizado de ejemplo.
IMPORTANT
También debe seguir los pasos necesarios para cargar ensamblados de tema (abajo) agregando código estereotipado a
iOS AppDelegate y Android MainActivity . Se mejorará en versión preliminar futura.
<StackLayout Padding="40">
<Label Text="Regular label" />
<Entry Placeholder="type here" />
<Button Text="OK" />
<BoxView Color="Yellow" />
<Switch />
</StackLayout>
<StackLayout Padding="40">
<BoxView StyleClass="HorizontalRule" />
<BoxView StyleClass="Circle" />
<BoxView StyleClass="Rounded" />
</StackLayout>
Clases integradas
Además de aplicar un estilo a automáticamente común controla la luz y los temas oscuros actualmente admiten
las siguientes clases que se pueden aplicar mediante el establecimiento del StyleClass en estos controles:
BoxView
HorizontalRule
Círculo
Redondeado
Image
Círculo
Redondeado
Vista en miniatura
Button
Default
Principal
Correcto
Info
Advertencia
Peligro
Vínculo
Pequeño
Grandes
Label
Header
Subencabezado
Cuerpo
Vínculo
Inverso
Solución de problemas
No se pudo cargar el archivo o ensamblado 'Xamarin.Forms.Theme.Light' o uno de sus dependencias
En la versión preliminar, los temas no pueda cargar en tiempo de ejecución. Agregue el código que se muestra
a continuación, en los proyectos correspondientes para corregir este error.
iOS
En el AppDelegate.cs agregue las líneas siguientes después de LoadApplication
var x = typeof(Xamarin.Forms.Themes.DarkThemeResources);
x = typeof(Xamarin.Forms.Themes.LightThemeResources);
x = typeof(Xamarin.Forms.Themes.iOS.UnderlineEffect);
Android
En el MainActivity.cs agregue las líneas siguientes después de LoadApplication
var x = typeof(Xamarin.Forms.Themes.DarkThemeResources);
x = typeof(Xamarin.Forms.Themes.LightThemeResources);
x = typeof(Xamarin.Forms.Themes.Android.UnderlineEffect);
Vínculos relacionados
Ejemplo de ThemesDemo
Tema claro de Xamarin.Forms
11/07/2019 • 2 minutes to read • Edit Online
NOTE
Los temas requieren la versión preliminar de Xamarin.Forms 2.3. Compruebe el sugerencias para solucionar problemas si se
producen errores.
4. Usar StyleClass
Este es un ejemplo de botones y etiquetas en el tema claro, junto con el marcado que los genera.
<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>
El lista completa de las clases integradas muestra qué estilos están disponibles para algunos controles comunes.
Tema oscuro de Xamarin.Forms
11/07/2019 • 2 minutes to read • Edit Online
NOTE
Los temas requieren la versión preliminar de Xamarin.Forms 2.3. Compruebe el sugerencias para solucionar problemas si se
producen errores.
4. Usar StyleClass
Este es un ejemplo de botones y etiquetas en el tema oscuro, junto con el marcado que los genera.
<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" />
El lista completa de las clases integradas muestra qué estilos están disponibles para algunos controles comunes.
Crear un tema personalizado de Xamarin.Forms
11/07/2019 • 4 minutes to read • Edit Online
Además de agregar un tema de un paquete Nuget (como el luz y oscuro temas), puede crear su propio recurso de
temas de diccionario que se pueden hacer referencia en la aplicación.
Ejemplo
Los tres BoxView s que se muestra en el página temas tienen un estilo según tres clases definidas en los dos temas
descargables.
Para entender cómo funcionan, el marcado siguiente crea un estilo equivalente que se puede agregar directamente
a su App.xaml.
Tenga en cuenta la Class atributo Style (en contraposición a la x:Key disponible en versiones anteriores de
Xamarin.Forms (atributo).
<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>
Observará que el Rounded clase hace referencia a un efecto personalizado CornerRadius . El código para este
efecto se indica a continuación: hacer referencia a él correctamente un personalizado xmlns deben agregarse a la
App.xamldel elemento raíz:
xmlns:local="clr-namespace:ThemesDemo;assembly=ThemesDemo"
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);
}
namespace ThemesDemo.iOS
{
public class CornerRadiusEffect : PlatformEffect
{
private nfloat _originalRadius;
UpdateCorner();
}
}
if (args.PropertyName == ThemeEffects.CornerRadiusProperty.PropertyName)
{
UpdateCorner();
}
}
namespace ThemesDemo.Droid
{
public class CornerRadiusEffect : BaseEffect
{
private ViewOutlineProvider _originalProvider;
if (!Attached)
{
return;
}
if (args.PropertyName == ThemeEffects.CornerRadiusProperty.PropertyName)
{
Container.Invalidate();
}
}
descargar el ejemplo
Una vista de Xamarin.Forms que permite al usuario seleccionar una hora.
Xamarin.Forms TimePicker invoca el control de selector de hora de la plataforma y permite al usuario seleccionar
una hora. TimePicker define las siguientes propiedades:
Time de tipo TimeSpan , la hora seleccionada, cuyo valor predeterminado es un TimeSpan de 0. El TimeSpan
tipo indica una duración de tiempo desde la medianoche.
Format de tipo string , un estándar o personalizado .NET formato de cadena, cuyo valor predeterminado es
"t", el patrón de hora corta.
TextColor de tipo Color , el color utilizado para mostrar la hora seleccionada, cuyo valor predeterminado es
Color.Default .
FontAttributes de tipo FontAttributes , cuyo valor predeterminado es FontAtributes.None .
FontFamily de tipo string , cuyo valor predeterminado es null .
FontSize de tipo double , que de forma predeterminada va de -1,0.
Todas estas propiedades están respaldados por BindableProperty objetos, lo que significa que puede cambiar el
estilo y las propiedades pueden ser destinos de enlaces de datos. El Time propiedad tiene un modo de enlace
predeterminada de BindingMode.TwoWay , lo que significa que puede ser un destino de enlace de datos en una
aplicación que utiliza el Model-View -ViewModel (MVVM ) arquitectura.
El TimePicker no incluye un evento para indicar un nuevo seleccionado Time valor. Si necesita recibir una
notificación de esto, puede agregar un controlador para el PropertyChanged eventos.
Cuando el Time se especifica la propiedad en XAML, el valor se convierte en un TimeSpan y validado para
asegurarse de que el número de milisegundos es mayor o igual que 0 y que el número de horas es menor que 24.
Los componentes de tiempo deben estar separados por signos de dos puntos:
Si el BindingContext propiedad de TimePicker está establecida en una instancia de un modelo de vista que
contiene una propiedad de tipo TimeSpan denominado SelectedTime (por ejemplo), puede crear una instancia el
TimePicker similar al siguiente:
TimePicker y diseño
Es posible usar una opción de diseño horizontal sin restricciones, como Center , Start ,o End con TimePicker :
<TimePicker ···
HorizontalOptions="Center"
··· />
Sin embargo, esto no se recomienda. Según la configuración de la Format propiedad, selecciona veces pueden
requerir los anchos de pantalla diferente. Por ejemplo, la cadena de formato "T" hace que el TimePicker vista para
mostrar veces en un formato largo y "4:15:26 A.M." requiere un mayor ancho de pantalla que el formato de hora
corta ("t") de "4:15 A.M.". Según la plataforma, esta diferencia puede provocar la TimePicker vista para cambiar el
ancho de diseño o en la presentación se trunque.
TIP
Es mejor usar el valor predeterminado HorizontalOptions de Fill con TimePicker y no se debe utilizar un ancho de
Auto al poner TimePicker en un Grid celda.
<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>
El Entry permite escribir el texto de recordatorio que se mostrará cuando se produce el tiempo seleccionado. El
TimePicker se asigna un Format propiedad de "T" para el formato de hora larga. Tiene un controlador de
eventos asociado a la PropertyChanged eventos y el Switch ha adjuntado un controlador a su Toggled eventos.
Estos controladores de eventos están en el archivo de código subyacente y llamar a la SetTriggerTime método:
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 SetTriggerTime()
{
if (_switch.IsToggled)
{
_triggerTime = DateTime.Today + _timePicker.Time;
if (_triggerTime < DateTime.Now)
{
_triggerTime += TimeSpan.FromDays(1);
}
}
}
}
Siempre que el Switch se alterna en la posición, la aplicación muestra un cuadro de diálogo de alerta recuerda al
usuario del texto en el Entry cuando se produce la hora seleccionada:
Tan pronto como se muestra el cuadro de diálogo de alerta, el Switch cambia a la posición de apagado.
Vínculos relacionados
Ejemplo de SetTimer
TimePicker API
Xamarin.Forms Visual
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Diseño de materiales es un sistema de diseño bien fundamentadas creado por Google, que establece el tamaño,
color, espaciado y otros aspectos de cómo las vistas y diseños deben aspecto y comportamiento.
Xamarin.Forms Material Visual puede utilizarse para aplicar las reglas de Material Design a las aplicaciones de
Xamarin.Forms, crear aplicaciones que tienen un aspecto idénticos o idéntica en gran medida en iOS y Android.
Cuando se habilita Material Visual, vistas admitidas adoptarán el mismo diseño multiplataforma, crear una
apariencia unificada. Esto se logra con los representadores de material, que se aplican las reglas de diseño de
materiales.
Es el proceso para habilitar Visual del Material de Xamarin.Forms en la aplicación:
1. Agregar el Xamarin.Forms.Visual.Material paquete NuGet a los proyectos de plataforma Android y iOS. Este
paquete de NuGet entrega optimizada de los representadores de Material Design en iOS y Android. En iOS, el
paquete proporciona la dependencia transitiva al Xamarin.iOS.MaterialComponents, que es un C# enlazar a
Google componentes de Material para iOS. En Android, el paquete proporciona destinos de compilación para
asegurarse de que su TargetFramework está configurado correctamente.
2. Inicializar a los representadores de material en cada proyecto de la plataforma. Para obtener más información,
consulte inicializar representadores materiales.
3. Consumir los representadores de material estableciendo el Visual propiedad Material en todas las páginas
que deben adoptar las reglas de diseño de materiales. Para obtener más información, consulte consumir los
representadores de material.
4. [opcional] Personalizar a los representadores de material. Para obtener más información, consulte personalizar
representadores materiales.
IMPORTANT
En Android, los representadores de material requieren una versión mínima de 5.0 (API 21) o superior y un TargetFramework
de la versión 9.0 (28 de API). Además, el proyecto de plataforma requiere compatibilidad con Android bibliotecas 28.0.0 o
superior, y su tema debe heredar de un tema de los componentes de Material o continuar heredar de un tema de
AppCompat. Para obtener más información, consulte Introducción a los componentes de Material para Android.
Funcionalmente, los representadores de material no son distintos a los representadores de forma predeterminada.
global::Xamarin.Forms.Forms.Init();
FormsMaterial.Init();
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
FormsMaterial.Init(this, savedInstanceState);
<ContentPage Visual="Material"
...>
...
</ContentPage>
El Visual propiedad puede establecerse en cualquier tipo que implemente IVisual , con el VisualMarker clase
que proporciona la siguiente IVisual propiedades:
Default : indica que la vista debe presentarse mediante el representador predeterminado.
MatchParent : indica que la vista debe utilizar el representador mismo como su elemento primario directo.
Material : indica que la vista debe representar con un procesador de material.
IMPORTANT
El Visual propiedad está definida en el VisualElement (clase), con vistas al heredar el Visual valor de propiedad de sus
elementos primarios. Por consiguiente, establecer el Visual propiedad en un ContentPage garantiza que todas las vistas
admitidas en la página usará ese objeto Visual. Además, el Visual propiedad se puede invalidar en una vista.
Las capturas de pantalla siguientes muestran una interfaz de usuario que se va a representar utilizando a los
representadores de forma predeterminada:
Las capturas de pantalla siguientes muestran la misma interfaz de usuario que se va a representar utilizando a los
representadores de materiales:
Las principales diferencias visibles entre los representadores de material, se muestra aquí y de los representadores
de forma predeterminada son que aproveche los representadores de material Button texto y redondear las
esquinas del Frame bordes. Sin embargo, los representadores de material usar controles nativos y, por tanto,
puede haber diferencias de la interfaz de usuario entre plataformas para áreas como fuentes, colores, sombras y
elevación.
NOTE
Componentes de diseño de materiales cumplen rigurosamente las directrices de Google. Como resultado, los
representadores de Material Design están orientados a ese cambio de tamaño y el comportamiento. Cuando necesite mayor
control del comportamiento o los estilos, puede crear sus propios efecto, comportamiento, o Custom Renderer para lograr el
detalle que se requiera.
using Xamarin.Forms.Material.Android;
NOTE
Un representador que especifica un IVisual tipo, como parte de su ExportRendererAttribute , se usará para
representar participa en las vistas, en lugar de con el representador predeterminado. En tiempo de selección del
representador, el Visual propiedad de la vista es inspeccionar y se incluye en el proceso de selección del representador.
Para obtener más información acerca de los representadores personalizados, consulte representadores
personalizados.
Vínculos relacionados
Material Visual (ejemplo)
Crear a un representador Xamarin.Forms Visual
Representadores personalizados
Crear a un representador Xamarin.Forms Visual
11/07/2019 • 6 minutes to read • Edit Online
descargar el ejemplo
Xamarin.Forms Visual permite crear y aplicar de forma selectiva a los representadores de VisualElement objetos,
sin tener que las vistas de Xamarin.Forms subclase. Un representador que especifica un IVisual tipo, como parte
de su ExportRendererAttribute , se usará para representar participa en las vistas, en lugar de con el representador
predeterminado. En tiempo de selección del representador, el Visual propiedad de la vista es inspeccionar y se
incluye en el proceso de selección del representador.
IMPORTANT
Actualmente la Visual propiedad no se puede cambiar después de que se ha representado la vista, pero esta operación
cambiará en futuras versiones.
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
El ejemplo de código siguiente muestra a la representación de botón para Android:
if (e.OldElement != null)
{
// Cleanup
}
if (e.NewElement != null)
{
Control.SetShadowLayer(5, 3, 3, Color.Black.ToAndroid());
}
}
}
El CustomVisual tipo, a continuación, se puede registrar en las clases de representador que permita Button
objetos que opten por usar los representadores.
<Button Visual="Custom"
Text="CUSTOM BUTTON"
BackgroundColor="{StaticResource PrimaryColor}"
TextColor="{StaticResource SecondaryTextColor}"
HorizontalOptions="FillAndExpand" />
NOTE
En XAML, un convertidor de tipos elimina la necesidad de incluir el sufijo "Visual" en el Visual valor de propiedad. Sin
embargo, también se puede especificar el nombre de tipo completo.
En tiempo de selección del representador, el Visual propiedad de la Button es inspeccionar y puede incluir en el
proceso de selección del representador. Si no encuentra un representador, se usará el representador
predeterminado de Xamarin.Forms.
Las capturas de pantalla siguientes muestran el representado Button , que muestra su texto con sombreado:
<Button Visual="MyVisual"
... />
NOTE
Al consumir un objeto Visual a través de su nombre registrado, se debe incluir cualquier sufijo "Visual".
Vínculos relacionados
Material Visual (ejemplo)
Material de Xamarin.Forms Visual
Representadores personalizados
El Administrador de estado Visual de
Xamarin.Forms
11/07/2019 • 28 minutes to read • Edit Online
descargar el ejemplo
Utilice Visual State Manager para realizar cambios en los elementos XAML basados en los estados visuales
establecer desde el código.
El Administrador de estado Visual (VSM ) es nuevo en Xamarin.Forms 3.0. VSM proporciona una manera
estructurada para realizar cambios visuales en la interfaz de usuario desde el código. En la mayoría de los
casos, la interfaz de usuario de la aplicación se define en XAML, y este XAML incluye marcado que describe
cómo Visual State Manager afecta a los objetos visuales de la interfaz de usuario.
VSM introduce el concepto de estados visuales. Una vista de Xamarin.Forms, como un Button puede tener
varios una apariencia visual distinta según su estado subyacente — si está deshabilitado, o presiona o, tiene
foco de entrada. Estos son los Estados del botón.
Estados visuales se recopilan en grupos de estado visual. Todos los estados visuales dentro de un grupo de
estados visuales son mutuamente excluyentes. Estados visuales y grupos de estado visual se identifican
mediante cadenas de texto simple.
Xamarin.Forms Visual State Manager define un grupo de estados visuales denominado "CommonStates" con
tres estados visuales:
"Normal"
"Deshabilitado"
"Con foco"
Es compatible con todas las clases que derivan de este grupo de estados visuales VisualElement , que es la
clase base para View y Page .
También puede definir sus propios grupos de estados visuales y estados visuales, como en este artículo se
muestran.
NOTE
Xamarin.Forms los desarrolladores familiarizados con desencadenadores son conscientes de que los desencadenadores
también pueden realizar cambios en los objetos visuales en la interfaz de usuario según los cambios en las propiedades
de una vista o la activación de eventos. Sin embargo, usar desencadenadores para tratar con varias combinaciones de
estos cambios puede ser algo confuso. Históricamente, el Administrador de estado Visual se introdujo en entornos
basados en XAML de Windows para solucionar la confusión resultante de las combinaciones de estados visuales. VSM
los estados visuales dentro de un grupo de estados visuales siempre son mutuamente excluyentes. En cualquier
momento, solo un estado de cada grupo es el estado actual.
<Entry FontSize="18">
</Entry>
Asignó un tamaño de fuente explícita porque uno de los Estados que usará el FontSize propiedad duplicar el
tamaño del texto en el Entry .
A continuación, inserte VisualStateManager.VisualStateGroups etiquetas entre las etiquetas:
<Entry FontSize="18">
<VisualStateManager.VisualStateGroups>
</VisualStateManager.VisualStateGroups>
</Entry>
VisualStateGroups es una propiedad enlazable adjunta definida por el VisualStateManager clase. (Para obtener
más información sobre las propiedades enlazables adjuntas, consulte el artículo propiedades adjuntas.) Se
trata cómo el VisualStateGroups propiedad está asociada a la Entry objeto.
El VisualStateGroups propiedad es de tipo VisualStateGroupList , que es una colección de VisualStateGroup
objetos. Dentro de la VisualStateManager.VisualStateGroups etiquetas, inserte un par de VisualStateGroup
etiquetas para cada grupo de estados visuales que desea incluir:
<Entry FontSize="18">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Entry>
Tenga en cuenta que el VisualStateGroup etiqueta tiene una x:Name atributo que indica el nombre del grupo.
El VisualStateGroup clase define un Name propiedad que puede usar en su lugar:
<VisualStateGroup Name="CommonStates">
<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>
VisualState define una propiedad denominada Setters , que es una colección de Setter objetos. Estas son
las mismas Setter objetos que se usan en un Style objeto.
Setters es no la propiedad content de VisualState , por lo que es necesario incluir las etiquetas de elemento
de propiedad para el Setters propiedad:
<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>
Ahora puede insertar uno o varios Setter objetos entre cada par de Setters etiquetas. Estos son los Setter
objetos que definen los estados visuales que se ha descrito 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 etiqueta indica el valor de una propiedad determinada cuando ese estado está activo. Cualquier
propiedad que se hace referencia a un Setter objeto debe estar respaldado por una propiedad enlazable.
Similar a este marcado es la base de la VSM en la vista página en el VsmDemos programa de ejemplo. La
página incluye tres Entry vistas, pero solo la segunda se tiene la marca de VSM conectada a ella:
<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>
<Entry />
<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>
<Entry x:Name="entry3"
Text=""
Placeholder="Type something to enable 2nd Entry" />
</StackLayout>
</ContentPage>
Tenga en cuenta que el segundo Entry también tiene un DataTrigger como parte de su Trigger colección.
Esto hace que el Entry deshabilitarse hasta que no se escribe algo en la tercera Entry . Esta es la página de
inicio que se ejecutan en iOS, Android y la plataforma Universal de Windows (UWP ):
El estado visual actual es "Disabled" por lo que el fondo de la segunda Entry es de color fucsia en iOS y
Android pantallas. La implementación de UWP de Entry no permite establecer el fondo de color cuando el
Entry está deshabilitado.
Cuando escriba algún texto en la tercera Entry , el segundo Entry modificadores en el estado "Normal" y el
fondo es ahora CAL:
Al tocar el segundo Entry , obtiene el foco de entrada. Se activa en estado "Focused" y se expande al doble del
alto:
Tenga en cuenta que el Entry no conserva el fondo de color verde cuando recibe el foco de entrada. Como
Visual State Manager cambia entre los estados visuales, no están establecidas las propiedades establecidas por
el estado anterior. Tenga en cuenta que los estados visuales son mutuamente excluyentes. El estado "Normal"
no significa solamente que el Entry está habilitado. Esto significa que el Entry está habilitado y no tiene el
foco de entrada.
Si desea que el Entry para tener un fondo de color verde en el estado "Enfocado", agregue otro Setter a ese
estado visual:
<VisualState x:Name="Focused">
<VisualState.Setters>
<Setter Property="FontSize" Value="36" />
<Setter Property="BackgroundColor" Value="Lime" />
</VisualState.Setters>
</VisualState>
En orden para estas Setter objetos funcione correctamente, un VisualStateGroup debe contener VisualState
objetos para todos los Estados de ese grupo. Si no hay un estado visual que no tiene ningún Setter objetos,
incluirla como una etiqueta vacía:
<Style TargetType="Entry">
<Setter Property="Margin" Value="20, 0" />
<Setter Property="FontSize" Value="18" />
</Style>
</Setter>
</Style>
La propiedad de contenido para Setter es Value , por lo que el valor de la Value propiedad se puede
especificar directamente dentro de esas etiquetas. Que es propiedad de tipo VisualStateGroupList :
<Style TargetType="Entry">
<Setter Property="Margin" Value="20, 0" />
<Setter Property="FontSize" Value="18" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
</VisualStateGroupList>
</Setter>
</Style>
<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>
<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>
<Entry />
<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>
<Entry x:Name="entry3"
Text=""
Placeholder="Type something to enable 2nd Entry" />
</StackLayout>
</ContentPage>
Ahora todos los Entry vistas en esta página responden a la misma manera para sus estados visuales. Tenga
en cuenta también que el estado de "Focused" incluye ahora un segundo Setter que ofrece cada Entry una
CAL fondo también cuando tiene foco de entrada:
VisualStateManager.GoToState(this, "Focused");
Este es el único código Visual State Manager que encontrará en el VisualElement clase. Dado que GoToState
se llama para cada objeto en función de cada clase que derive de VisualElement , puede utilizar Visual State
Manager con cualquier VisualElement objeto para responder a estos cambios.
Curiosamente, el nombre del grupo de estados visuales "CommonStates" no se mencionan explícitamente en
VisualElement . El nombre del grupo no es parte de la API para el Administrador de estado Visual. Dentro de
uno de los dos programa de ejemplo mostrado hasta ahora, puede cambiar el nombre del grupo de
"CommonStates" en cualquier otro valor y el programa seguirá funcionando. El nombre del grupo es
simplemente una descripción general de los Estados de ese grupo. Implícitamente se entiende que los estados
visuales en todos los grupos se excluyen mutuamente: Un estado y el estado de un único es actual en cualquier
momento.
Si desea implementar sus propios estados visuales, deberá llamar a VisualStateManager.GoToState desde el
código. Con más frecuencia, hará que esta llamada desde el archivo de código subyacente de la clase de
página.
El VSM validación página en el VsmDemos ejemplo muestra cómo utilizar Visual State Manager en relación
con la validación de entrada. El archivo XAML consta de dos Label elementos, un Entry , y 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">
<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>
</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="Invalid">
<VisualState.Setters>
<Setter Property="IsEnabled" Value="False" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Button>
</StackLayout>
</ContentPage>
Marcado VSM está asociado a la segunda Label (denominado helpLabel ) y el Button (denominado
submitButton ). Hay dos estados se excluyen mutuamente, denominados "Valid" y "No válido". Tenga en cuenta
que contiene cada uno de los dos grupos de "ValidationState" VisualState etiquetas para "Valid" y "No válido",
aunque uno de ellos está vacío en cada caso.
Si el Entry no contiene un número de teléfono válido, a continuación, el estado actual es "No válido" por lo
que el segundo Label está visible y el Button está deshabilitado:
Cuando se escribe un número de teléfono válido, el estado actual es "Valid". El segundo Entry desaparece y el
Button ahora está habilitado:
GoToState(false);
}
Observe también que el GoToState se llama al método desde el constructor para inicializar el estado. Siempre
debe haber un estado actual. Pero no en el código está ahí cualquier referencia al nombre del grupo de estados
visuales, aunque se hace referencia en el XAML como "ValidationStates" para fines de claridad.
Tenga en cuenta que el archivo de código subyacente debe tener en cuenta todos los objetos en la página que
se ve afectada por estos estados visuales y llamar a VisualStateManager.GoToState para cada uno de estos
objetos. En este ejemplo, es solo dos objetos (el Label y Button ), pero podría ser varias más.
Tal vez se pregunte: Si el archivo de código subyacente debe hacer referencia a todos los objetos en la página
que se ve afectado por estos estados visuales, ¿por qué no el archivo de código subyacente basta con acceder a
los objetos directamente? Seguramente podría. Sin embargo, la ventaja de usar VSM es que puede controlar
cómo visual elementos reaccionan a otro estado completamente en XAML, que conserva todo el diseño de
interfaz de usuario en una ubicación. Esto evita la apariencia visual de configuración mediante el acceso a los
elementos visuales directamente desde el código subyacente.
Puede ser tentador que considere la posibilidad de derivar una clase de Entry y quizás definir una propiedad
que se puede establecer para una función de validación externo. La clase que derive de Entry , a continuación,
puede llamar a la VisualStateManager.GoToState método. Este esquema funcionará bien, pero solo si el Entry
era el único objeto afectado por los diferentes estados visuales. En este ejemplo, un Label y un Button son
también se ve afectado. No hay ninguna manera de marcado VSM adjunta a un Entry a otros objetos en la
página y no hay forma de control para marcado VSM asociado a estos otros objetos para hacer referencia a un
cambio en el estado visual de otro objeto.
En modo horizontal, la matriz de botones podría mover a un lado y muestra en una columna:
De arriba a abajo, el programa se está ejecutando en la plataforma Universal de Windows, iOS y Android.
El diseño adaptable VSM página en el VsmDemos ejemplo define un grupo denominado "OrientationStates"
con dos estados visuales denominados "Vertical" y "Horizontal". (Un enfoque más complejo podría basarse en
varios diferentes anchos de página o ventana).
Marcado VSM se produce en cuatro lugares en el archivo XAML. El StackLayout denominado mainStack
contiene el menú y el contenido, que es un Image elemento. Esto StackLayout debe tener una orientación
vertical en modo vertical y una orientación horizontal en modo horizontal:
<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="Monkey"
Command="{Binding SelectedCommand}"
CommandParameter="monkey.png" />
<Image x:Name="image"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand" />
</StackLayout>
</ContentPage>
menuStack.BindingContext = this;
}
Vínculos relacionados
VsmDemos
Xamarin.Forms WebView
11/07/2019 • 19 minutes to read • Edit Online
descargar el ejemplo
WebView es una vista para mostrar la web y el contenido HTML en la aplicación. A diferencia de OpenUri , que
lleva al usuario en el explorador web en el dispositivo, WebView muestra el contenido HTML dentro de la
aplicación.
Contenido
WebView admite los siguientes tipos de contenido:
Sitios Web HTML y CSS – WebView es totalmente compatible con sitios Web escritos con HTML y CSS,
incluida la compatibilidad con JavaScript.
Documentos – porque WebView se implementa con componentes nativos en cada plataforma, WebView es
capaz de mostrar los documentos que están visibles en cada plataforma. Esto significa que los archivos PDF
funcionan en iOS y Android.
Las cadenas HTML – WebView puede mostrar las cadenas HTML de la memoria.
Archivos locales – WebView puede presentar cualquiera de los tipos de contenido anteriores incrustado en la
aplicación.
NOTE
WebView en Windows no admite Silverlight, Flash o los controles ActiveX, incluso si son compatibles con Internet Explorer
en esa plataforma.
Sitios web
Para mostrar un sitio Web desde internet, establezca el WebView del Source propiedad a una dirección URL de
cadena:
NOTE
Las direcciones URL se deben formar totalmente con el protocolo especificado (es decir, debe tener "http://" o "https://"
antepuesto a él).
iOS y ATS
Desde la versión 9, iOS solo permitirá a su aplicación comunicarse con servidores que implementan la seguridad
de prácticas recomendadas de forma predeterminada. Los valores que se deben establecer Info.plist para
habilitar la comunicación con servidores no seguras.
NOTE
Si la aplicación requiere una conexión a un sitio Web no seguro, siempre debe escribir el dominio como una excepción
mediante NSExceptionDomains en lugar de desactivar que ATS completamente utilizando NSAllowsArbitraryLoads .
NSAllowsArbitraryLoads solo debe usarse en situaciones de emergencias extremas.
El siguiente muestra cómo habilitar un dominio específico (en este caso en xamarin.com) para omitir los
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>
Es una práctica recomendada para permitir solo algunos dominios omitir ATS, lo que permite utilizar los sitios de
confianza y seguir disfrutando de la seguridad adicional sobre los dominios de confianza. A continuación muestra
el método menos seguro de deshabilitar ATS para la aplicación:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads </key>
<true/>
</dict>
...
</key>
Consulte App Transport Security para obtener más información acerca de esta nueva característica de iOS 9.
Cadenas HTML
Si desea presentar una cadena HTML que se define de forma dinámica en el código, deberá crear una instancia de
HtmlWebViewSource :
En el código anterior, @ se usa para marcar el código HTML como una cadena literal, lo que significa que se
omiten todos los caracteres de escape habituales.
NOTE
Puede ser necesario establecer el WidthRequest y HeightRequest propiedades de la WebView para ver el contenido
HTML, dependiendo del diseño el WebView es un elemento secundario. Por ejemplo, esto es necesario en un
StackLayout .
Contenido HTML
WebView puede mostrar el contenido de HTML, CSS y Javascript incrustados dentro de la aplicación. Por
ejemplo:
<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;
}
Tenga en cuenta que las fuentes especificadas en las CSS anterior debe personalizarse para cada plataforma, ya
que no todas las plataformas tiene las mismas fuentes.
Para mostrar local contenido mediante un WebView , deberá abrir el archivo HTML como cualquier otro, a
continuación, cargar el contenido como una cadena en el Html propiedad de un HtmlWebViewSource . Para obtener
más información sobre los archivos de apertura, consulte trabajar con archivos.
Las capturas de pantalla siguientes muestran el resultado de mostrar el contenido local en cada plataforma:
Aunque la primera página se ha cargado, el WebView no tiene conocimiento de dónde procede el código HTML.
Que es un problema cuando se trabaja con páginas que hacen referencia a los recursos locales. Cuando el vínculo
local páginas unos de otros, una página hace uso de un archivo JavaScript independiente o una página se vincula
a una hoja de estilos CSS son ejemplos de cuándo esto puede suceder.
Para resolver este problema, deberá indicar el WebView dónde encontrar los archivos en el sistema de archivos.
Hacerlo estableciendo la BaseUrl propiedad en el HtmlWebViewSource utilizado por el WebView .
Dado que el sistema de archivos en cada uno de los sistemas operativos es diferente, deberá determinar esa
dirección URL en cada plataforma. Xamarin.Forms presenta el DependencyService para resolver las dependencias
en tiempo de ejecución en cada plataforma.
Para usar el DependencyService , primero defina una interfaz que se puede implementar en cada plataforma:
Tenga en cuenta que hasta que la interfaz se implementa en cada plataforma, no se ejecutará la aplicación. En el
proyecto común, asegúrese de que recuerde establecer la BaseUrl utilizando el DependencyService :
Android
En Android, coloque las imágenes, CSS y HTML en la carpeta de activos con la acción de compilación
AndroidAsset como se muestra a continuación:
Visual Studio
Visual Studio para Mac
En Android, el BaseUrl debe establecerse en "file:///android_asset/" :
En Android, archivos en el activos carpeta también se puede acceder mediante el contexto de Android actual, que
se expone mediante el MainActivity.Instance propiedad:
[assembly: Dependency(typeof(BaseUrl))]
namespace WorkingWithWebview.UWP
{
public class BaseUrl : IBaseUrl
{
public string Get()
{
return "ms-appx-web:///";
}
}
}
Navegación
Vista Web admite la navegación a través de varios métodos y propiedades que están disponible:
GoForward() – si CanGoForward es true, una llamada a GoForward se desplaza hacia delante a la siguiente
página visitada.
GoBack() – si CanGoBack es true, una llamada a GoBack navegará a la última página visitada.
CanGoBack – true si hay páginas para ir a, false si el explorador se encuentre en la dirección URL de
inicio.
CanGoForward – true si el usuario ha navegado hacia atrás y puede avanzar a una página que ya ha
visitado.
En las páginas, WebView no es compatible con los gestos multitoque. Es importante para asegurarse de que el
contenido está optimizada para móviles y aparece sin la necesidad de zoom.
Es habitual que las aplicaciones mostrar un vínculo dentro de un WebView , en lugar del explorador del dispositivo.
En estos casos, resulta útil permitir la navegación normal, pero cuando el usuario eligió una mientras están en el
vínculo de inicio, la aplicación debe volver a la vista de aplicación normal.
Para habilitar este escenario, utilice las propiedades y métodos de navegación integrados.
Empiece por crear la página de la vista de explorador:
<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>
En el código subyacente:
public partial class InAppBrowserXaml : ContentPage
{
public InAppBrowserXaml(string URL)
{
InitializeComponent();
webView.Source = URL;
}
Ya está.
Eventos
WebView provoca los eventos siguientes para ayudarle a responder a los cambios de estado:
Navigating : evento se genera cuando la vista Web comienza a cargar una nueva página.
Navigated : evento se genera cuando se carga la página y se ha detenido la navegación.
ReloadRequested : evento se genera cuando se realiza una solicitud para volver a cargar el contenido actual.
El WebNavigatingEventArgs objeto que acompaña a la Navigating eventos tiene cuatro propiedades:
Cancel : indica si se deben cancelar la navegación.
NavigationEvent : el evento de navegación que se produjo.
Source : el elemento que realiza la navegación.
Url : el destino de navegación.
Si prevé que usará las páginas Web que toman mucho tiempo en cargar, considere el uso de la Navigating y
Navigated eventos para implementar un indicador de estado. Por ejemplo:
<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>
Cuando el Reload método se invoca el ReloadRequested se desencadena el evento, que indica que se ha realizado
una solicitud para volver a cargar el contenido actual.
Rendimiento
Ahora, los exploradores web populares adoptarán las tecnologías como la representación y la compilación de
JavaScript de aceleración de hardware. En iOS, de forma predeterminada, Xamarin.Forms WebView se
implementa mediante el UIWebView clase y muchas de estas tecnologías no están disponibles en esta
implementación. Sin embargo, una aplicación puede participar en utilizar iOS WkWebView clase implemente
Xamarin.Forms WebView , que es compatible con una navegación más rápida. Esto se consigue agregando el
código siguiente a la AssemblyInfo.cs archivo en el proyecto de la plataforma iOS para la aplicación:
Permisos
En orden para WebView para que funcione, debe asegurarse de que los permisos se establecen para cada
plataforma. Tenga en cuenta que en algunas plataformas, WebView funcionará en modo de depuración, pero no
cuando se compila para la versión. Eso es porque algunos permisos, como los de acceso a internet en Android, se
establecen de manera predeterminada Visual Studio para Mac en el modo de depuración.
UWP – requiere la capacidad de Internet (cliente y servidor) al mostrar el contenido de la red.
Android – requiere INTERNET solo al mostrar el contenido de la red. El contenido local no requiere ningún
permiso especial.
iOS – no requiere permisos especiales.
Diseño
A diferencia de la mayoría de vistas de Xamarin.Forms, WebView requiere que HeightRequest y WidthRequest se
especifican al contenido en StackLayout o RelativeLayout. Si no especifica las propiedades, los WebView no se
representará.
Los ejemplos siguientes muestran los diseños que dar lugar a trabajar, representación WebView s:
StackLayout con WidthRequest & HeightRequest:
<StackLayout>
<Label Text="test" />
<WebView Source="http://www.xamarin.com/"
HeightRequest="1000"
WidthRequest="1000" />
</StackLayout>
<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>
<Label Text="test" AbsoluteLayout.LayoutBounds="0,0,100,100" />
<WebView Source="http://www.xamarin.com/"
AbsoluteLayout.LayoutBounds="0,150,500,500" />
</AbsoluteLayout>
Cuadrícula sin WidthRequest & HeightRequest. Cuadrícula es uno de los diseños de algunas que no necesita
especificar los anchos y altos 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>
Invocación de JavaScript
WebView incluye la capacidad para invocar una función de JavaScript desde C#y se devuelve ningún resultado
para la llamada a C# código. Esto se consigue con la WebView.EvaluateJavaScriptAsync método, que se muestra en
el ejemplo siguiente de la WebView ejemplo:
<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>
Vínculos relacionados
Trabajar con la vista Web (ejemplo)
Vista Web (ejemplo)
Características de la plataforma de Xamarin.Forms
11/07/2019 • 2 minutes to read • Edit Online
Android
Esta guía describe los detalles de plataforma Android proporcionados por Xamarin.Forms y cómo implementar
Material Design mediante la actualización de aplicaciones de Xamarin.Forms Android existentes.
Clase de dispositivo
Esta guía describe cómo usar el Device clase para crear un comportamiento específico de la plataforma en código
compartido y la interfaz de usuario (incluido el uso de XAML ) y cómo interactuar con los controles de interfaz de
usuario de subprocesos en segundo plano.
iOS
Esta guía describen los detalles plataforma de iOS proporcionados por Xamarin.Forms y cómo realizar aplicar
estilos a través de iOS adicionales Info.plist y UIAppearance API.
Formularios nativos
Formularios nativos permiten Xamarin.Forms ContentPage -derivados de las páginas que será consumido por los
proyectos nativos de Xamarin.iOS, Xamarin.Android y plataforma Universal de Windows (UWP ).
Vistas nativas
Pueden hacer referencia directamente a vistas nativas de iOS, Android y la plataforma Universal de Windows de
Xamarin.Forms. Se pueden establecer las propiedades y los controladores de eventos en vistas nativas, y pueden
interactuar con las vistas de Xamarin.Forms.
Windows
Esta guía describe los detalles plataforma de Windows proporcionados Xamarin.Forms y cómo agregar un
proyecto UWP a una solución existente de Xamarin.Forms.
Características de la plataforma Android
11/07/2019 • 5 minutes to read • Edit Online
Desarrollo de aplicaciones de Xamarin.Forms para Android requiere Visual Studio. El página requisitos contiene
más información sobre los requisitos previos.
Y este es el mismo código después de actualizar el proyecto para usar FormsAppCompatActivity (y agregar la
información del tema adicional):
NOTE
Cuando se usa FormsAppCompatActivity , clases base para algunos representadores personalizados Android será diferente.
Vínculos relacionados
Agregar compatibilidad con Material Design
Adición de AppCompat y Material Design
11/07/2019 • 4 minutes to read • Edit Online
Siga estos pasos para convertir aplicaciones de Xamarin.Forms Android existentes para usar AppCompat y
Material Design
Información general
Estas instrucciones explican cómo actualizar las aplicaciones de Xamarin.Forms Android existentes para usar la
biblioteca AppCompat y habilitar el Material de diseño en la versión de Android de sus aplicaciones de
Xamarin.Forms.
1. Actualización de Xamarin.Forms
Asegúrese de que la solución está usando Xamarin.Forms 2.0 o posterior. Si es necesario, actualice el paquete de
Xamarin.Forms Nuget a 2.0.
2. Comprobar la versión de Android
Asegúrese de que .NET framework de destino del proyecto Android es Android 6.0 (Marshmallow ). Compruebe el
proyecto Android > Opciones > compilar > General configuración garantiza que el marco de trabajo corrent
está seleccionado:
<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>
Un estilo adicionales debe incluirse en el valores v21 carpeta para aplicar propiedades específicas cuando se
ejecuta en Android Lollipop y versiones más recientes.
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 garantizar este nuevo tema información sea utilizado, establezca el tema en el AndroidManifest archivo
agregando android:theme="@style/MyTheme" (deje el resto del código XML tal como estaba).
Properties/AndroidManifest.xml
...
<application android:label="AppName" android:icon="@drawable/icon"
android:theme="@style/MyTheme">
...
<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" />
Algunas propiedades de las pestañas se han establecido como la gravedad de la ficha fill y modo a fixed . Si
tiene muchas pestañas desea cambiarlo a desplazable - lea el Android TabLayout documentación para obtener
más información.
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" />
En estos archivos estamos creando un tema específico de la barra de herramientas que puede variar para la
aplicación. Hacer referencia a la barra de herramientas Hello del blog para obtener más información.
6. Actualización de la MainActivity
Por último, "conectar" los diseños del nuevo del paso 5 en el OnCreate método, como se muestra aquí:
descargar el ejemplo
Este Android específicos de plataforma controla si los botones de Xamarin.Forms usan los valores de sombra de
botones de Android y el relleno predeterminado. Se consume en XAML estableciendo el
Button.UseDefaultPadding y Button.UseDefaultShadow adjunta propiedades a 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>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...
button.On<Android>().SetUseDefaultPadding(true).SetUseDefaultShadow(true);
Tenga en cuenta que en la captura de pantalla encima de cada Button tiene definiciones idénticas, salvo que el
derecho Button utiliza el relleno predeterminado y los valores de sombra de los botones de Android.
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
AndroidSpecific API
AndroidSpecific.AppCompat API
Opciones del Editor de métodos de entrada de
entrada en Android
11/07/2019 • 4 minutes to read • Edit Online
descargar el ejemplo
Este específicos de plataforma Android establece el método de entrada de opciones del editor (IME ) para el
teclado en pantalla para una Entry . Esto incluye la configuración del botón de acción del usuario en la esquina
inferior del teclado en pantalla y las interacciones con el Entry . Se consume en XAML estableciendo el
Entry.ImeOptions propiedad adjunta a un valor de la ImeFlags enumeración:
<ContentPage ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core">
<StackLayout ...>
<Entry ... android:Entry.ImeOptions="Send" />
...
</StackLayout>
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...
entry.On<Android>().SetImeOptions(ImeFlags.Send);
El Entry.On<Android> método especifica que solo se ejecutarán este específicos de la plataforma en Android. El
Entry.SetImeOptions método, en el Xamarin.Forms.PlatformConfiguration.AndroidSpecific espacio de nombres, se
usa para establecer la opción de acción del método de entrada para el teclado en pantalla para el Entry , con el
ImeFlags enumeración que proporciona los siguientes valores:
Default : indica que se requiere ninguna acción específica de clave y que el control subyacente producirá sí
solo si puede. Esto será Next o Done .
None : indica que ninguna clave de la acción estará disponible.
Go : indica que la clave de acción llevará a cabo una operación de "Ir", al usuario en el destino del texto escrito.
Search : indica que la clave de acción realiza una operación de "búsqueda", al usuario a los resultados de
buscar el texto han escrito.
Send : indica que la clave de acción llevará a cabo una operación de "Enviar", que se entrega el texto a su
destino.
Next : indica que la clave de acción llevará a cabo una operación de "siguiente", tomar el usuario al siguiente
campo que aceptará el texto.
Done : indica que la clave de acción llevará a cabo una operación de "done", el teclado en pantalla de cierre.
Previous : indica que la clave de acción llevará a cabo una operación de "anterior", tomar el usuario al campo
anterior que aceptará el texto.
ImeMaskAction – la máscara para seleccionar las opciones de acción.
NoPersonalizedLearning : indica que el corrector ortográfico se obtenga la información del usuario, ni sugerir
correcciones según lo que el usuario ha escrito anteriormente.
NoFullscreen : indica que la interfaz de usuario no debería pasar a pantalla completa.
NoExtractUi : indica que no se mostrará ninguna interfaz de usuario para el texto extraído.
NoAccessoryAction : indica que no se mostrará ninguna interfaz de usuario para las acciones personalizadas.
El resultado es que un determinado ImeFlags se aplica el valor para el teclado en pantalla para el Entry , que
establece el método de entrada en las opciones del editor:
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
AndroidSpecific API
AndroidSpecific.AppCompat API
ImageButton sombras en Android
11/07/2019 • 3 minutes to read • Edit Online
descargar el ejemplo
Este Android específicos de plataforma se usan para habilitar una sombra paralela en un ImageButton . Se
consume en XAML estableciendo el ImageButton.IsShadowEnabled propiedad enlazable a true , junto con un
número de propiedades enlazables opcionales adicionales que controlan el efecto de 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>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...
IMPORTANT
Se dibuja una sombra paralela como parte de la ImageButton en segundo plano y el fondo se dibuja solo si el
BackgroundColor se establece la propiedad. Por lo tanto, una sombra paralela no se dibujarán si el
ImageButton.BackgroundColor no se establece la propiedad.
El ImageButton.On<Android> método especifica que solo se ejecutarán este específicos de la plataforma en Android.
El ImageButton.SetIsShadowEnabled método, en el Xamarin.Forms.PlatformConfiguration.AndroidSpecific espacio de
nombres, se usa para controlar si una sombra paralela está habilitada en el ImageButton . Además, se pueden
invocar los métodos siguientes para controlar el efecto de sombra:
SetShadowColor : establece el color de la sombra paralela. El color predeterminado es Color.Default .
SetShadowOffset : establece el desplazamiento de la sombra paralela. El desplazamiento cambia la dirección de
la sombra se convierte y se especifica como un Size valor. El Size los valores de la estructura se expresan en
unidades independientes del dispositivo, con el primer valor que se va a la distancia a la izquierda (valor
negativo) o la derecha (valor positivo) y el segundo valor que se va a la distancia anterior (negativo) o por
debajo (valor positivo) . El valor predeterminado de esta propiedad es (0.0, 0.0), que da como resultado la
sombra que se va a convertir en torno a cada lado de la ImageButton .
SetShadowRadius : establece el radio de desenfoque utilizado para representar la sombra paralela. El valor de
radio predeterminado es 10,0.
NOTE
Se puede consultar el estado de una sombra paralela mediante una llamada a la GetIsShadowEnabled , GetShadowColor ,
GetShadowOffset , y GetShadowRadius métodos.
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
AndroidSpecific API
AndroidSpecific.AppCompat API
Fast ListView desplazamiento en Android
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Este Android específicos de plataforma se usan para habilitar el desplazamiento rápido a través de los datos en un
ListView . Se consume en XAML estableciendo el ListView.IsFastScrollEnabled propiedad adjunta un 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>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...
listView.On<Android>().SetIsFastScrollEnabled(!listView.On<Android>().IsFastScrollEnabled());
El resultado es ese desplazamiento rápido a través de los datos en un ListView puede habilitarse, que cambia el
tamaño de la miniatura de desplazamiento:
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
AndroidSpecific API
AndroidSpecific.AppCompat API
Alto de la barra de NavigationPage en Android
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Este Android específicos de plataforma establece el alto de la barra de navegación en un NavigationPage . Se
consume en XAML estableciendo el NavigationPage.BarHeight propiedad enlazable en un valor entero:
<NavigationPage ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific.AppCompat;assembly=Xamarin.Forms.Core"
android:NavigationPage.BarHeight="450">
...
</NavigationPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific.AppCompat;
...
descargar el ejemplo
Este Android específicos de plataforma se usan para deshabilitar la Disappearing y Appearing eventos de página
en la aplicación pausar y reanudar, respectivamente, para las aplicaciones que usan AppCompat. Además, incluye
la capacidad para controlar si se muestra el teclado en pantalla al reanudar si se mostrara en pausa, siempre que el
modo de funcionamiento del teclado en pantalla se establece en WindowSoftInputModeAdjust.Resize .
NOTE
Tenga en cuenta que estos eventos están habilitados de forma predeterminada para conservar el comportamiento existente
para las aplicaciones que dependen de los eventos. Deshabilitar estos eventos hace que el ciclo de eventos AppCompat
coincide con el ciclo de eventos anteriores a AppCompat.
<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>
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);
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
AndroidSpecific API
AndroidSpecific.AppCompat API
Modo de entrada de teclado en pantalla en Android
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Este Android específicos de plataforma se usa para establecer el modo de funcionamiento para un área de entrada
de teclado en pantalla y se consume en XAML estableciendo el Application.WindowSoftInputModeAdjust propiedad
adjunta a un valor de la WindowSoftInputModeAdjust enumeración:
<Application ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
android:Application.WindowSoftInputModeAdjust="Resize">
...
</Application>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...
App.Current.On<Android>().UseWindowSoftInputModeAdjust(WindowSoftInputModeAdjust.Resize);
El Application.On<Android> método especifica que solo se ejecutarán este específicos de la plataforma en Android.
El Application.UseWindowSoftInputModeAdjust método, en el Xamarin.Forms.PlatformConfiguration.AndroidSpecific
espacio de nombres, se usa para establecer el modo de funcionamiento del área de entrada de teclado en pantalla,
con el WindowSoftInputModeAdjust enumeración que proporciona dos valores: Pan y Resize . El Pan valor usa la
AdjustPan la opción de ajuste, que no cambiar el tamaño de la ventana cuando un control de entrada tiene el foco.
En su lugar, el contenido de la ventana distribuido para que el foco actual no está oculto por el teclado en pantalla.
El Resize valor usa la AdjustResize la opción de ajuste, que cambia el tamaño de la ventana cuando un control
de entrada tiene el foco, para dejar espacio para el teclado en pantalla.
El resultado es que el teclado en pantalla se puede establecer el modo de funcionamiento cuando un control de
entrada tiene el foco del área de entrada:
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
AndroidSpecific API
AndroidSpecific.AppCompat API
Página TabbedPage desplazándose en Android
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Este Android específicos de plataforma se utilizan para habilitar el gesto de deslizar rápidamente con un gesto del
dedo horizontal entre las páginas de un TabbedPage . Se consume en XAML estableciendo el
TabbedPage.IsSwipePagingEnabled propiedad adjunta un boolean valor:
<TabbedPage ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
android:TabbedPage.OffscreenPageLimit="2"
android:TabbedPage.IsSwipePagingEnabled="true">
...
</TabbedPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...
On<Android>().SetOffscreenPageLimit(2)
.SetIsSwipePagingEnabled(true);
El TabbedPage.On<Android> método especifica que solo se ejecutarán este específicos de la plataforma en Android.
El TabbedPage.SetIsSwipePagingEnabled método, en el Xamarin.Forms.PlatformConfiguration.AndroidSpecific
espacio de nombres, se utiliza para habilitar el gesto de deslizar rápidamente entre las páginas de un TabbedPage .
Además, el TabbedPage clase en el Xamarin.Forms.PlatformConfiguration.AndroidSpecific espacio de nombres
también tiene un EnableSwipePaging método que permite este específicos de la plataforma, y un
DisableSwipePaging método que deshabilita Esta plataforma específica. El TabbedPage.OffscreenPageLimit
propiedad adjunta, y SetOffscreenPageLimit método, se utilizan para establecer el número de páginas que se
deben conservar en un estado de inactividad a cada lado de la página actual.
El resultado es que la paginación a través de las páginas se muestran por Deslizar rápidamente un TabbedPage
está habilitado:
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
AndroidSpecific API
AndroidSpecific.AppCompat API
Animaciones de transición de página TabbedPage en
Android
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Este Android específicos de plataforma se usan para deshabilitar las animaciones de transición al navegar a través
de páginas, ya sea mediante programación o cuando se usa la barra de pestañas, en un TabbedPage . Se consume
en XAML estableciendo el TabbedPage.IsSmoothScrollEnabled propiedad enlazable a false :
<TabbedPage ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
android:TabbedPage.IsSmoothScrollEnabled="false">
...
</TabbedPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...
On<Android>().SetIsSmoothScrollEnabled(false);
El TabbedPage.On<Android> método especifica que solo se ejecutarán este específicos de la plataforma en Android.
El TabbedPage.SetIsSmoothScrollEnabled método, en el Xamarin.Forms.PlatformConfiguration.AndroidSpecific
espacio de nombres, se usa para controlar si las animaciones de transición se mostrará al navegar entre páginas
en un TabbedPage . Además, el TabbedPage clase en el Xamarin.Forms.PlatformConfiguration.AndroidSpecific
espacio de nombres también tiene los métodos siguientes:
IsSmoothScrollEnabled , que se usa para recuperar datos si las animaciones de transición se mostrará al navegar
entre páginas en un TabbedPage .
EnableSmoothScroll , que se usa para habilitar animaciones de transición al navegar entre páginas en un
TabbedPage .
DisableSmoothScroll , que se usa para deshabilitar las animaciones de transición al navegar entre páginas en un
TabbedPage .
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
AndroidSpecific API
AndroidSpecific.AppCompat API
Colocación de la barra de herramientas TabbedPage
y Color en Android
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
IMPORTANT
Las funcionalidades específicas de plataforma que establece el color de la barra de herramientas en un TabbedPage ahora
están obsoletos y se han reemplazado por la SelectedTabColor y UnselectedTabColor propiedades. Para obtener más
información, consulte creando una TabbedPage.
Estas funcionalidades específicas de plataforma se utilizan para establecer la selección de ubicación y color de la
barra de herramientas en un TabbedPage . Que se consumen en XAML estableciendo el
TabbedPage.ToolbarPlacement propiedad adjunta a un valor de la ToolbarPlacement enumeración y el
TabbedPage.BarItemColor y TabbedPage.BarSelectedItemColor adjunta propiedades a un 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>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...
On<Android>().SetToolbarPlacement(ToolbarPlacement.Bottom)
.SetBarItemColor(Color.Black)
.SetBarSelectedItemColor(Color.Red);
NOTE
El GetToolbarPlacement , GetBarItemColor , y GetBarSelectedItemColor métodos pueden usarse para recuperar la
selección de ubicación y color de la TabbedPage barra de herramientas.
El resultado es que se pueden establecer la posición de la barra de herramientas, el color de los elementos de la
barra de herramientas y el color del elemento seleccionado de la barra de herramientas en un TabbedPage :
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
AndroidSpecific API
AndroidSpecific.AppCompat API
Elevación VisualElement en Android
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Este Android específicos de plataforma se usa para controlar la elevación o el orden Z de los elementos visuales en
aplicaciones que tienen como destino API 21 o mayor. La elevación de un elemento visual determina su orden de
dibujo, con elementos visuales con los valores más altos de Z occluding elementos visuales con los valores más
bajos de Z. Se consume en XAML estableciendo el VisualElement.Elevation propiedad adjunta un 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>
El resultado es que se puede controlar la elevación de los elementos visuales para que los elementos visuales con
los valores más altos de Z occlude elementos visuales con los valores más bajos de Z. Por lo tanto, en este ejemplo
el segundo Button se representa por encima del BoxView porque tiene un valor mayor de elevación:
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
AndroidSpecific API
AndroidSpecific.AppCompat API
Modo de Color VisualElement heredado en Android
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Algunas de las vistas de Xamarin.Forms cuentan con un modo de color heredado. En este modo, cuando el
IsEnabled se establece la propiedad de la vista en false , la vista invalida los colores establecidos por el usuario
con los colores nativo predeterminado para el estado deshabilitado. Para hacia atrás compatibilidad, este modo
heredado de color permanece el comportamiento predeterminado para las vistas admitidas.
Este Android específicos de plataforma deshabilita este modo heredado de color, para que los colores establecidos
en una vista por el usuario permanezcan incluso cuando la vista está deshabilitada. Se consume en XAML
estableciendo el VisualElement.IsLegacyColorModeEnabled propiedad adjunta 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>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...
_legacyColorModeDisabledButton.On<Android>().SetIsLegacyColorModeEnabled(false);
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
AndroidSpecific API
AndroidSpecific.AppCompat API
WebView mezclado en Android
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Este Android específicos de plataforma controla si un WebView puede mostrar contenido mixto en aplicaciones
que tienen como destino API 21 o posterior. El contenido mixto es el contenido que se cargó inicialmente a través
de una conexión HTTPS, pero que cargan recursos (por ejemplo, imágenes, audio, vídeo, hojas de estilo, scripts) en
una conexión HTTP. Se consume en XAML estableciendo el WebView.MixedContentMode propiedad adjunta a un
valor de la MixedContentHandling enumeración:
<ContentPage ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core">
<WebView ... android:WebView.MixedContentMode="AlwaysAllow" />
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...
webView.On<Android>().SetMixedContentMode(MixedContentHandling.AlwaysAllow);
descargar el ejemplo
Este Android específicos de plataforma permite acercar para alejar y un control de zoom en un WebView . Se
consume en XAML estableciendo el WebView.EnableZoomControls y WebView.DisplayZoomControls propiedades
enlazables a boolean valores:
<ContentPage ...
xmlns:android="clr-
namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core">
<WebView Source="https://www.xamarin.com"
android:WebView.EnableZoomControls="true"
android:WebView.DisplayZoomControls="true" />
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...
webView.On<Android>()
.EnableZoomControls(true)
.DisplayZoomControls(true);
El WebView.On<Android> método especifica que solo se ejecutarán este específicos de la plataforma en Android. El
WebView.EnableZoomControls método, en el Xamarin.Forms.PlatformConfiguration.AndroidSpecific espacio de
nombres, se usa para controlar si pinch a zoom está habilitado en el WebView . El WebView.DisplayZoomControls
método, en el mismo espacio de nombres, se utiliza para controlar si los controles de zoom se superponen en el
WebView . Además, el WebView.ZoomControlsEnabled y WebView.ZoomControlsDisplayed métodos pueden usarse para
devolver si se habilitan los controles de zoom y acercar para alejar, respectivamente.
El resultado es que acercar para alejar puede habilitarse en un WebView , y se pueden superponer los controles de
zoom en el WebView :
IMPORTANT
Controles de zoom deben ser habilitados y muestra, a través de las respectivas propiedades enlazables o métodos, que se
superpone en un WebView .
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
AndroidSpecific API
AndroidSpecific.AppCompat API
Clase Device de Xamarin.Forms
11/07/2019 • 11 minutes to read • Edit Online
descargar el ejemplo
La clase Device contiene un número de propiedades y métodos para ayudar a los desarrolladores personalizar
diseño y funcionalidad de acuerdo con cada plataforma.
Además de métodos y propiedades para el código de destino en los tipos de hardware específico y tamaños, el
Device clase incluye métodos que se pueden usar para interactuar con los controles de interfaz de usuario de
subprocesos en segundo plano. Para obtener más información, consulte interactúe con la interfaz de usuario de
subprocesos en segundo plano.
En C#, se pueden proporcionar valores específicos por plataforma mediante la creación de una instruccion
switch con la propiedad Device.RuntimePlatform y, a continuación, proporcionar las instrucciones case para
las plataformas necesarias:
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);
El OnPlatform clase es una clase genérica que debe crearse con un x:TypeArguments atributo que coincida con el
tipo de destino. En la clase On , el atributo Platform puede aceptar un único valor string o varios valores
string delimitados por comas.
IMPORTANT
Proporcionar un valor incorrecto en el atributo Platform de la clase On no producirá un error. En su lugar, el código se
ejecutará sin el valor específico de la plataforma que se va a aplicar.
Como alternativa, el OnPlatform se puede usar extensión de marcado en XAML para personalizar la apariencia
de la interfaz de usuario en forma de acuerdo con la plataforma. Para obtener más información, consulte
OnPlatform Markup Extension.
Device.Idiom
El Device.Idiom propiedad puede usarse para modificar los diseños o funcionalidad en función del dispositivo
de la aplicación se ejecuta en. El enumerador TargetIdiom contiene los siguientes valores:
Teléfono – iPhone, iPod touch y los dispositivos Android más estrechas que 600 DIP ^
Tablet : iPad, los dispositivos de Windows y dispositivos Android más amplio que 600 DIP ^
Escritorio : solo se devuelven en aplicaciones para UWP en equipos de escritorio de Windows 10 (devuelve
Phone en dispositivos móviles de Windows, como en escenarios de Continuum )
TV: dispositivos de TV con Tizen
Watch – relojes Tizen
Unsupported : no se utiliza
^ DIP no es necesariamente el número de píxeles físicos
El Idiom propiedad resulta especialmente útil para la creación de diseños que se benefician de las pantallas más
grandes, similar al siguiente:
if (Device.Idiom == TargetIdiom.Phone) {
// layout views vertically
} else {
// layout views horizontally for a larger display (tablet or desktop)
}
El OnIdiom clase es una clase genérica que debe crearse con un x:TypeArguments atributo que coincida con el
tipo de destino.
Como alternativa, el OnIdiom se puede usar extensión de marcado en XAML para personalizar la apariencia de
la interfaz de usuario en función de la expresión del dispositivo se está ejecutando la aplicación en. Para obtener
más información, consulte OnIdiom Markup Extension.
Device.FlowDirection
El Device.FlowDirection valor recupera un FlowDirection valor de enumeración que representa la dirección del
flujo actual que usa el dispositivo. La dirección de flujo es la dirección en la que el ojo humano lee los elementos
de la interfaz de usuario en la página. Los valores de la enumeración son:
LeftToRight
RightToRight
MatchParent
this.FlowDirection = Device.FlowDirection;
Para obtener más información acerca de la dirección del flujo, consulte localización de derecha a izquierda.
Device.Styles
La propiedad Styles contiene las definiciones de estilo integradas que pueden aplicarse a algunos de los
controles (como Label ) la propiedad Style . Los estilos disponibles son:
BodyStyle
CaptionStyle
ListItemDetailTextStyle
ListItemTextStyle
SubtitleStyle
TitleStyle
Device.GetNamedSize
GetNamedSize puede utilizarse al establecer FontSize en código C#:
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
El metodo OpenUri puede usarse para desencadenar operaciones en la plataforma nativa, como abrir una
dirección URL en el explorador web nativo (Safari en iOS o Internet en Android).
Device.OpenUri(new Uri("https://evolve.xamarin.com/"));
El ejemplo WebView incluye un ejemplo que usa OpenUri para abrir las direcciones URL y desencadenar
también llamadas telefónicas.
El ejemplo mapas también usa Device.OpenUri para mostrar mapas y las direcciones mediante la aplicacion de
Mapas nativa en iOS y Android.
Device.StartTimer
La clase Device también tiene un metodo StartTimer que proporciona una manera sencilla de desencadenar
tareas dependientes del tiempo que funcionan en el código común de Xamarin.Forms, incluidas una biblioteca
.NET Standard. Pasa un valor TimeSpan para establecer el intervalo y devuelve true para mantener el
temporizador en ejecución o false para detenerlo después de la invocación actual.
Si el código del temporizador interactúa con la interfaz de usuario (como establecer el texto de un Label o
mostrar una alerta) debe realizarse dentro de una expresión BeginInvokeOnMainThread (ver abajo).
GetMainThreadSynchronizationContextAsync Task<SynchronizationContext>Devuelve el
SynchronizationContext
del subproceso principal.
Vínculos relacionados
Ejemplo Device
Ejemplo Styles
Device
características de la plataforma de iOS de
Xamarin.Forms
11/07/2019 • 7 minutes to read • Edit Online
Desarrollo de aplicaciones de Xamarin.Forms para iOS requiere Visual Studio. El página requisitos contiene más
información sobre los requisitos previos.
descargar el ejemplo
Este iOS específicos de la plataforma establece el color de fondo predeterminado de Cell instancias. Se consume
en XAML estableciendo el Cell.DefaultBackgroundColor propiedad enlazable para un 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>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
descargar el ejemplo
Este iOS específicos de la plataforma establece el color de cursor de un Entry en un color especificado. Se
consume en XAML estableciendo el Entry.CursorColor propiedad enlazable para un Color :
<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core">
<StackLayout>
<Entry ... ios:Entry.CursorColor="LimeGreen" />
</StackLayout>
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
El Entry.On<iOS> método especifica que solo se ejecutarán este específicos de la plataforma de iOS. El
Entry.SetCursorColor método, en el Xamarin.Forms.PlatformConfiguration.iOSSpecific espacio de nombres,
Establece el color de cursor en un determinado Color . Además, el Entry.GetCursorColor método puede utilizarse
para recuperar el color actual del cursor.
El resultado es que el color del cursor en un Entry se puede establecer en un determinado Color :
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
iOSSpecific API
Tamaño de fuente de entrada en iOS
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Este específicos de plataforma de iOS se usan para escalar el tamaño de fuente de un Entry para asegurarse de
que se ajuste el texto de entrada en el control. Se consume en XAML estableciendo el
Entry.AdjustsFontSizeToFitWidth propiedad adjunta un 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>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
entry.On<iOS>().EnableAdjustsFontSizeToFitWidth();
entry.On<iOS>().SetAdjustsFontSizeToFitWidth(!entry.On<iOS>().AdjustsFontSizeToFitWidth());
El resultado es que el tamaño de fuente de la Entry se escala para asegurarse de que se ajuste el texto de entrada
en el control:
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
iOSSpecific API
Adición de formato específica de iOS
11/07/2019 • 4 minutes to read • Edit Online
Una manera de establecer iOS específicos de formato es crear un representador personalizado para un control y
los estilos específicos de la plataforma y los colores para cada plataforma.
Otras opciones para controlar la manera en la apariencia de la aplicación de iOS Xamarin.Forms incluyen:
Configuración Mostrar opciones en Info.plist
Establecer estilos de control a través de la UIAppearance API
Estas alternativas se describen a continuación.
Personalización de Info.plist
El Info.plist archivo le permite configurar algunos aspectos de renderering de una aplicación de iOS, por ejemplo,
cómo (y si) se muestra la barra de estado.
Por ejemplo, el ejemplo "todo" usa el código siguiente para establecer la barra de color y color del texto de
navegación en todas las plataformas:
El resultado se muestra en el siguiente fragmento de pantalla. Tenga en cuenta que los elementos de la barra de
estado son de color negros (no se puede establecer en Xamarin.Forms porque es una característica específica de la
plataforma).
Lo ideal es que la barra de estado también sería blanco: algo podemos realizar directamente en el proyecto de iOS.
Agregue las siguientes entradas a la Info.plist para forzar la barra de estado blanco:
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleLightContent</string>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
Ahora cuando se ejecuta la aplicación, la barra de navegación es verde y su texto es blanco (debido a un formato
de Xamarin.Forms) y el texto de la barra de estado también es blanco gracias a la configuración específica de iOS:
UIAppearance API
El UIAppearance API puede usarse para establecer propiedades visuales en muchos controles de iOS sin tener que
crear un representador personalizado.
Adición de una sola línea de código para el AppDelegate.cs FinishedLaunching método aplicar estilo a todos los
controles de un tipo determinado mediante sus Appearance propiedad. El código siguiente contiene dos ejemplos:
globalmente aplicar estilos a la pestaña de barras y cambiar el control:
AppDelegate.cs en el proyecto de iOS
UITabBar
De forma predeterminada, el icono de barra de la pestaña seleccionada en un TabbedPage sería azul:
Uso de esta API le permite personalizar la apariencia de Xamarin.Forms TabbedPage en iOS con muy poco código.
Hacer referencia a la receta personalizar pestañas para obtener más detalles sobre el uso de un representador
personalizado para establecer una fuente específica de la pestaña.
UISwitch
El Switch control es otro ejemplo que puede cambiar fácilmente el estilo:
Estas capturas de dos pantalla mostrar el valor predeterminado UISwitch control a la izquierda y la versión
personalizada (opción Appearance ) a la derecha en el ejemplo "todo":
Otros controles
Muchos controles de interfaz de usuario de iOS pueden tener sus colores predeterminados y otros atributos
establecidos mediante la UIAppearance API.
Vínculos relacionados
UIAppearance
Personalizar las fichas
Estilo de presentación de la página modal de iPad
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Este específicos de plataforma de iOS se usan para establecer el estilo de presentación de una página modal en un
iPad. Se consume en XAML estableciendo el Page.ModalPresentationStyle propiedad enlazable para un
UIModalPresentationStyle valor de enumeración:
<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
ios:Page.ModalPresentationStyle="FormSheet">
...
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
FullScreen , que establece el estilo de presentación modal para abarcar toda la pantalla. De forma
predeterminada, las páginas modales se muestran con este estilo de presentación.
FormSheet , que establece el estilo de presentación modal sea menor que la pantalla y centrado en.
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
iOSSpecific API
Títulos de página grande en iOS
11/07/2019 • 3 minutes to read • Edit Online
descargar el ejemplo
Este específicos de plataforma de iOS se usan para mostrar el título de página como un título de gran tamaño en
la barra de navegación de un NavigationPage , para los dispositivos que usan iOS 11 o superior. Un gran título
está alineado a la izquierda y usa una fuente mayor y realiza la transición a un título estándar como el usuario
comienza a desplazarse por el contenido, por lo que se usan de forma eficaz el espacio en pantalla. Sin embargo,
en orientación horizontal, el título devolverá al centro de la barra de navegación para optimizar el diseño del
contenido. Se consume en XAML estableciendo el NavigationPage.PrefersLargeTitles propiedad adjunta un
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>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
Title="Large Title"
ios:Page.LargeTitleDisplay="Never">
...
</ContentPage>
Además, el SetLargeTitleDisplay método puede utilizarse para activar o desactivar los valores de enumeración
mediante una llamada a la LargeTitleDisplay método, que devuelve el valor actual 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;
}
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
iOSSpecific API
Estilo de encabezado de grupo de ListView en iOS
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Este controles específicos de la plataforma de iOS si ListView las celdas de encabezado float durante el
desplazamiento. Se consume en XAML estableciendo el ListView.GroupHeaderStyle propiedad enlazable en un
valor de la GroupHeaderStyle enumeración:
<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core">
<StackLayout Margin="20">
<ListView ... ios:ListView.GroupHeaderStyle="Grouped">
...
</ListView>
</StackLayout>
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
listView.On<iOS>().SetGroupHeaderStyle(GroupHeaderStyle.Grouped);
Plain : indica que las celdas de encabezado float cuando la ListView es desplazado (valor predeterminado).
Grouped : indica que las celdas de encabezado no flotantes cuando el ListView se desplaza.
descargar el ejemplo
Este controles específicos de la plataforma de iOS si las animaciones de fila están deshabilitados cuando la
ListView se está actualizando la colección de elementos. Se consume en XAML estableciendo el
ListView.RowAnimationsEnabled propiedad enlazable a 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>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
listView.On<iOS>().SetRowAnimationsEnabled(false);
NOTE
ListView las animaciones de la fila se habilitan de forma predeterminada. Por lo tanto, se produce una animación cuando
se inserta una nueva fila en un ListView .
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
iOSSpecific API
Estilo del separador de ListView en iOS
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Este iOS específicos de la plataforma controla si el separador entre las celdas de un ListView usa todo el ancho
de la ListView . Se consume en XAML estableciendo el ListView.SeparatorStyle propiedad adjunta a un valor de
la SeparatorStyle enumeración:
<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core">
<StackLayout Margin="20">
<ListView ... ios:ListView.SeparatorStyle="FullWidth">
...
</ListView>
</StackLayout>
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
listView.On<iOS>().SetSeparatorStyle(SeparatorStyle.FullWidth);
El resultado es que un determinado SeparatorStyle valor se aplica a la ListView , que controla el ancho del
separador entre las celdas:
NOTE
Una vez que se ha establecido el estilo del separador en FullWidth , no se puede cambiar a Default en tiempo de
ejecución.
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
iOSSpecific API
Actualizaciones de Control de subproceso principal
en iOS
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Este específicos de plataforma de iOS permite controlar el diseño y representación de las actualizaciones que se
realizará en el subproceso principal, en lugar de que se va a realizar en un subproceso en segundo plano. Debería
ser necesario con poca frecuencia, pero en algunos casos puede evitar que se bloquee. Su XAML consumido en
estableciendo el Application.HandleControlUpdatesOnMainThread propiedad enlazable a true :
<Application ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
ios:Application.HandleControlUpdatesOnMainThread="true">
...
</Application>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
Xamarin.Forms.Application.Current.On<iOS>().SetHandleControlUpdatesOnMainThread(true);
El Application.On<iOS> método especifica que solo se ejecutarán este específicos de la plataforma de iOS. El
Application.SetHandleControlUpdatesOnMainThread método, en el Xamarin.Forms.PlatformConfiguration.iOSSpecific
espacio de nombres, se usa para controlar si el diseño del control y la representación de las actualizaciones se
realizan en el subproceso principal, en lugar de que se va a realizar en un subproceso en segundo plano. Además,
el Application.GetHandleControlUpdatesOnMainThread método puede utilizarse para devolver si el diseño de
controles y la representación de las actualizaciones se realizan en el subproceso principal.
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
iOSSpecific API
Separador de barra NavigationPage en iOS
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Este específicos de plataforma de iOS ocultan la línea de separación y la sombra que se encuentra en la parte
inferior de la barra de navegación en un NavigationPage . Se consume en XAML estableciendo el
NavigationPage.HideNavigationBarSeparator propiedad enlazable a false :
<NavigationPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
ios:NavigationPage.HideNavigationBarSeparator="true">
</NavigationPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
descargar el ejemplo
Este controles específicos de la plataforma si el texto de la barra de estado de color en un NavigationPage se ajusta
para que coincida con la luminosidad de la barra de navegación. Se consume en XAML estableciendo el
NavigationPage.StatusBarTextColorMode propiedad adjunta a un valor de la StatusBarTextColorMode enumeración:
<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>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
iOSSpecific API
NavigationPage barra translucidez en iOS
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Este específicos de plataforma de iOS se usan para cambiar la transparencia de la barra de navegación en un
NavigationPage y se consume en XAML estableciendo el NavigationPage.IsNavigationBarTranslucent propiedad
adjunta a un boolean valor:
<NavigationPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
BackgroundColor="Blue"
ios:NavigationPage.IsNavigationBarTranslucent="true">
...
</NavigationPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
(App.Current.MainPage as Xamarin.Forms.NavigationPage)
.On<iOS>()
.SetIsNavigationBarTranslucent(!(App.Current.MainPage as Xamarin.Forms.NavigationPage).On<iOS>
().IsNavigationBarTranslucent());
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
iOSSpecific API
Visibilidad de indicador principal de iOS
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Este específicos de plataforma de iOS establece la visibilidad del indicador principal de un Page . Se consume en
XAML estableciendo el Page.PrefersHomeIndicatorAutoHidden propiedad enlazable para un boolean :
<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
ios:Page.PrefersHomeIndicatorAutoHidden="true">
...
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
On<iOS>().SetPrefersHomeIndicatorAutoHidden(true);
NOTE
Este específicos de la plataforma se pueden aplicar a ContentPage , MasterDetailPage , NavigationPage ,y
TabbedPage objetos.
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
iOSSpecific API
Visibilidad de barra de estado de página en iOS
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Este específicos de plataforma de iOS se usan para establecer la visibilidad de la barra de estado en un Page , e
incluye la capacidad para controlar cómo la barra de estado entra o sale de la Page . Se consume en XAML
estableciendo el Page.PrefersStatusBarHidden propiedad adjunta a un valor de la StatusBarHiddenMode
enumeración y, opcionalmente, el Page.PreferredStatusBarUpdateAnimation propiedad adjunta a un valor de la
UIStatusBarAnimation enumeración:
<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
ios:Page.PrefersStatusBarHidden="True"
ios:Page.PreferredStatusBarUpdateAnimation="Fade">
...
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
On<iOS>().SetPrefersStatusBarHidden(StatusBarHiddenMode.True)
.SetPreferredStatusBarUpdateAnimation(UIStatusBarAnimation.Fade);
El Page.SetPreferredStatusBarUpdateAnimation método se usa para establecer cómo la barra de estado entra o sale
de la Page especificando uno de los UIStatusBarAnimation valores de enumeración: None , Fade , o Slide . Si el
Fade o Slide se especifica el valor de enumeración, 0.25 segunda animación se ejecuta como la barra de estado
entra o sale de la Page .
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
iOSSpecific API
Selector de selección de elementos en iOS
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Este iOS específicos de la plataforma controla cuándo se produce la selección de elementos en un Picker , lo
que permite al usuario especificar que la selección de elementos se produce al examinar los elementos del
control, o solo una vez que la realiza botón está presionado. Se consume en XAML estableciendo el
Picker.UpdateMode propiedad adjunta a un valor de la UpdateMode enumeración:
<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>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
picker.On<iOS>().SetUpdateMode(UpdateMode.WhenFinished);
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;
}
El resultado es que un determinado UpdateMode se aplica a la Picker , que controla cuándo se produce la
selección de elementos:
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
iOSSpecific API
Guía de diseño de área segura en iOS
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Se usan este específicos de plataforma de iOS para asegurarse de que el contenido de la página se coloca en un
área de la pantalla que es seguro para todos los dispositivos que usan iOS 11 y versiones posteriores. En concreto,
le ayudará a asegurarse de que el contenido no recortado por dispositivo esquinas redondeadas, el indicador
principal o el alojamiento del sensor en un iPhone X. Se consume en XAML estableciendo el Page.UseSafeArea
propiedad adjunta un 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>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
On<iOS>().SetUseSafeArea(true);
El área segura se puede personalizar mediante la recuperación de su Thickness valor con el Page.SafeAreaInsets
método desde el Xamarin.Forms.PlatformConfiguration.iOSSpecific espacio de nombres. A continuación, se puede
modificar como necesarios y volver a asignar a la Padding propiedad en el constructor de la página o
OnAppearing invalidar:
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
iOSSpecific API
ScrollView toques contenido en iOS
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Se desencadena un temporizador implícito cuando se inicia un movimiento táctil en un ScrollView en iOS y el
ScrollView decide, en función de la acción del usuario dentro del intervalo del temporizador, independientemente
de que se debe controlar el gesto o pasarlo a su contenido. De forma predeterminada, el archivo iOS ScrollView
toques contenido retrasos, pero esto puede causar problemas en algunas circunstancias con el ScrollView
contenido no ganando el gesto cuando debería. Por lo tanto, este controles específicos de la plataforma si un
ScrollView controla un movimiento táctil o pasa a su contenido. Se consume en XAML estableciendo el
ScrollView.ShouldDelayContentTouches propiedad adjunta un 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>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
scrollView.On<iOS>().SetShouldDelayContentTouches(false);
El ScrollView.On<iOS> método especifica que solo se ejecutarán este específicos de la plataforma de iOS. El
ScrollView.SetShouldDelayContentTouches método, en el Xamarin.Forms.PlatformConfiguration.iOSSpecific espacio
de nombres, se utiliza para controlar si un ScrollView controla un movimiento táctil o pasa a su contenido.
Además, el SetShouldDelayContentTouches método puede utilizarse para activar o desactivar retrasar toques
contenidos mediante una llamada a la ShouldDelayContentTouches método para devolver si se retrasan toques de
contenido:
scrollView.On<iOS>().SetShouldDelayContentTouches(!scrollView.On<iOS>().ShouldDelayContentTouches());
El resultado es que un ScrollView puede deshabilitar retrasar recibir contenidos toques, así que en este escenario
el Slider recibe el gesto en lugar de Detail página de la MasterDetailPage :
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
iOSSpecific API
Reconocimiento de gestos de movimiento
panorámico simultáneas en iOS
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Cuando un PanGestureRecognizer se adjunta a una vista dentro de una vista desplazable, todo el pan gestos
capturados por el PanGestureRecognizer y no se pasan a la vista de desplazamiento. Por lo tanto, ya no se
desplazará la vista de desplazamiento.
Este específicos de plataforma de iOS permite un PanGestureRecognizer en una vista desplazable para capturar y
compartir el movimiento panorámico con la vista de desplazamiento. Se consume en XAML estableciendo el
Application.PanGestureRecognizerShouldRecognizeSimultaneously propiedad adjunta true :
<Application ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
ios:Application.PanGestureRecognizerShouldRecognizeSimultaneously="true">
...
</Application>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
Xamarin.Forms.Application.Current.On<iOS>().SetPanGestureRecognizerShouldRecognizeSimultaneously(true);
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
iOSSpecific API
Control deslizante Thumb pulsar en iOS
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Este específicos de plataforma de iOS permite la Slider.Value propiedad debe establecerse si pulsa en una
posición en la Slider barra, en lugar de tener que arrastrar la Slider thumb. Se consume en XAML
estableciendo el Slider.UpdateOnTap propiedad enlazable a true :
<ContentPage ...
xmlns:ios="clr-
namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core">
<StackLayout ...>
<Slider ... ios:Slider.UpdateOnTap="true" />
...
</StackLayout>
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
iOSSpecific API
Desenfoque VisualElement en iOS
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Este específicos de plataforma de iOS se usa para difuminar el contenido en capas por debajo de ella y pueden
aplicarse a cualquier VisualElement . Se consume en XAML estableciendo el VisualElement.BlurEffect propiedad
adjunta a un valor de la BlurEffectStyle enumeración:
<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>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
boxView.On<iOS>().UseBlurEffect(BlurEffectStyle.ExtraLight);
El BoxView.On<iOS> método especifica que solo se ejecutarán este específicos de la plataforma de iOS. El
VisualElement.UseBlurEffect método, en el Xamarin.Forms.PlatformConfiguration.iOSSpecific espacio de nombres,
se usa para aplicar el efecto de desenfoque, con el BlurEffectStyle enumeración que proporciona cuatro valores:
None , ExtraLight , Light , y Dark .
El resultado es que un determinado BlurEffectStyle se aplica a la BoxView instancia que desenfoca la Image por
niveles por debajo de ella:
NOTE
Al agregar un efecto de desenfoque a una VisualElement , eventos de toque, todavía recibirán el VisualElement .
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
iOSSpecific API
VisualElement Drop sombras en iOS
11/07/2019 • 3 minutes to read • Edit Online
descargar el ejemplo
Este específicos de plataforma de iOS se utilizan para habilitar una sombra paralela en un VisualElement . Se
consume en XAML estableciendo el VisualElement.IsShadowEnabled propiedad adjunta true , junto con un
número de adicional opcional adjunta propiedades que controlan el efecto de sombra:
<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>
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);
NOTE
Se puede consultar el estado de una sombra paralela mediante una llamada a la GetIsShadowEnabled , GetShadowColor ,
GetShadowOffset , GetShadowOpacity , y GetShadowRadius métodos.
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
iOSSpecific API
Modo de Color VisualElement heredado en iOS
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Algunas de las vistas de Xamarin.Forms cuentan con un modo de color heredado. En este modo, cuando el
IsEnabled se establece la propiedad de la vista en false , la vista invalida los colores establecidos por el usuario
con los colores nativo predeterminado para el estado deshabilitado. Para hacia atrás compatibilidad, este modo
heredado de color permanece el comportamiento predeterminado para las vistas admitidas.
Esta plataforma iOS específicos deshabilita este modo heredado de color en un VisualElement , de modo que los
colores establecidos en una vista por el usuario permanezcan incluso cuando se deshabilita la vista. Se consume
en XAML estableciendo el VisualElement.IsLegacyColorModeEnabled propiedad adjunta 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>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
...
_legacyColorModeDisabledButton.On<iOS>().SetIsLegacyColorModeEnabled(false);
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
iOSSpecific API
Xamarin.Forms en proyectos nativos de Xamarin
17/07/2019 • 22 minutes to read • Edit Online
Descargar el ejemplo
Normalmente, una aplicación de Xamarin.Forms incluye una o más páginas que se derivan de ContentPage , y
estas páginas se comparten con todas las plataformas en un proyecto compartido o un proyecto de biblioteca de
.NET Standard. Sin embargo, permite formularios nativos ContentPage -derivada páginas agregarse directamente
a las aplicaciones de Xamarin.iOS, Xamarin.Android y UWP nativas. En comparación a tener el proyecto nativo
consumir ContentPage -derivadas páginas desde un proyecto de biblioteca estándar de .NET o un proyecto
compartido, la ventaja de agregar páginas directamente a proyectos nativos es que las páginas se pueden
extender con vistas nativas. A continuación, se pueden denominar vistas nativas en XAML con x:Name y que se
hace referencia desde el código subyacente. Para obtener más información acerca de vistas nativas, consulte vistas
nativas.
El proceso para consumir un Xamarin.Forms ContentPage -página derivada en un proyecto nativo es como sigue:
1. Agregue el paquete de Xamarin.Forms NuGet en el proyecto nativo.
2. Agregar el ContentPage -derivados de página y las dependencias, en el proyecto nativo.
3. Llame al método Forms.Init .
4. Construir una instancia de la ContentPage -página derivada y convertirlo al tipo nativo apropiado con uno de
los siguientes métodos de extensión: CreateViewController para iOS, CreateSupportFragment para Android, o
CreateFrameworkElement para UWP.
5. Vaya a la representación de tipo nativo de la ContentPage -mediante la API nativa barra de navegación de
página derivada.
Xamarin.Forms debe inicializarse llamando el Forms.Init método antes de que un proyecto nativo se puede
construir un ContentPage -página derivada. Elegir cuándo deben hacerlo principalmente depende cuando sea más
conveniente en el flujo de la aplicación: puede realizarse al iniciar la aplicación, o justo antes de la ContentPage -
página derivada se construye. En este artículo y las aplicaciones de ejemplo que lo acompaña, el Forms.Init se
llama al método al iniciarse la aplicación.
NOTE
El NativeForms solución de aplicación de ejemplo no contiene todos los proyectos de Xamarin.Forms. En su lugar, consta de
un proyecto de Xamarin.iOS, un proyecto de Xamarin.Android y un proyecto de UWP. Cada proyecto es un proyecto nativo
que usa formularios nativos para consumir ContentPage -derivados de las páginas. Sin embargo, no hay ningún motivo
por qué no podían consumir los proyectos nativos ContentPage -deriva de las páginas de un proyecto de biblioteca
estándar de .NET o un proyecto compartido.
iOS
En iOS, el FinishedLaunching invalidar en el AppDelegate clase suele ser el lugar para ejecutar la aplicación las
tareas relacionadas con el inicio. Se llama después de la aplicación ha lanzado y normalmente se reemplaza para
configurar la ventana principal y ver el controlador. El siguiente ejemplo de código muestra la AppDelegate clase
en la aplicación de ejemplo:
[Register("AppDelegate")]
public class AppDelegate : UIApplicationDelegate
{
public static string FolderPath { get; private set; }
UIWindow _window;
UINavigationController _navigation;
Instance = this;
_window = new UIWindow(UIScreen.MainScreen.Bounds);
UINavigationBar.Appearance.SetTitleTextAttributes(new UITextAttributes
{
TextColor = UIColor.Black
});
FolderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData));
UIViewController mainPage = new NotesPage().CreateViewController();
mainPage.Title = "Notes";
return true;
}
...
}
Una vez el FinishedLaunching ha ejecutado el método, definido por la interfaz de usuario en Xamarin.Forms
NotesPage clase se mostrará como se muestra en la captura de pantalla siguiente:
Interactuar con la interfaz de usuario, por ejemplo, al pulsar la + Button , dará como resultado el siguiente
controlador de eventos en el NotesPage ejecutando el código subyacente:
WARNING
El Popping de un UIViewController en la navegación nativo de iOS pila no eliminará automáticamente
UIViewController s. Es responsabilidad del programador asegurarse de que cualquier UIViewController que ya no se
necesita tiene su Dispose() llama al método, lo contrario, el UIViewController y adjunta Page quedarán huérfanos y
no se recopilarán por el recolector de elementos no utilizados lo que produce una pérdida de memoria.
Android
En Android, el OnCreate invalidar en el MainActivity clase suele ser el lugar para ejecutar la aplicación las tareas
relacionadas con el inicio. El siguiente ejemplo de código muestra la MainActivity clase en la aplicación de
ejemplo:
Forms.Init(this, bundle);
Instance = this;
SetContentView(Resource.Layout.Main);
var toolbar = FindViewById<Toolbar>(Resource.Id.toolbar);
SetSupportActionBar(toolbar);
SupportActionBar.Title = "Notes";
FolderPath =
Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData));
Android.Support.V4.App.Fragment mainPage = new NotesPage().CreateSupportFragment(this);
SupportFragmentManager
.BeginTransaction()
.Replace(Resource.Id.fragment_frame_layout, mainPage)
.Commit();
...
}
...
}
Cuando el NoteEntryPage se muestra, puntee en la parte posterior flecha se mostrará el mensaje el Fragment para
el NoteEntryPage desde la pila de retroceso del fragmento, devolver al usuario la Fragment para el NotesPage
clase.
Habilitar la compatibilidad con la navegación hacia atrás
El SupportFragmentManager clase tiene un BackStackChanged evento que se desencadena cada vez que cambia el
contenido de la pila de retroceso de fragmento. El OnCreate método en el MainActivity clase contiene un
controlador 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 ? "Note Entry" : "Notes";
};
Este controlador de eventos muestra un botón Atrás en la barra de acciones siempre que hay uno o más
Fragment instancias en el fragmento de la pila de retroceso. La respuesta al pulsar el botón Atrás se controla
mediante el OnOptionsItemSelected invalidar:
Elija un archivo
Al incrustar un ContentPage -derivados de la página que utiliza un WebView que necesita para compatibilidad con
HTML "Elegir el archivo" botón, el Activity será necesario invalidar el OnActivityResult método:
UWP
En UWP, nativo App clase suele ser el lugar para ejecutar la aplicación las tareas relacionadas con el inicio.
Xamarin.Forms es normalmente inicializado, en las aplicaciones de UWP de Xamarin.Forms, en el OnLaunched
invalidar en nativo App (clase), para pasar el LaunchActivatedEventArgs argumento para el Forms.Init método.
Por este motivo, las aplicaciones nativas de UWP que consumen un Xamarin.Forms ContentPage -más fácilmente
puede llamar page derivada el Forms.Init método desde el App.OnLaunched método.
De forma predeterminada, nativo App clase inicia la MainPage clase como la primera página de la aplicación. El
siguiente ejemplo de código muestra la MainPage clase en la aplicación de ejemplo:
public sealed partial class MainPage : Page
{
public static MainPage Instance;
public MainPage()
{
this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Enabled;
Instance = this;
FolderPath =
Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData));
this.Content = new Notes.UWP.Views.NotesPage().CreateFrameworkElement();
}
...
}
Una vez el MainPage ha ejecutado el constructor, definido por la interfaz de usuario en Xamarin.Forms NotesPage
clase se mostrará como se muestra en la captura de pantalla siguiente:
Interactuar con la interfaz de usuario, por ejemplo, al pulsar la + Button , dará como resultado el siguiente
controlador de eventos en el NotesPage ejecutando el código subyacente:
Navegación en UWP se suele realizar con la Frame.Navigate método, que toma un Page argumento.
Xamarin.Forms define una Frame.Navigate método de extensión que toma un ContentPage -derivados de la
instancia de la página. Por lo tanto, cuando el NavigateToNoteEntryPage método se ejecuta, la interfaz de usuario
definido en Xamarin.Forms NoteEntryPage se mostrará como se muestra en la captura de pantalla siguiente:
if (rootFrame == null)
{
...
// Place the frame in the current Window
Window.Current.Content = rootFrame;
SystemNavigationManager.GetForCurrentView().BackRequested += OnBackRequested;
}
...
}
El OnBackRequested llamadas del controlador de eventos el GoBack método en el marco de la raíz de la aplicación
y establece el BackRequestedEventArgs.Handled propiedad a true para marcar el evento como controlado. Error al
marcar el evento como controlado podría producir en el evento que se pasa por alto.
La aplicación decide si se deben mostrar un botón Atrás en la barra de título. Esto se consigue estableciendo la
AppViewBackButtonVisibility propiedad en uno de los AppViewBackButtonVisibility valores de enumeración:
Vínculos relacionados
NativeForms (ejemplo)
Vistas nativas
Vistas nativas en Xamarin.Forms
11/07/2019 • 2 minutes to read • Edit Online
Pueden hacer referencia directamente a vistas nativas de iOS, Android y la plataforma Universal de Windows
(UWP ) de Xamarin.Forms. Se pueden establecer las propiedades y los controladores de eventos en vistas nativas,
y pueden interactuar con las vistas de Xamarin.Forms.
Vistas nativas en C#
Vistas nativas de iOS, Android y UWP pueden hacer referencia directamente desde las páginas de
Xamarin.Forms creadas con C#.
Vínculos relacionados
Formularios nativos
Vistas nativas en XAML
11/07/2019 • 24 minutes to read • Edit Online
descargar el ejemplo
Vistas nativas de iOS, Android y la plataforma Universal de Windows pueden hacer referencia directamente desde
los archivos XAML de Xamarin.Forms. Se pueden establecer las propiedades y los controladores de eventos en
vistas nativas, y pueden interactuar con las vistas de Xamarin.Forms. En este artículo se muestra cómo consumir
vistas nativas en archivos XAML de Xamarin.Forms.
En este artículo se trata los temas siguientes:
Consumo de vistas nativas – el proceso para utilizar una vista en XAML nativa.
Uso de enlaces nativos : a y desde las propiedades de vistas nativas de enlace de datos.
Pasar argumentos a vistas nativas : pasar argumentos a los constructores de la vista nativa y llamar a vista
nativa de los métodos de fábrica.
Que hace referencia a vistas nativas desde código – recuperar instancias de vista nativa declarados en un
archivo XAML, el archivo de código subyacente.
Creación de subclases de vistas nativas : creación de subclases de vistas nativas para definir una API compatible
con XAML.
Información general
Para insertar una vista nativa a un archivo XAML de Xamarin.Forms:
1. Agregar un xmlns declaración de espacio de nombres en el archivo XAML para el espacio de nombres que
contiene la vista nativa.
2. Cree una instancia de la vista nativa en el archivo XAML.
IMPORTANT
XAML compilado debe deshabilitarse para todas las páginas XAML que utilice vistas nativas. Esto puede realizarse mediante
la decoración de la clase de código subyacente para la página XAML con el
[XamlCompilation(XamlCompilationOptions.Skip)] atributo. Para obtener más información sobre la compilación de
XAML, vea compilación XAML en Xamarin.Forms.
Para hacer referencia a una vista nativa desde un archivo de código subyacente, debe usar un proyecto de activos
compartidos (SAP ) y ajustar el código específico de plataforma con directivas de compilación condicional. Para
obtener más información, consulte que hace referencia a vistas nativas desde código.
Así como especificar el clr-namespace y assembly para un espacio de nombres de vista nativo, un targetPlatform
también debe especificarse. Esto se debe establecer en uno de los valores de la TargetPlatform enumeración y
normalmente se establecerá en iOS , Android , o Windows . En tiempo de ejecución, el analizador XAML pasará por
alto los prefijos de espacios de nombres XML que tienen un targetPlatform que no coincide con la plataforma en
la que se ejecuta la aplicación.
Cada declaración de espacio de nombres puede utilizarse para hacer referencia a cualquier clase o estructura del
espacio de nombres especificado. Por ejemplo, el ios declaración de espacio de nombres se puede usar para
hacer referencia a cualquier clase o estructura desde iOS UIKit espacio de nombres. Se pueden establecer
propiedades de la vista nativa a través de XAML, pero deben coincidir con los tipos de propiedad y objeto. Por
ejemplo, el UILabel.TextColor propiedad está establecida en UIColor.Red utilizando el x:Static extensión de
marcado y el ios espacio de nombres.
Propiedades enlazables y adjuntadas propiedades enlazables también pueden establecerse en vistas nativas
mediante el uso de la Class.BindableProperty="value" sintaxis. Cada vista nativa se encapsula en una plataforma
específica NativeViewWrapper instancia, que se deriva de la Xamarin.Forms.View clase. Establecer una propiedad
enlazable o una propiedad enlazable adjunta en una vista nativa, el valor de propiedad transfiere al contenedor. Por
ejemplo, se puede especificar un diseño centrado horizontal estableciendo View.HorizontalOptions="Center" en la
vista nativa.
NOTE
Tenga en cuenta que los estilos no se puede usar con vistas nativas, porque los estilos solo pueden tener como destino las
propiedades que están respaldadas por BindableProperty objetos.
Constructores de widget Android requieren generalmente el Android Context objeto como un argumento y esto
es posible acceder a través de una propiedad estática en el MainActivity clase. Por lo tanto, al crear un widget de
Android en XAML, el Context objeto normalmente se debe pasar al constructor del widget mediante el
x:Arguments atributo con un x:Static extensión de marcado. Para obtener más información, consulte pasar
argumentos a vistas nativas.
NOTE
Tenga en cuenta que una vista nativa con nombres x:Name no es posible en un proyecto de biblioteca estándar de .NET o
un proyecto de activos compartidos (SAP). Si lo hace, se generará una variable del tipo nativo, lo que provocará un error de
compilación. Sin embargo, las vistas nativas pueden envolverse en ContentView instancias y recuperarse en el archivo de
código subyacente, siempre que se utilice un SAP. Para obtener más información, consulte Referencia a una vista nativa
desde el código.
Enlaces nativos
Enlace de datos se utiliza para sincronizar una interfaz de usuario con su origen de datos y simplifica la forma en
que una aplicación de Xamarin.Forms muestra e interactúa con sus datos. Siempre que el objeto fuente
implemente la interfaz INotifyPropertyChanged , los cambios en el objeto fuente se envían automáticamente al
objeto objetivo por el marco vinculante, y los cambios en el objeto objetivo opcionalmente se pueden enviar al
objeto fuente.
Las propiedades de las vistas nativas también pueden usar el enlace de datos. El siguiente ejemplo de código
demuestra el enlace de datos usando propiedades de vistas 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>
Las capturas de pantalla siguientes muestran el resultado de especificar los argumentos de método y constructor
del generador para establecer la fuente en diferentes vistas nativas:
Para obtener más información sobre cómo pasar argumentos en XAML, vea pasar argumentos en XAML.
A continuación, se pueden invocar las API nativas en la vista nativa para realizar las operaciones deseadas. Este
enfoque también ofrece la ventaja que varias vistas XAML nativas para diferentes plataformas pueden ser
elementos secundarios del mismo ContentView . En el ejemplo de código siguiente se muestra esta 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>
En el ejemplo anterior, las vistas nativas para cada plataforma son elementos secundarios de ContentView
controles, con el x:Name valor del atributo que se usa para recuperar el ContentView en el código subyacente:
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
}
El ContentView.Content acceso a la propiedad para recuperar la vista ajustada nativa como una plataforma
específica NativeViewWrapper instancia. El NativeViewWrapper.NativeElement , a continuación, se obtiene acceso de
propiedad para recuperar la vista nativa como tipo nativo. A continuación, se invoca la API nativa de la vista para
llevar a cabo las operaciones deseadas.
IOS y Android botones nativos comparten el mismo OnButtonTap controlador de eventos, porque cada botón
nativo consume un EventHandler delegar en respuesta a un evento de toque. Sin embargo, la plataforma
Universal de Windows (UWP ) usa un independiente RoutedEventHandler , que a su vez los consume el
OnButtonTap controlador de eventos en este ejemplo. Por lo tanto, cuando un botón nativo se hace clic en, el
OnButtonTap ejecuta el controlador de eventos, que se escala y gira el control nativo dentro de la ContentView
denominado contentViewTextParent . Las capturas de pantalla siguientes muestran este que se producen en cada
plataforma:
Creación de subclases de vistas nativas
Muchos iOS y Android vistas nativas no son adecuadas para crear instancias en XAML porque usan métodos, en
lugar de propiedades, para configurar el control. Vistas nativas de subclase de contenedores que definen una API
compatible con XAML más que usa las propiedades para el control de la instalación, y que usa eventos
independientes de la plataforma es la solución a este problema. El ajustada nativas vistas pueden, a continuación,
se coloca en un proyecto de activos compartidos (SAP ) y rodeadas con directivas de compilación condicional, o
colocar en los proyectos específicos de la plataforma y de XAML al que hace referencia en un proyecto de
biblioteca de .NET Standard.
En el ejemplo de código siguiente se muestra una página de Xamarin.Forms que consume una subclase de vistas
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>
La página contiene un Label que muestra la fruta elegida por el usuario en un control nativo. El Label enlaza a la
SubclassedNativeControlsPageViewModel.SelectedFruit propiedad. El BindingContext de la página se establece en
una nueva instancia de la SubclassedNativeControlsPageViewModel clase en el archivo de código subyacente, con la
clase ViewModel que implementa el INotifyPropertyChanged interfaz.
La página también contiene una vista de selector nativo para cada plataforma. Cada vista nativa muestra la
colección de frutas enlazando su ItemSource propiedad a la SubclassedNativeControlsPageViewModel.Fruits
colección. Esto permite al usuario elegir una frutas, como se muestra en las capturas de pantalla siguiente:
En iOS y Android los selectores nativos usar métodos para configurar los controles. Por lo tanto, deben ser una
subclase estos selectores para exponer propiedades para que sean compatible con XAML. En la plataforma
Universal de Windows (UWP ), el ComboBox ya es compatible con XAML y, por lo que no requiere la creación de
subclases.
iOS
Las subclases de la implementación de iOS la UIPickerView vista y expone propiedades y un evento que se puede
consumir fácilmente desde 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;
}
Android
Las subclases de implementación para Android el Spinner vista y expone propiedades y un evento que se puede
consumir fácilmente desde XAML:
class MySpinner : Spinner
{
ArrayAdapter adapter;
IList<string> items;
El MySpinner clase expone ItemsSource y SelectedObject propiedades y un ItemSelected eventos. Los elementos
mostrados por la MySpinner proporcionados clase por el Adapter asociado a la vista y los elementos se rellenan
en el Adapter cuando el ItemsSource propiedad se establece en primer lugar. Cada vez que el elemento
seleccionado en el MySpinner clase cambios, el OnBindableSpinnerItemSelected actualizaciones del controlador de
eventos el SelectedObject propiedad.
Resumen
En este artículo se muestra cómo consumir vistas nativas en archivos XAML de Xamarin.Forms. Se pueden
establecer las propiedades y los controladores de eventos en vistas nativas, y pueden interactuar con las vistas de
Xamarin.Forms.
Vínculos relacionados
NativeSwitch (ejemplo)
Forms2Native (ejemplo)
NativeViewInsideContentView (sample)
SubclassedNativeControls (ejemplo)
Formularios nativos
Pasar argumentos en XAML
Vistas nativas en C#
11/07/2019 • 12 minutes to read • Edit Online
descargar el ejemplo
Vistas nativas de iOS, Android y UWP pueden hacer referencia directamente desde las páginas de Xamarin.Forms
creadas con C#. En este artículo se muestra cómo agregar vistas nativas a un diseño de Xamarin.Forms creado con
C# y cómo reemplazar el diseño de vistas personalizadas para corregir su uso de la API de medición.
Información general
Cualquier control de Xamarin.Forms que permita Content debe establecerse, o que tenga un Children colección,
puede agregar vistas específicas de plataforma. Por ejemplo, un iOS UILabel pueden agregarse directamente a la
ContentView.Content propiedad, o a la StackLayout.Children colección. Sin embargo, tenga en cuenta que esta
funcionalidad requiere el uso de #if define en las soluciones de proyecto de Xamarin.Forms compartido y no
está disponible desde soluciones de la biblioteca estándar de .NET de Xamarin.Forms.
Las capturas de pantalla siguientes muestran específicos de la plataforma, las vistas que se han agregado a un
objeto Xamarin.Forms StackLayout :
La capacidad de agregar vistas específicas de plataforma a un diseño de Xamarin.Forms se habilita mediante dos
métodos de extensión en cada plataforma:
Add : agrega una vista específica de la plataforma para la Children colección de un diseño.
ToView : toma una vista específica de la plataforma y lo encapsula como un objeto Xamarin.Forms View que
se pueden establecer como el Content propiedad de un control.
Mediante estos métodos en un proyecto compartido Xamarin.Forms, es necesario importar el espacio de nombres
de Xamarin.Forms específicos de la plataforma adecuada:
iOS – Xamarin.Forms.Platform.iOS
Android – Xamarin.Forms.Platform.Android
Plataforma universal de Windows (UWP ) – Xamarin.Forms.Platform.UWP
El ejemplo supone que el stackLayout y contentView instancias se han creado previamente en XAML o C#.
Android
En el ejemplo de código siguiente se muestra cómo agregar un TextView a un StackLayout y un ContentView :
El ejemplo supone que el stackLayout y contentView instancias se han creado previamente en XAML o C#.
Plataforma universal de Windows
En el ejemplo de código siguiente se muestra cómo agregar un TextBlock a un StackLayout y un ContentView :
El ejemplo supone que el stackLayout y contentView instancias se han creado previamente en XAML o C#.
Una instancia de esta vista se agrega a un StackLayout , tal y como se muestra en el ejemplo de código siguiente:
Sin embargo, dado que el CustomControl.SizeThatFits invalidación siempre devuelve un valor de 150 de alto, se
mostrará la vista con un espacio vacío por encima y debajo de él, como se muestra en la siguiente captura de
pantalla:
if (uiView == null) {
return null;
}
Este método utiliza el ancho proporcionado por el CustomControl.SizeThatFits método, pero sustituye la altura de
150 por una altura de 70. Cuando el CustomControl instancia se agrega a la StackLayout , el FixSize método se
puede especificar como el GetDesiredSizeDelegate para corregir la medida incorrecta proporcionada por el
CustomControl clase:
El resultado en la vista personalizada que se muestra correctamente, sin espacio en blanco por encima y debajo de
él, como se muestra en la captura de pantalla siguiente:
Android
El siguiente ejemplo de código muestra la CustomControl (clase), que hereda de TextView :
Sin embargo, dado que el CustomControl.OnMeasure invalidación siempre devuelve la mitad del ancho solicitado, la
vista se mostrarán ocupando sólo la mitad el ancho disponible del dispositivo, como se muestra en la captura de
pantalla siguiente:
Este método utiliza el ancho proporcionado por el CustomControl.OnMeasure método, pero la multiplica por dos.
Cuando el CustomControl instancia se agrega a la StackLayout , el FixSize método se puede especificar como el
GetDesiredSizeDelegate para corregir la medida incorrecta proporcionada por el CustomControl clase:
Esto da como resultado la vista personalizada se muestra correctamente, ocupan el ancho del dispositivo, como se
muestra en la captura de pantalla siguiente:
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);
}
Una instancia de esta vista se agrega a un StackLayout , tal y como se muestra en el ejemplo de código siguiente:
Sin embargo, dado que el CustomControl.ArrangeOverride invalidación siempre devuelve la mitad del ancho
solicitado, se recortará la vista a la mitad el ancho disponible del dispositivo, como se muestra en la captura de
pantalla siguiente:
Una solución a este problema consiste en proporcionar un ArrangeOverrideDelegate implementación, al agregar la
vista para la StackLayout , tal y como se muestra en el ejemplo de código siguiente:
Este método utiliza el ancho proporcionado por el CustomControl.ArrangeOverride método, pero la multiplica por
dos. Esto da como resultado la vista personalizada se muestra correctamente, ocupan el ancho del dispositivo,
como se muestra en la captura de pantalla siguiente:
Resumen
En este artículo se explica cómo agregar vistas nativas a un diseño de Xamarin.Forms creado con C# y cómo
reemplazar el diseño de vistas personalizadas para corregir su uso de la API de medición.
Vínculos relacionados
NativeEmbedding (ejemplo)
Formularios nativos
Otras plataformas de Xamarin.Forms
11/07/2019 • 2 minutes to read • Edit Online
Xamarin.Forms es compatible con plataformas adicionales más allá de iOS, Android y Windows.
GTK
Xamarin.Forms tiene ahora soporte técnico de vista previa para aplicaciones de GTK #.
Mac
Xamarin.Forms tiene ahora la compatibilidad de versión preliminar para las aplicaciones de Mac OS.
Tizen
Tizen .NET permite crear aplicaciones .NET con Xamarin.Forms y Tizen .NET Framework.
WPF
Xamarin.Forms tiene ahora soporte técnico de vista previa para aplicaciones de Windows Presentation Foundation
(WPF ).
Configuración de la plataforma GTK #
11/07/2019 • 10 minutes to read • Edit Online
Xamarin.Forms tiene ahora soporte técnico de vista previa para aplicaciones de GTK #. GTK # es un Kit de
herramientas de interfaz gráfica de usuario que vincula el Kit de herramientas GTK + y de diversas bibliotecas
GNOME, lo que permite el desarrollo de GNOME totalmente nativa con aplicaciones de gráficos con Mono y.
NET. En este artículo se muestra cómo agregar un proyecto de GTK # a una solución de Xamarin.Forms.
Antes de empezar, cree una nueva solución de Xamarin.Forms o usar una solución de Xamarin.Forms existente,
por ejemplo, GameOfLife.
NOTE
Aunque en este artículo se centra en Agregar una aplicación de GTK # a una solución de Xamarin.Forms en VS2017 y Visual
Studio para Mac, también se puede realizar en MonoDevelop para Linux.
namespace GameOfLife.GTK
{
class MainClass
{
[STAThread]
public static void Main(string[] args)
{
Gtk.Application.Init();
Forms.Init();
Gtk.Application.Run();
}
}
}
Este código inicializa GTK # y Xamarin.Forms, crea una ventana de aplicación y ejecuta la aplicación.
11. En el el Explorador de soluciones, a la derecha, haga clic en el proyecto GTK y seleccione propiedades.
12. En el propiedades ventana, seleccione el aplicación pestaña y cambie el tipo de salida lista desplegable
para aplicación Windows.
13. En el el Explorador de soluciones, haga clic en el proyecto GTK y seleccione establecer como proyecto
de inicio. Presione F5 para ejecutar el programa con el depurador de Visual Studio en el escritorio de
Windows:
Pasos siguientes
Funcionalidad específica de plataforma
Puede determinar qué plataforma se está ejecutando en la aplicación de Xamarin.Forms en XAML o código. Esto
le permite cambiar las características del programa cuando se ejecuta en GTK #. En el código, compare el valor de
Device.RuntimePlatform con el Device.GTK constante (que es igual a la cadena "GTK"). Si hay una coincidencia, la
aplicación se ejecuta en GTK #.
En XAML, puede usar el OnPlatform para seleccionar un valor de propiedad específico de la 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>
Icono de aplicación
Puede establecer el icono de la aplicación en el inicio:
window.SetApplicationIcon("icon.png");
Temas
Hay una amplia variedad de temas disponibles para GTK #, y se pueden usar desde una aplicación de
Xamarin.Forms:
GtkThemes.Init ();
GtkThemes.LoadCustomTheme ("Themes/gtkrc");
Formularios nativos
Formularios nativos permite Xamarin.Forms ContentPage -derivados de las páginas que será consumido por los
proyectos nativos, incluidos los proyectos de GTK #. Esto puede realizarse mediante la creación de una instancia de
la ContentPage -derivados de página y convertirlo en el nativo GTK # tipo usando el CreateContainer método de
extensión:
Para obtener más información acerca de los formularios nativos, vea formularios nativos.
Problemas
Se trata de una vista previa, por lo que debe esperar que no todo está lista para producción. Para el estado actual
de la implementación, consulte estado y para los problemas conocidos actuales, consulte problemas conocidos y
pendientes.
Configuración de la plataforma Mac
11/07/2019 • 5 minutes to read • Edit Online
Antes de empezar, cree (o usar una existente) proyecto de Xamarin.Forms. Solo puede agregar aplicaciones de
Mac con Visual Studio para Mac.
5. En el proyecto de Mac, haga doble clic en paquetes > Agregar paquetes... para agregar la Xamarin.Forms
NuGet. También debe actualizar los otros proyectos para usar la misma versión del paquete Xamarin.Forms
NuGet.
6. En el proyecto de Mac, haga doble clic en referencias y agregue una referencia al proyecto de
Xamarin.Forms (proyecto de biblioteca de proyecto compartido o .NET Standard).
8. Actualización AppDelegate para inicializar Xamarin.Forms, crear una ventana y cargar la aplicación de
Xamarin.Forms (sin olvidarse de definir un adecuado Title ). Si tiene otras dependencias que deben
inicializarse, hacerlo aquí también.
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;
Puede editar el sistema de menú en el guión gráfico para quitar elementos no deseados.
10. Por último, agregue cualquier recurso local (p ej. archivos de imagen) de los proyectos existentes de
plataforma que son necesarios.
11. El proyecto de Mac ahora debe ejecutar el código de Xamarin.Forms en macOS.
Pasos siguientes
Aplicación de estilos
Con los cambios recientes realizados en OnPlatform ahora puede definir cualquier número de plataformas. Esto
incluye 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>
Tenga en cuenta también es posible que duplica en plataformas como esta: <On Platform="iOS, macOS" ...> .
Posición y tamaño de ventana
Puede ajustar el tamaño inicial y la ubicación de la ventana en la AppDelegate :
Problemas conocidos
Se trata de una vista previa, por lo que debe esperar que no todo está lista para producción. A continuación se
muestran algunas cosas que puede encontrarse con que agregue macOS a los proyectos:
No todos los paquetes de NuGet están listos para macOS
Es posible que algunas de las bibliotecas que usa aún no admite macOS. En este caso, deberá enviar una solicitud
al mantenedor del proyecto para agregarlo. Hasta que tengan soporte técnico, deberá buscar otras alternativas.
Características de Xamarin.Forms que faltan
No todas las características de Xamarin.Forms son completadas en esta versión preliminar. Para obtener más
información, consulte compatibilidad con la plataforma macOS estado en el Xamarin.Forms repositorio de
GitHub.
Vínculos relacionados
Xamarin.Mac
Tizen .NET
11/07/2019 • 2 minutes to read • Edit Online
Tizen .NET le permite desarrollar aplicaciones de Tizen para ejecutarse en dispositivos de Samsung, incluidos los
televisores, ponibles, dispositivos móviles y otros dispositivos de IoT.
Tizen .NET le permite crear aplicaciones .NET con Xamarin.Forms y Tizen .NET framework. Xamarin.Forms le
permite crear fácilmente interfaces de usuario, mientras que la API TizenFX proporciona interfaces para el
hardware que se encuentra en TV moderna, móvil, ponible y dispositivos IoT. Para obtener más información
acerca de .NET Tizen, consulte Introducción a la aplicación de .NET Tizen.
Primeros pasos
Antes de empezar a desarrollar aplicaciones .NET Tizen, primero debe configurar el entorno de desarrollo. Para
obtener más información, consulte instalar Visual Studio Tools para Tizen.
Para obtener información sobre cómo agregar proyecto Tizen .NET a una solución existente de Xamarin.Forms,
consulte crear su primera aplicación .NET de Tizen.
Documentación
Documentación de Xamarin.Forms – cómo compilar aplicaciones multiplataforma con C# y Xamarin.Forms.
Developer.tizen.org – documentación y los vídeos que le ayudarán a crear e implementar aplicaciones Tizen.
Muestras
Samsung mantiene una bifurcación de la ejemplos de Xamarin.Forms con proyectos Tizen agregados, y hay un
repositorio independiente Tizen-Csharp-Samples que contiene proyectos adicionales, incluido el ponible y
Demostraciones específicas de TV.
Configuración de la plataforma WPF
11/07/2019 • 6 minutes to read • Edit Online
Xamarin.Forms tiene ahora la compatibilidad de versión preliminar de Windows Presentation Foundation (WPF ).
En este artículo se muestra cómo agregar un proyecto de WPF a una solución de Xamarin.Forms.
Antes de empezar, cree una nueva solución de Xamarin.Forms en Visual Studio de 2019 o usar una solución de
Xamarin.Forms existente, por ejemplo, BoxViewClock. Las aplicaciones de WPF solo se pueden agregar a una
solución de Xamarin.Forms en Windows.
8. Editar el MainWindow.xaml archivo del proyecto WPF. En el Window etiqueta, agregue una declaración
de espacio de nombres XML para el Xamarin.Forms.Platform.WPF ensamblado y espacio de nombres:
xmlns:wpf="clr-namespace:Xamarin.Forms.Platform.WPF;assembly=Xamarin.Forms.Platform.WPF"
<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 el MainWindow.xaml.cs archivo del proyecto WPF. Agregue dos nuevos using directivas:
using Xamarin.Forms;
using Xamarin.Forms.Platform.WPF;
Forms.Init();
LoadApplication(new BoxViewClock.App());
Excepto en los comentarios y sin usar using directivas, completo MainWindows.xaml.cs archivo debería
tener este aspecto:
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. Haga clic en el proyecto WPF en el el Explorador de soluciones y seleccione establecer como proyecto
de inicio. Presione F5 para ejecutar el programa con el depurador de Visual Studio en el escritorio de
Windows:
Pasos siguientes
Funcionalidad específica de plataforma
Puede determinar qué plataforma se está ejecutando en la aplicación de Xamarin.Forms mediante código o XAML.
Esto le permite cambiar las características del programa cuando se ejecuta en WPF. En el código, compare el valor
de Device.RuntimePlatform con el Device.WPF constante (que es igual a la cadena "WPF"). Si hay una coincidencia,
la aplicación se ejecuta en WPF.
En XAML, puede usar el OnPlatform para seleccionar un valor de propiedad específico de la 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>
Tamaño de ventana
Puede ajustar el tamaño inicial de la ventana de WPF MainWindow.xaml archivo:
Problemas
Se trata de una vista previa, por lo que debe esperar que no todo está lista para producción. No todos los paquetes
de NuGet para Xamarin.Forms están listos para WPF, y algunas características no ser totalmente operativo.
Funcionalidades específicas de plataforma
11/07/2019 • 11 minutes to read • Edit Online
descargar el ejemplo
Funcionalidades específicas de plataforma permiten utilizar la funcionalidad que solo está disponible en una
plataforma concreta, sin necesidad de implementar los representadores personalizados o los efectos.
El proceso para consumir una plataforma específica a través de XAML, o a través de la API fluida de código es
como sigue:
1. Agregar un xmlns declaración o using la directiva para el Xamarin.Forms.PlatformConfiguration espacio de
nombres.
2. Agregar un xmlns declaración o using la directiva para el espacio de nombres que contiene la funcionalidad
específica de la plataforma:
a. En iOS, se trata la Xamarin.Forms.PlatformConfiguration.iOSSpecific espacio de nombres.
b. En Android, se trata la Xamarin.Forms.PlatformConfiguration.AndroidSpecific espacio de nombres. Para
Android AppCompat, este es el Xamarin.Forms.PlatformConfiguration.AndroidSpecific.AppCompat espacio
de nombres.
c. En la plataforma Universal de Windows, se trata la Xamarin.Forms.PlatformConfiguration.WindowsSpecific
espacio de nombres.
3. Aplicar el específico de la plataforma de XAML, o de código con el On<T> API fluida. El valor de T puede ser el
iOS , Android , o Windows tipos a partir de la Xamarin.Forms.PlatformConfiguration espacio de nombres.
NOTE
Tenga en cuenta que intenta consumir un específico de la plataforma en una plataforma que no está disponible no dará
como resultado un error. En su lugar, el código se ejecutará sin el específico de la plataforma que se va a aplicar.
Funcionalidades específicas de plataforma consumen a través de la On<T> devueltos de la API de código fluent
IPlatformElementConfiguration objetos. Esto permite que varias funcionalidades específicas de plataforma que se
invocará en el mismo objeto con el método en cascada.
Para obtener más información sobre las características de plataforma proporciona Xamarin.Forms, consulte
funcionalidades específicas de plataforma de iOS, funcionalidades específicas de plataforma Android, y Windows
funcionalidades específicas de plataforma.
NOTE
Se prevé que los proveedores usará esta técnica para crear sus propias funcionalidades específicas de plataforma, para facilitar
su consumo por usuarios. Mientras que los usuarios pueden elegir crear sus propias funcionalidades específicas de
plataforma, se debe tener en cuenta que requiere más código que la creación y consumo de un efecto.
El aplicación de ejemplo muestra un Shadow específicos de la plataforma que se agrega una sombra al texto
mostrado por un Label control:
El aplicación de ejemplo implementa el Shadow específico de la plataforma en cada plataforma, para facilitar la
comprensión. Sin embargo, aparte de cada implementación de efecto específico de la plataforma, la
implementación de la clase de la sombra es idéntica en gran medida para cada plataforma. Por lo tanto, esta guía
se centra en la implementación de la clase de instantáneas y el efecto asociado en una sola plataforma.
Para obtener más información acerca de los efectos, vea personalización de controles con efectos.
Creación de una clase específica de la plataforma
Se crea una plataforma específica como un public static clase:
namespace MyCompany.Forms.PlatformConfiguration.iOS
{
public static Shadow
{
...
}
}
Las secciones siguientes describen la implementación de la Shadow efecto específico de la plataforma y asociado.
Agregar una propiedad adjunta
Una propiedad adjunta debe agregarse a la Shadow específicos de la plataforma para permitir el consumo a través
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";
...
El IsShadowed propiedad adjunta se utiliza para agregar el MyCompany.LabelShadowEffect efecto y lo eliminará del
control que el Shadow clase se adjunta a. Esto adjunta la propiedad registra el OnIsShadowedPropertyChanged
método que se ejecutará cuando cambia el valor de la propiedad. A su vez, llama este método la AttachEffect o
DetachEffect método para agregar o quitar el efecto en función del valor de la IsShadowed propiedad adjunta. El
efecto se agrega o quita el control modificando el control Effects colección.
NOTE
Tenga en cuenta que el efecto se resuelve mediante la especificación de un valor que es una concatenación del nombre del
grupo de resolución y el identificador único que se especifica en la implementación del efecto. Para obtener más información,
consulte crea un efecto.
Para obtener más información sobre las propiedades adjuntas, consulte Attached Properties.
Adición de métodos de extensión
Métodos de extensión deben agregarse a la Shadow específicos de la plataforma para permitir el consumo a través
de una API fluida de código:
namespace MyCompany.Forms.PlatformConfiguration.iOS
{
using System.Linq;
using Xamarin.Forms;
using Xamarin.Forms.PlatformConfiguration;
using FormsElement = Xamarin.Forms.Label;
El IsShadowed y SetIsShadowed invocar la operación get de métodos de extensión y establecer los descriptores de
acceso para el IsShadowed propiedad adjunta, respectivamente. Cada método de extensión funciona en el
IPlatformElementConfiguration<iOS, FormsElement> type que especifica que se puede invocar el específico de la
plataforma en Label instancias de iOS.
Creación del efecto
El Shadow específicos de la plataforma agrega el MyCompany.LabelShadowEffect a un Label y lo quita. El siguiente
ejemplo de código muestra la LabelShadowEffect implementación para el proyecto de iOS:
[assembly: ResolutionGroupName("MyCompany")]
[assembly: ExportEffect(typeof(LabelShadowEffect), "LabelShadowEffect")]
namespace ShadowPlatformSpecific.iOS
{
public class LabelShadowEffect : PlatformEffect
{
protected override void OnAttached()
{
UpdateShadow();
}
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);
}
}
}
}
El UpdateShadow método establece Control.Layer propiedades para crear la sombra, siempre que el IsShadowed
se establece la propiedad adjunta en true y siempre que el Shadow específico de la plataforma que se haya
invocado en la misma plataforma que el Efecto se implementa. Esta comprobación se realiza con el
OnThisPlatform método.
using Xamarin.Forms.PlatformConfiguration;
using MyCompany.Forms.PlatformConfiguration.iOS;
...
shadowLabel.On<iOS>().SetIsShadowed(true);
Vínculos relacionados
PlatformSpecifics (ejemplo)
ShadowPlatformSpecific (ejemplo)
funcionalidades específicas de plataforma de iOS
Funcionalidades específicas de plataforma Android
Funcionalidades específicas de plataforma de Windows
Personalización de controles con efectos
Propiedades asociadas
PlatformConfiguration API
Características de la plataforma Windows
11/07/2019 • 4 minutes to read • Edit Online
Desarrollar aplicaciones de Xamarin.Forms para plataformas de Windows requiere Visual Studio. El página
requisitos contiene más información sobre los requisitos previos.
NOTE
Compatibilidad de Xamarin.Forms 1.x y 2.x Windows Phone 8 Silverlight, Windows Phone 8.1, y Windows 8.1 desarrollo de
aplicaciones. Sin embargo, estos tipos de proyecto han quedado desusados.
Introducción
Vaya a archivo > Nuevo > proyecto en Visual Studio y elija uno de los multiplataforma > aplicación vacía
(Xamarin.Forms) plantillas para comenzar.
Las soluciones de Xamarin.Forms anteriores o los creados en macOS, no tendrá todos los proyectos de Windows
enumerados anteriormente (pero deben agregarse manualmente). Si desea tener como destino la plataforma de
Windows no está en la solución, viste el instrucciones de instalación para agregar el deseado de Windows/s de
tipo de proyecto.
Muestras
Todos los ejemplos de libro de Charles Creating Mobile Apps with Xamarin.Forms se incluyen los proyectos de
plataforma Universal de Windows (para Windows 10).
El "Scott Hanselman" aplicación de demostración está disponible por separado y también incluye proyectos de
Apple Watch y Android Wear (con Xamarin.iOS y Xamarin.Android, respectivamente, Xamarin.Forms no se
ejecuta en estas plataformas).
Vínculos relacionados
Proyectos de instalación de Windows
Orden de lectura de InputView en Windows
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Esta plataforma Universal de Windows específicos de la plataforma permite que el orden de lectura (de izquierda a
derecha o de derecha a izquierda) de texto bidireccional en Entry , Editor y Label instancias que se ha
detectado dinámicamente. Se consume en XAML estableciendo el InputView.DetectReadingOrderFromContent (para
Entry y Editor instancias) o Label.DetectReadingOrderFromContent propiedad adjunta un boolean valor:
<ContentPage ...
xmlns:windows="clr-
namespace:Xamarin.Forms.PlatformConfiguration.WindowsSpecific;assembly=Xamarin.Forms.Core">
<StackLayout>
<Editor ... windows:InputView.DetectReadingOrderFromContent="true" />
...
</StackLayout>
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;
...
editor.On<Windows>().SetDetectReadingOrderFromContent(true);
El Editor.On<Windows> método especifica que solo se ejecutan este específicos de la plataforma en la plataforma
Universal de Windows. El InputView.SetDetectReadingOrderFromContent método, en el
Xamarin.Forms.PlatformConfiguration.WindowsSpecific espacio de nombres, se usa para controlar si se detecta el
orden de lectura del contenido en el InputView . Además, el InputView.SetDetectReadingOrderFromContent método
puede utilizarse para alternar si se detecta el orden de lectura del contenido mediante una llamada a la
InputView.GetDetectReadingOrderFromContent método para devolver el valor actual:
editor.On<Windows>().SetDetectReadingOrderFromContent(!editor.On<Windows>
().GetDetectReadingOrderFromContent());
El resultado es que Entry , Editor ,y Label instancias pueden tener el orden de lectura de su contenido
dinámicamente detectado:
NOTE
A diferencia de la configuración de la FlowDirection propiedad, la lógica para las vistas que detectar el orden de lectura de
su contenido de texto no afectará a la alineación del texto dentro de la vista. En su lugar, ajusta el orden en el que se colocan
los bloques de texto bidireccional.
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
WindowsSpecific API
ListView SelectionMode en Windows
11/07/2019 • 3 minutes to read • Edit Online
descargar el ejemplo
En la plataforma Universal de Windows, de forma predeterminada el Xamarin.Forms ListView usa nativo
ItemClick eventos para responder a interacción, en lugar de nativo Tapped eventos. Esto proporciona la
funcionalidad de accesibilidad para que el Narrador de Windows y el teclado pueden interactuar con el ListView .
Sin embargo, también presenta los gestos de tap dentro de la ListView no funciona.
Este controles específicos de la plataforma de plataforma Universal de Windows si los elementos de un ListView
pulse gestos, puede responder y, por tanto, si nativo ListView se activa el ItemClick o Tapped eventos. Se
consume en XAML estableciendo el ListView.SelectionMode propiedad adjunta a un valor de la
ListViewSelectionMode enumeración:
<ContentPage ...
xmlns:windows="clr-
namespace:Xamarin.Forms.PlatformConfiguration.WindowsSpecific;assembly=Xamarin.Forms.Core">
<StackLayout>
<ListView ... windows:ListView.SelectionMode="Inaccessible">
...
</ListView>
</StackLayout>
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;
...
listView.On<Windows>().SetSelectionMode(ListViewSelectionMode.Inaccessible);
El ListView.On<Windows> método especifica que solo se ejecutan este específicos de la plataforma en la plataforma
Universal de Windows. El ListView.SetSelectionMode método, en el
Xamarin.Forms.PlatformConfiguration.WindowsSpecific espacio de nombres, se utiliza para controlar si los
elementos de un ListView puede responder pulse gestos, con el ListViewSelectionMode enumeración que
proporciona dos valores posibles:
Accessible : indica que el ListView desencadenará nativo ItemClick eventos para controlar la interacción y,
por lo tanto, proporcionar una funcionalidad de accesibilidad. Por lo tanto, el Narrador de Windows y el teclado
pueden interactuar con el ListView . Sin embargo, los elementos de la ListView no puede responder para
puntear gestos. Este es el comportamiento predeterminado para ListView instancias en la plataforma
Universal de Windows.
Inaccessible : indica que el ListView desencadenará nativo Tapped eventos para controlar la interacción. Por
lo tanto, los elementos de la ListView pulse gestos puede responder. Sin embargo, no hay ninguna
funcionalidad de accesibilidad y, por tanto, el Narrador de Windows y el teclado no pueden interactuar con el
ListView .
NOTE
El Accessible y Inaccessible modos de selección son mutuamente excluyentes y tendrá que elegir entre una accesible
ListView o un ListView que puede responder a los gestos de pulse.
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
WindowsSpecific API
Barra de navegación MasterDetailPage Windows
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Esta plataforma Universal de Windows específicos de la plataforma se usan para contraer la barra de navegación
en un MasterDetailPage y se consume en XAML estableciendo el MasterDetailPage.CollapseStyle y
MasterDetailPage.CollapsedPaneWidth propiedades adjuntas:
<MasterDetailPage ...
xmlns:windows="clr-
namespace:Xamarin.Forms.PlatformConfiguration.WindowsSpecific;assembly=Xamarin.Forms.Core"
windows:MasterDetailPage.CollapseStyle="Partial"
windows:MasterDetailPage.CollapsedPaneWidth="48">
...
</MasterDetailPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;
...
page.On<Windows>().SetCollapseStyle(CollapseStyle.Partial).CollapsedPaneWidth(148);
descargar el ejemplo
Esta plataforma Universal de Windows específicos de la plataforma se usan para cambiar la ubicación de una
barra de herramientas en un Page y se consume en XAML estableciendo el Page.ToolbarPlacement propiedad
adjunta un valor de la ToolbarPlacement enumeración:
<TabbedPage ...
xmlns:windows="clr-
namespace:Xamarin.Forms.PlatformConfiguration.WindowsSpecific;assembly=Xamarin.Forms.Core"
windows:Page.ToolbarPlacement="Bottom">
...
</TabbedPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;
...
page.On<Windows>().SetToolbarPlacement(ToolbarPlacement.Bottom);
2 . En el nuevo proyecto de plataforma Universal de Windows cuadro de diálogo, seleccione las versiones
mínima y de destino de Windows 10 que se ejecutará la aplicación:
3 . Haga doble clic en el proyecto de UWP y seleccione administrar paquetes NuGet... y agregue el
Xamarin.Forms paquete. Asegúrese de que los otros proyectos de la solución también se actualizan a la misma
versión del paquete de Xamarin.Forms.
4 . Asegúrese de que el nuevo proyecto UWP se compilará el compilar > Administrador de configuración
ventana (Esto probablemente no habrá sucedido de forma predeterminada). Marca el compilar y implementar
cuadros para el proyecto Universal:
5 . Haga doble clic en el proyecto y seleccione Agregar > referencia y crear una referencia al proyecto de
aplicación de Xamarin.Forms (.NET Standard o proyectos compartidos).
6 . En el proyecto UWP, edite App.xaml.cs para incluir el Init llamada al método dentro de la OnLaunched
método alrededor de la línea 52:
xmlns:forms="using:Xamarin.Forms.Platform.UWP"
<forms:WindowsPage
...
xmlns:forms="using:Xamarin.Forms.Platform.UWP"
...
</forms:WindowsPage>
10 . En el proyecto UWP, edite MainPage.xaml.cs para quitar el : Page especificador de herencia para el
nombre de clase (puesto que ahora se heredará desde WindowsPage debido a los cambios realizados en el paso
anterior):
12 . Agregue los recursos locales (p ej. archivos de imagen) de los proyectos existentes de plataforma que son
necesarios.
Solución de problemas
"Excepción de invocación de destino" cuando se usa "Compilación con la cadena de herramientas nativas de
.NET"
Si su aplicación para UWP se hace referencia a varios ensamblados (por ejemplo un control de terceros
bibliotecas o su propia aplicación se divide en varias bibliotecas), no es posible que pueda Xamarin.Forms cargar
los objetos de dichos ensamblados (como representadores personalizados).
Esto puede ocurrir cuando se usa el compilar con cadena de herramientas .NET Native que es una opción
para aplicaciones UWP en el Propiedades > compilar > General ventana para el proyecto.
Puede solucionar este problema mediante una sobrecarga específica de UWP de la Forms.Init llamar
App.xaml.cs tal como se muestra en el código siguiente (debe reemplazar ClassInOtherAssembly con una clase
real hace referencia su código):
Agregue una entrada para cada ensamblado que ha agregado como una referencia en el Explorador de
soluciones, ya sea a través de una referencia directa o NuGet.
Compilación nativa de .NET y de servicios de dependencia
Versiones de lanzamiento con .NET Native puede producir un error de compilación para resolver los servicios de
dependencia que se definen fuera el ejecutable de aplicación principal (como en un proyecto independiente o
biblioteca).
Use el DependencyService.Register<T>() método para registrar manualmente clases del servicio de dependencia.
Según el ejemplo anterior, agregue el método register similar al siguiente:
Xamarin.Forms.Forms.Init(e, assembliesToInclude);
Xamarin.Forms.DependencyService.Register<ClassInOtherAssembly>(); // add this
SearchBar ortográfica en Windows
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Esta plataforma Universal de Windows específicos de la plataforma permite una SearchBar para interactuar con el
motor de corrección ortográfica. Se consume en XAML estableciendo el SearchBar.IsSpellCheckEnabled propiedad
adjunta un boolean valor:
<ContentPage ...
xmlns:windows="clr-
namespace:Xamarin.Forms.PlatformConfiguration.WindowsSpecific;assembly=Xamarin.Forms.Core">
<StackLayout>
<SearchBar ... windows:SearchBar.IsSpellCheckEnabled="true" />
...
</StackLayout>
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;
...
searchBar.On<Windows>().SetIsSpellCheckEnabled(true);
searchBar.On<Windows>().SetIsSpellCheckEnabled(!searchBar.On<Windows>().GetIsSpellCheckEnabled());
El resultado es que el texto escrito en el SearchBar puede spell comprobarse, con ortografía incorrecta que se
indica al usuario:
NOTE
El SearchBar clase en el Xamarin.Forms.PlatformConfiguration.WindowsSpecific también dispone de espacio de
nombres EnableSpellCheck y DisableSpellCheck métodos que pueden usarse para habilitar y deshabilitar el corrector
ortográfico en el SearchBar , respectivamente.
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
WindowsSpecific API
Iconos de TabbedPage en Windows
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Esta plataforma Universal de Windows específicos de la plataforma permite a los iconos de página que se
mostrará en un TabbedPage barra de herramientas y proporciona la capacidad de especificar opcionalmente el
tamaño del icono. Se consume en XAML estableciendo el TabbedPage.HeaderIconsEnabled propiedad adjunta true
y, opcionalmente, estableciendo el TabbedPage.HeaderIconsSize propiedad adjunta un 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" IconImageSource="todo.png">
...
</ContentPage>
<ContentPage Title="Reminders" IconImageSource="reminders.png">
...
</ContentPage>
<ContentPage Title="Contacts" IconImageSource="contacts.png">
...
</ContentPage>
</TabbedPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;
...
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
WindowsSpecific API
Claves de acceso de VisualElement en Windows
11/07/2019 • 6 minutes to read • Edit Online
descargar el ejemplo
Teclas de acceso son métodos abreviados de teclado que mejoran la facilidad de uso y accesibilidad de las
aplicaciones en la plataforma Universal de Windows (UWP ) al proporcionar una manera intuitiva para los
usuarios a navegar rápidamente e interactuar con de interfaz de usuario visible la aplicación a través de un teclado
en lugar de a través de la interacción o un mouse. Son combinaciones de la tecla Alt y uno o más teclas
alfanuméricas, normalmente presionadas de manera secuencial. Métodos abreviados de teclado automáticamente
son compatibles con las claves de acceso que utilizan un carácter alfanumérico individual.
Sugerencias de teclas de acceso son flotantes distintivos que se muestra al lado de los controles que incluyen las
claves de acceso. Cada sugerencia de clave de acceso contiene las teclas alfanuméricas que activación el control
asociado. Cuando un usuario presiona la tecla Alt, se muestran las sugerencias de teclas de acceso.
Esta plataforma específica de UWP se usa para especificar una clave de acceso para un VisualElement . Se
consume en XAML estableciendo el VisualElement.AccessKey propiedad adjunta a un valor alfanumérico y,
opcionalmente, establezca el VisualElement.AccessKeyPlacement propiedad adjunta a un valor de la
AccessKeyPlacement enumeración, el VisualElement.AccessKeyHorizontalOffset propiedad adjunta un double y el
VisualElement.AccessKeyVerticalOffset propiedad adjunta a un 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>
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);
...
NOTE
Normalmente, el Auto colocación keytips es suficiente, lo que incluye compatibilidad con interfaces de usuario adaptable.
NOTE
Desplazamientos de sugerencia de clave de acceso no pueden establecerse cuando se establece la posición de clave de
acceso Auto .
Cuando un usuario activa una tecla de acceso presionando la tecla Alt, seguida por el acceso de clave, la acción
predeterminada para el VisualElement se ejecutará. Por ejemplo, cuando un usuario activa la clave de acceso en
un Switch , el Switch se alterna. Cuando un usuario activa la clave de acceso en un Entry , el Entry recibe el
foco. Cuando un usuario activa la clave de acceso en un Button , el controlador de eventos para el Clicked se
ejecuta el evento.
Para obtener más información acerca de las claves de acceso, consulte claves de acceso.
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
WindowsSpecific API
Modo de Color VisualElement heredado en Windows
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Algunas de las vistas de Xamarin.Forms cuentan con un modo de color heredado. En este modo, cuando el
IsEnabled se establece la propiedad de la vista en false , la vista invalida los colores establecidos por el usuario
con los colores nativo predeterminado para el estado deshabilitado. Para hacia atrás compatibilidad, este modo
heredado de color permanece el comportamiento predeterminado para las vistas admitidas.
Esta plataforma Universal de Windows específicos de la plataforma deshabilita este modo heredado de color, por
lo que establecen los colores en una vista por el usuario permanece incluso cuando la vista está deshabilitada. Se
consume en XAML estableciendo el VisualElement.IsLegacyColorModeEnabled propiedad adjunta 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>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;
...
_legacyColorModeDisabledEditor.On<Windows>().SetIsLegacyColorModeEnabled(false);
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
WindowsSpecific API
Alertas de JavaScript en WebView en Windows
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Este específicos de la plataforma permite una WebView para mostrar las alertas de JavaScript en un cuadro de
diálogo de mensaje UWP. Se consume en XAML estableciendo el WebView.IsJavaScriptAlertEnabled propiedad
adjunta un boolean valor:
<ContentPage ...
xmlns:windows="clr-
namespace:Xamarin.Forms.PlatformConfiguration.WindowsSpecific;assembly=Xamarin.Forms.Core">
<StackLayout>
<WebView ... windows:WebView.IsJavaScriptAlertEnabled="true" />
...
</StackLayout>
</ContentPage>
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;
...
El WebView.On<Windows> método especifica que solo se ejecutan este específicos de la plataforma en la plataforma
Universal de Windows. El WebView.SetIsJavaScriptAlertEnabled método, en el
Xamarin.Forms.PlatformConfiguration.WindowsSpecific espacio de nombres, se usa para controlar si las alertas de
JavaScript están habilitadas. Además, el WebView.SetIsJavaScriptAlertEnabled método puede utilizarse para activar
o desactivar las alertas de JavaScript mediante una llamada a la IsJavaScriptAlertEnabled método para devolver
si están habilitadas:
_webView.On<Windows>().SetIsJavaScriptAlertEnabled(!_webView.On<Windows>().IsJavaScriptAlertEnabled());
El resultado es que se pueden mostrar las alertas de JavaScript en un cuadro de diálogo de mensaje UWP:
Vínculos relacionados
PlatformSpecifics (ejemplo)
Creación funcionalidades específicas de plataforma
WindowsSpecific API
Xamarin.Essentials
11/07/2019 • 4 minutes to read • Edit Online
Xamarin.Essentials brinda a los desarrolladores API multiplataformas para sus aplicaciones móviles.
Android, iOS y UWP ofrecen API de plataforma y sistema operativo únicas a las que los desarrolladores pueden
tener acceso desde C# mediante Xamarin. Xamarin.Essentials brinda una API multiplataforma única que funciona
con cualquier aplicación Xamarin.Forms, Android, iOS o UWP accesible desde código compartido, sin importar
cómo se creó la interfaz de usuario.
Introducción a Xamarin.Essentials
Siga la guía de introducción para instalar el paquete NuGet de Xamarin.Essentials a los proyectos nuevos o
existentes de Xamarin.Forms, Android, iOS o UWP.
Guías de características
Siga las guías para integrar estas características de Xamarin.Essentials en las aplicaciones:
Accelerometer: recupere los datos de aceleración del dispositivo en un espacio tridimensional.
App Information: conozca información sobre la aplicación.
Barometer: supervise los cambios de presión con el barómetro.
Battery: detecte fácilmente el nivel, origen y estado de la batería.
Clipboard: establezca o lea fácil y rápidamente texto en el Portapapeles.
Color Converters: métodos del asistente para System.Drawing.Color.
Compass: supervise los cambios en la brújula.
Connectivity: compruebe el estado de la conectividad y detecte cambios.
Detect Shake: detecte movimientos de agitación en el dispositivo.
Device Display Information: obtenga la orientación y las métricas de la pantalla del dispositivo.
Device Information: conozca información sobre el dispositivo de manera sencilla.
Email: envíe fácilmente mensajes de correo electrónico.
File System Helpers: guarde fácilmente archivos en los datos de la aplicación.
Flashlight: una manera sencilla de encender y apagar la linterna.
Geocoding: coordenadas y direcciones de código geográfico y de código geográfico inverso.
Geolocation: recupere la ubicación de GPS del dispositivo.
Gyroscope: haga seguimiento de la rotación alrededor de tres ejes primarios del dispositivo.
Launcher: permite que una aplicación abra un URI por el sistema.
Magnetometer: detecte la orientación del dispositivo respectivo del campo magnético de la Tierra.
MainThread: ejecute código en el subproceso principal de la aplicación.
Maps: abra la aplicación de mapas en una ubicación específica.
Open Browser: abra rápidamente y sin problemas un explorador en un sitio web específico.
Orientation Sensor: recupere la orientación del dispositivo en un espacio tridimensional.
Phone Dialer: abra el marcador telefónico.
Platform Extensions: métodos del asistente para convertir Rect, Size y Point.
Preferences: agregue rápida y sencillamente las preferencias persistentes.
Secure Storage: almacene datos de manera segura.
Share: envíe texto y URI de sitio web a otras aplicaciones.
SMS: cree un mensajes SMS para enviarlo.
Text-to-Speech: vocalice texto en el dispositivo.
Unit Converters: métodos del asistente para convertir unidades.
Version Tracking: haga seguimiento de las versiones de las aplicaciones y los números de compilación.
Vibrate: haga que el dispositivo vibre.
Solución de problemas
Busque ayuda si se encuentra con problemas.
Documentación de la API
Examine la documentación de la API para cada característica de Xamarin.Essentials.
Introducción a Xamarin.Essentials
11/07/2019 • 5 minutes to read • Edit Online
Xamarin.Essentials brinda una API multiplataforma única que funciona con cualquier aplicación iOS,
Android o UWP accesible desde código compartido, sin importar cómo se creó la interfaz de usuario.
Compatibilidad de la plataforma
Xamarin.Essentials admite las siguientes plataformas y sistemas operativos:
PLATAFORMA VERSIÓN
Instalación
Xamarin.Essentials está disponible como paquete NuGet que se puede agregar a cualquier proyecto
nuevo o existente con Visual Studio.
1. Descargue e instale Visual Studio con Visual Studio Tools para Xamarin.
2. Abra un proyecto existente o cree uno nuevo con la plantilla de aplicación vacía en Visual Studio
C# (Android, iPhone e iPad o multiplataforma). Importante: Si se agrega a un proyecto de UWP,
asegúrese de que en las propiedades del proyecto esté establecida la compilación 16299 u otra
posterior.
3. Agregue el paquete NuGet Xamarin.Essentials a cada proyecto:
Visual Studio
Visual Studio para Mac
En el panel del Explorador de soluciones, haga clic con el botón derecho en el nombre de la
solución y seleccione Administrar paquetes NuGet. Busque Xamarin.Essentials e instale el
paquete en TODOS los proyectos, incluidos Android, iOS, UWP y las bibliotecas de .NET
Standard.
4. Agregue una referencia a Xamarin.Essentials en cualquier clase de C# para hacer referencia a las
API.
using Xamarin.Essentials;
Para controlar los permisos en tiempo de ejecución de Android, Xamarin.Essentials debe recibir
cualquier OnRequestPermissionsResult . Agregue el código siguiente a todas las clases Activity :
6. Siga las guías de Xamarin.Essentials para poder copiar y pegar fragmentos de código para cada
característica.
Otros recursos
Es recomendable que los desarrolladores que trabajan por primera vez con Xamarin visiten Introducción
al desarrollo de Xamarin.
Visite el repositorio GitHub de Xamarin.Essentials para ver el código fuente actual, qué viene más
adelante, ejecutar ejemplos y clonar el repositorio. Estaremos encantados de recibir cualquier
colaboración de la comunidad.
Examine la documentación de la API para conocer cada característica de Xamarin.Essentials.
Xamarin.Essentials: Acelerómetro
11/07/2019 • 4 minutes to read • Edit Online
La clase Accelerometer permite supervisar el sensor del acelerómetro del dispositivo, que indica la aceleración
del dispositivo en un espacio tridimensional.
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que
la biblioteca está correctamente instalada y configurada en los proyectos.
Uso de Accelerometer
Agregue una referencia a Xamarin.Essentials en su clase:
using Xamarin.Essentials;
La funcionalidad Accelerometer funciona mediante una llamada a los métodos Start y Stop para realizar
escuchas de los cambios realizados en la aceleración. Los cambios se enviarán a través del evento ReadingChanged .
A continuación le mostramos un ejemplo 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;
}
Las lecturas del acelerómetro se notifican en G. La G es una unidad de fuerza gravitacional igual a la ejercida por
el campo gravitatorio de la Tierra (9,81 m/s^2).
El sistema de coordenadas se define con respecto a la pantalla del teléfono en orientación predeterminada.
Cuando cambia la orientación de pantalla del dispositivo no se intercambian los ejes.
El eje X es horizontal y apunta a la derecha, el eje Y es vertical y apunta hacia arriba, y el eje Z apunta hacia el
exterior de la parte frontal de la pantalla. En este sistema, las coordenadas de detrás de la pantalla tienen valores
de Z negativo.
Ejemplos:
Cuando el dispositivo se encuentra plano sobre una mesa y se mueve desde el lado izquierdo hacia la
derecha, el valor de aceleración de X es positivo.
Cuando el dispositivo se encuentra plano sobre una mesa, el valor de aceleración es + 1,00 G o (+ 9,81
m/s^2), que corresponden a la aceleración del dispositivo (0 m/s^2) menos la fuerza de la gravedad (- 9,81
m/s^2) y normalizada en G.
Cuando el dispositivo se encuentra plano sobre una mesa y se mueve hacia el cielo con una aceleración de
A m/s^2, el valor de la aceleración es igual A + 9,81, que corresponde a la aceleración del dispositivo (+ A
m/s^2) menos la fuerza de la gravedad (- 9,81 m/s^2) y normalizada en G.
Velocidad de sensor
Más rápido: obtener los datos del sensor tan rápido como sea posible (no se garantiza la devolución en el
subproceso de interfaz de usuario).
Juego: velocidad adecuada para juegos (no se garantiza la devolución en el subproceso de interfaz de usuario).
Normal: velocidad predeterminada adecuada para los cambios de orientación de pantalla.
Interfaz de usuario: velocidad adecuada para la interfaz de usuario general.
Si no se garantiza la ejecución del controlador de eventos en el subproceso de interfaz de usuario y si el
controlador de eventos necesita tener acceso a elementos de la interfaz de usuario, use el método
MainThread.BeginInvokeOnMainThread para ejecutar ese código en el subproceso de interfaz de usuario.
API
Código fuente de Accelerometer
Documentación de API para Accelerometer
Vídeo relacionado
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que
la biblioteca está correctamente instalada y configurada en los proyectos.
Uso de AppInfo
Agregue una referencia a Xamarin.Essentials en su clase:
using Xamarin.Essentials;
// Application Name
var appName = AppInfo.Name;
Esta página de configuración permite al usuario cambiar los permisos de la aplicación y realizar otras tareas
específicas de la plataforma.
API
Código fuente de AppInfo
Documentación de API para AppInfo
Vídeo relacionado
La clase Barometer permite supervisar el sensor del barómetro del dispositivo, que mide la presión.
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que
la biblioteca está correctamente instalada y configurada en los proyectos.
Uso de Barometer
Agregue una referencia a Xamarin.Essentials en su clase:
using Xamarin.Essentials;
Barometer funciona mediante una llamada a los métodos Start y Stop para escuchar los cambios en la lectura
de presión del barómetro en hectopascales. Los cambios se enviarán a través del evento ReadingChanged . A
continuación le mostramos un ejemplo 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;
}
Velocidad de sensor
Más rápido: obtener los datos del sensor tan rápido como sea posible (no se garantiza la devolución en el
subproceso de interfaz de usuario).
Juego: velocidad adecuada para juegos (no se garantiza la devolución en el subproceso de interfaz de usuario).
Normal: velocidad predeterminada adecuada para los cambios de orientación de pantalla.
Interfaz de usuario: velocidad adecuada para la interfaz de usuario general.
Si no se garantiza la ejecución del controlador de eventos en el subproceso de interfaz de usuario y si el
controlador de eventos necesita tener acceso a elementos de la interfaz de usuario, use el método
MainThread.BeginInvokeOnMainThread para ejecutar ese código en el subproceso de interfaz de usuario.
La clase Battery le permite comprobar la información sobre la batería del dispositivo y supervisar los cambios.
Además, ofrece información sobre el estado de ahorro de energía del dispositivo, que indica si este se está
ejecutando en el modo de bajo consumo. Las aplicaciones deben evitar el procesamiento en segundo plano si el
estado de ahorro de energía del dispositivo está activado.
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que
la biblioteca está correctamente instalada y configurada en los proyectos.
Para acceder a la funcionalidad de Battery, se requiere la siguiente configuración específica para la plataforma.
Android
iOS
UWP
El permiso Battery es necesario y se debe configurar en el proyecto Android. Se puede agregar de las siguientes
maneras:
Abra el archivo AssemblyInfo.cs de la carpeta Propiedades y agregue lo siguiente:
[assembly: UsesPermission(Android.Manifest.Permission.BatteryStats)]
O haga clic con el botón derecho en el proyecto de Android y abra las propiedades del proyecto. En Manifiesto
de Android, busque el área Permisos requeridos: y active el permiso Battery (Batería). Esto actualizará
automáticamente el archivo AndroidManifest.xml.
Uso de Battery
Agregue una referencia a Xamarin.Essentials en su clase:
using Xamarin.Essentials;
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;
}
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;
}
Cada vez que se cambia cualquiera de las propiedades de la batería, se desencadena un evento:
Es posible poner los dispositivos que usan baterías en el modo de ahorro en caso de baja energía. A veces, los
dispositivos cambian automáticamente a este modo, por ejemplo, cuando la batería cae por debajo del 20 % de su
capacidad. El sistema operativo responde al modo de ahorro de energía reduciendo las actividades que tienden a
agotar la batería. Para ayudar, las aplicaciones pueden evitar el procesamiento en segundo plano u otras
actividades de alta potencia cuando el modo de ahorro de energía está activado.
También puede conocer el estado de ahorro de energía actual del dispositivo con la propiedad estática
Battery.EnergySaverStatus :
Si el estado de ahorro de energía cambia a On , la aplicación debe detener el procesamiento en segundo plano. Si
el estado cambia a Unknown o Off , la aplicación puede reanudar el procesamiento en segundo plano.
API
Código fuente de Battery
Documentación de API para Battery
Vídeo relacionado
Encuentre más vídeos de Xamarin en Channel 9 y YouTube.
Xamarin.Essentials: Portapapeles
11/07/2019 • 2 minutes to read • Edit Online
La clase Clipboard permite copiar y pegar texto en el Portapapeles del sistema entre aplicaciones.
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que
la biblioteca está correctamente instalada y configurada en los proyectos.
Uso de Clipboard
Agregue una referencia a Xamarin.Essentials en su clase:
using Xamarin.Essentials;
TIP
El acceso al Portapapeles debe realizarse en el subproceso de la interfaz de usuario principal. Consulte la API de MainThread
para ver cómo invocar métodos en el subproceso de la interfaz de usuario principal.
API
Código fuente de Clipboard
Documentación de API de Clipboard
Vídeo relacionado
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que
la biblioteca está correctamente instalada y configurada en los proyectos.
using Xamarin.Essentials;
Al trabajar con System.Drawing.Color , puede usar los convertidores integrados de Xamarin.Forms para crear un
color a partir de Hsl, Hex o UInt.
// Back to System.Drawing.Color
var system = platform.ToSystemColor();
API
Código fuente de los convertidores de color
Documentación sobre la API de los convertidores de color
Color fuente de las extensiones de color
Documentación sobre la API de las extensiones de color
Xamarin.Essentials: Brújula
11/07/2019 • 4 minutes to read • Edit Online
La clase Compass permite supervisar la dirección del norte magnético del dispositivo.
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que
la biblioteca está correctamente instalada y configurada en los proyectos.
Uso de Compass
Agregue una referencia a Xamarin.Essentials en su clase:
using Xamarin.Essentials;
La funcionalidad Compass funciona mediante una llamada a los métodos Start y Stop para realizar escuchas de
los cambios realizados en la brújula. Los cambios se enviarán a través del evento ReadingChanged . A continuación
se muestra un ejemplo:
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;
}
Velocidad de sensor
Más rápido: obtener los datos del sensor tan rápido como sea posible (no se garantiza la devolución en el
subproceso de interfaz de usuario).
Juego: velocidad adecuada para juegos (no se garantiza la devolución en el subproceso de interfaz de usuario).
Normal: velocidad predeterminada adecuada para los cambios de orientación de pantalla.
Interfaz de usuario: velocidad adecuada para la interfaz de usuario general.
Si no se garantiza la ejecución del controlador de eventos en el subproceso de interfaz de usuario y si el
controlador de eventos necesita tener acceso a elementos de la interfaz de usuario, use el método
MainThread.BeginInvokeOnMainThread para ejecutar ese código en el subproceso de interfaz de usuario.
Esto solo se aplica a la plataforma Android; el parámetro se ignora en iOS y UWP. Puede leer más información
aquí.
API
Código fuente de Compass
Documentación de API para Compass
Xamarin.Essentials: Conectividad
11/07/2019 • 4 minutes to read • Edit Online
La clase Connectivity permite supervisar los cambios en las condiciones de red del dispositivo, revisar el acceso
actual a la red y cómo está conectado actualmente.
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que
la biblioteca está correctamente instalada y configurada en los proyectos.
Para acceder a la funcionalidad Connectivity, se requiere la siguiente configuración específica para la plataforma.
Android
iOS
UWP
El permiso AccessNetworkState es necesario y se debe configurar en el proyecto Android. Se puede agregar de las
siguientes maneras:
Abra el archivo AssemblyInfo.cs de la carpeta Propiedades y agregue lo siguiente:
[assembly: UsesPermission(Android.Manifest.Permission.AccessNetworkState)]
O haga clic con el botón derecho en el proyecto de Android y abra las propiedades del proyecto. En Manifiesto
de Android, busque el área Permisos requeridos: y compruebe el permiso Access Network State (Estado de
red de acceso). Esto actualizará automáticamente el archivo AndroidManifest.xml.
Uso de Connectivity
Agregue una referencia a Xamarin.Essentials en su clase:
using Xamarin.Essentials;
if (current == NetworkAccess.Internet)
{
// Connection to internet is available
}
Acceso a la red cae en estas categorías:
Internet: acceso a Internet y local.
ConstrainedInternet: acceso limitado a Internet. Indica la conectividad cautiva del portal, donde se
proporciona acceso local a un portal web, pero el acceso a Internet requiere que se proporcionen credenciales
específicas a través de un portal.
Local: solo acceso a la red local.
None: sin conectividad disponible.
Unknown: no se puede determinar la conectividad de Internet.
Puede comprobar qué tipo de perfil de conexión el dispositivo usa de manera activa:
Cada vez que el perfil de conexión o el acceso a la red cambia, puede recibir un evento cuando se desencadena:
Limitaciones
Es importante tener en cuenta que puede que NetworkAccess informe Internet , pero no hay disponible acceso
total a la Web. Debido a cómo funciona la conectividad en cada plataforma, solo puede garantizar que hay
disponible una conexión. Por ejemplo, es posible que el dispositivo esté conectado a una red Wi-Fi, pero el
enrutador no está conectado a Internet. En esta instancia, puede que se indique que hay Internet, pero no hay
disponible ninguna conexión activa.
API
Código fuente de Connectivity
Documentación de API de Connectivity
Vídeo relacionado
Encuentre más vídeos de Xamarin en Channel 9 y YouTube.
Xamarin.Essentials: detección de agitaciones
11/07/2019 • 3 minutes to read • Edit Online
La clase Accelerometer permite supervisar el sensor del acelerómetro del dispositivo, que indica la aceleración
del dispositivo en un espacio tridimensional. Además, le permite registrar eventos que se realizarán cuando el
usuario agite el dispositivo.
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que
la biblioteca está correctamente instalada y configurada en los proyectos.
using Xamarin.Essentials;
Para detectar la agitación del dispositivo, debe usar la funcionalidad Accelerometer mediante una llamada a los
métodos Start y Stop para realizar cambios en la aceleración y para detectar movimientos de agitación.
Siempre que se detecte agitación, se desencadenará un evento ShakeDetected . Se recomienda usar Game o faster
para SensorSpeed . A continuación le mostramos un ejemplo 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 ;
}
Velocidad de sensor
Más rápido: obtener los datos del sensor tan rápido como sea posible (no se garantiza la devolución en el
subproceso de interfaz de usuario).
Juego: velocidad adecuada para juegos (no se garantiza la devolución en el subproceso de interfaz de usuario).
Normal: velocidad predeterminada adecuada para los cambios de orientación de pantalla.
Interfaz de usuario: velocidad adecuada para la interfaz de usuario general.
Si no se garantiza la ejecución del controlador de eventos en el subproceso de interfaz de usuario y si el
controlador de eventos necesita tener acceso a elementos de la interfaz de usuario, use el método
MainThread.BeginInvokeOnMainThread para ejecutar ese código en el subproceso de interfaz de usuario.
Detalles de implementación
La API para la detección de agitaciones usa lecturas sin procesar del acelerómetro para calcular la aceleración.
Utiliza un mecanismo de cola simple para detectar si tres cuartos de los eventos recientes del acelerómetro se han
producido durante el último medio segundo. La aceleración se calcula añadiendo el cuadrado de las lecturas X, Y y
Z del acelerómetro y comparándolo con un umbral determinado.
API
Código fuente de Accelerometer
Documentación de API de Accelerometer
Vídeo relacionado
La clase DeviceDisplay proporciona información sobre las métricas de la pantalla del dispositivo que determinan
cómo se ejecuta la aplicación. También puede solicitar que la pantalla no se apague mientras la aplicación se esté
ejecutando.
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que
la biblioteca está correctamente instalada y configurada en los proyectos.
Uso de DeviceDisplay
Agregue una referencia a Xamarin.Essentials en su clase:
using Xamarin.Essentials;
// Get Metrics
var mainDisplayInfo = DeviceDisplay.MainDisplayInfo;
// Screen density
var density = mainDisplayInfo.Density;
La clase DeviceDisplay también expone un evento al que se puede suscribir para que se desencadene siempre
que cambie cualquier métrica de pantalla:
public class DisplayInfoTest
{
public DisplayInfoTest()
{
// Subscribe to changes of screen metrics
DeviceDisplay.MainDisplayInfoChanged += OnMainDisplayInfoChanged;
}
La clase DeviceDisplay expone una propiedad bool con el nombre KeepScreenOn . Esta propiedad puede
establecerse para que intente impedir que la pantalla del dispositivo se apague o bloquee.
API
Código fuente de DeviceDisplay
Documentación de API de DeviceDisplay
Xamarin.Essentials: Información del dispositivo
11/07/2019 • 2 minutes to read • Edit Online
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que
la biblioteca está correctamente instalada y configurada en los proyectos.
Uso de DeviceInfo
Agregue una referencia a Xamarin.Essentials en su clase:
using Xamarin.Essentials;
// Manufacturer (Samsung)
var manufacturer = DeviceInfo.Manufacturer;
// Platform (Android)
var platform = DeviceInfo.Platform;
// Idiom (Phone)
var idiom = DeviceInfo.Idiom;
Plataformas
DeviceInfo.Platformse correlaciona con una cadena de constante que se asigna al sistema operativo. Los valores
se pueden comprobar con el struct DevicePlatform :
DevicePlatform.iOS: iOS
DevicePlatform.Android: Android
DevicePlatform.UWP: UWP
DevicePlatform.Unknown: desconocido
Expresiones
DeviceInfo.Idiom se correlaciona con una cadena de constante que se asigna al tipo de dispositivo en el que se
ejecuta la aplicación. Los valores se pueden comprobar con el struct DeviceIdiom :
DeviceIdiom.Phone: teléfono
DeviceIdiom.Tablet: tableta
DeviceIdiom.Desktop: escritorio
DeviceIdiom.TV: TV
DeviceIdiom.Watch: reloj
DeviceIdiom.Unknown: desconocido
Tipo de dispositivo
DeviceInfo.DeviceType pone en correlación una enumeración para determinar si la aplicación se ejecuta en un
dispositivo físico o virtual. Un dispositivo virtual es un simulador o emulador.
API
Código fuente de DeviceInfo
Documentación de API para DeviceInfo
Xamarin.Essentials: Correo electrónico
11/07/2019 • 3 minutes to read • Edit Online
La clase Email permite que una aplicación abra la aplicación de correo electrónico predeterminada con
información especificada incluido el asunto, el cuerpo y los destinatarios (PARA, CC, CCO ).
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que
la biblioteca está correctamente instalada y configurada en los proyectos.
TIP
Para usar la API de correo electrónico en iOS, debe ejecutarla en un dispositivo físico, si no, se producirá una excepción.
Uso de Email
Agregue una referencia a Xamarin.Essentials en su clase:
using Xamarin.Essentials;
Para usar la funcionalidad de Email se llama al método ComposeAsync con un valor EmailMessage que contiene
información sobre el correo electrónico:
Datos adjuntos
El envío de archivos por correo electrónico está disponible como versión preliminar experimental en
Xamarin.Essentials versión 1.1.0. Esta característica permite que una aplicación envíe archivos por correo
electrónico a través de clientes de correo electrónico en el dispositivo. Para habilitar esta característica, establezca
la siguiente propiedad en el código de inicio de la aplicación:
ExperimentalFeatures.Enable(ExperimentalFeatures.EmailAttachments);
Una vez que se haya habilitado la característica, se puede enviar por correo electrónico cualquier archivo.
Xamarin.Essentials detectará automáticamente el tipo de archivo (MIME ) y solicitará que el archivo se agregue
como datos adjuntos. Cada cliente de correo electrónico es diferente y podría admitir únicamente algunas
extensiones de archivo o ninguna en absoluto.
A continuación se muestra un ejemplo en el que se escribe texto en el disco y se agrega como datos adjuntos a un
correo electrónico:
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 fuente de Email
Documentación de API para Email
Xamarin.Essentials: Aplicaciones auxiliares de sistema
de archivos
11/07/2019 • 3 minutes to read • Edit Online
La clase FileSystem contiene una serie de aplicaciones auxiliares para buscar la caché y los directorios de datos de
la aplicación y abrir archivos dentro del paquete de aplicación.
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que
la biblioteca está correctamente instalada y configurada en los proyectos.
using Xamarin.Essentials;
Para obtener el directorio de la aplicación para almacenar datos en caché. Los datos en caché se pueden usar
para cualquier dato que se tenga que conservar más tiempo que los datos temporales, pero no deben ser datos
necesarios para que el funcionamiento sea correcto.
Para obtener el directorio de nivel superior de la aplicación para todos los archivos que no son archivos de datos
de usuario. Se realiza una copia de seguridad de estos archivos con el marco de sincronización del sistema
operativo. Vea Detalles de implementación de la plataforma a continuación.
API
Código fuente de las aplicaciones auxiliares de sistema de archivos
Documentación de API para FileSystem
Xamarin.Essentials: Linterna
11/07/2019 • 3 minutes to read • Edit Online
La clase Flashlight tiene la capacidad de activar o desactivar el flash de la cámara del dispositivo y convertirlo en
una linterna.
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que
la biblioteca está correctamente instalada y configurada en los proyectos.
Para acceder a la funcionalidad de Flashlight, se requiere la siguiente configuración específica para la plataforma.
Android
iOS
UWP
Los permisos Flashlight y Camera son obligatorios y se deben configurar en el proyecto de Android. Se puede
agregar de las siguientes maneras:
Abra el archivo AssemblyInfo.cs de la carpeta Propiedades y agregue lo siguiente:
[assembly: UsesPermission(Android.Manifest.Permission.Flashlight)]
[assembly: UsesPermission(Android.Manifest.Permission.Camera)]
O haga clic con el botón derecho en el proyecto de Android y abra las propiedades del proyecto. En Manifiesto
de Android, busque el área Permisos necesarios: y active los permisos FLASHLIGHT (Linterna) y CAMERA
(Cámara). Esto actualizará automáticamente el archivo AndroidManifest.xml.
Mediante la adición de estos permisos Google Play filtrará automáticamente los dispositivos sin necesidad de
hardware específico. Para solucionarlo, agregue lo siguiente al archivo AssemblyInfo.cs del proyecto de Android:
Uso de Flashlight
Agregue una referencia a Xamarin.Essentials en su clase:
using Xamarin.Essentials;
// 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
}
API
Código fuente de Flashlight
Documentación de API para Flashlight
Xamarin.Essentials: Codificación geográfica
11/07/2019 • 3 minutes to read • Edit Online
La clase Geocoding proporciona API para geocodificar una marca de posición en coordenadas de posición e
invertir las coordenadas de código geográfico a una marca de posición.
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que
la biblioteca está correctamente instalada y configurada en los proyectos.
Para acceder a la funcionalidad de Geocoding, se requiere la siguiente configuración específica para la
plataforma.
Android
iOS
UWP
No se requiere configuración adicional.
Uso de Geocoding
Agregue una referencia a Xamarin.Essentials en su clase:
using Xamarin.Essentials;
try
{
var address = "Microsoft Building 25 Redmond WA USA";
var locations = await Geocoding.GetLocationsAsync(address);
La altitud no siempre está disponible. Si no lo está, es posible que la propiedad Altitude sea null o que el valor
sea cero. Si lo está, el valor se expresa en metros sobre el nivel del mar.
try
{
var lat = 47.673988;
var lon = -122.121513;
Console.WriteLine(geocodeAddress);
}
}
catch (FeatureNotSupportedException fnsEx)
{
// Feature not supported on device
}
catch (Exception ex)
{
// Handle exception that may have occurred in geocoding
}
API
Código fuente de Geocoding
Documentación de API para Geocoding
Vídeo relacionado
La clase Geolocation proporciona las API para recuperar las coordenadas de geolocalización actuales del
dispositivo.
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que
la biblioteca está correctamente instalada y configurada en los proyectos.
Para acceder a la funcionalidad de Geolocation, se requiere la siguiente configuración específica para la
plataforma:
Android
iOS
UWP
Los permisos Coarse y Fine Location son requeridos y se deben configurar en el proyecto de Android. Además, si
la aplicación tiene como destino Android 5.0 (nivel de API 21) o versiones posteriores, debe declarar que la
aplicación usa las características de hardware en el archivo de manifiesto. Se puede agregar de las siguientes
maneras:
Abra el archivo AssemblyInfo.cs de la carpeta Propiedades y agregue lo siguiente:
[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)]
O bien, haga clic con el botón derecho en el proyecto de Android y abra las propiedades del proyecto. En
Manifiesto de Android, busque el área Permisos requeridos: y active los permisos
ACCESS_COARSE_LOCATION y ACCESS_FINE_LOCATION. Esto actualizará automáticamente el archivo
AndroidManifest.xml.
Uso de Geolocation
Agregue una referencia a Xamarin.Essentials en su clase:
using Xamarin.Essentials;
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
}
La altitud no siempre está disponible. Si no lo está, es posible que la propiedad Altitude sea null o que el valor
sea cero. Si lo está, el valor se expresa en metros sobre el nivel del mar.
Para consultar las coordenadas de ubicación del dispositivo actual, se puede usar GetLocationAsync . Es mejor
pasar un valor GeolocationRequest completo y CancellationToken , ya que se puede tardar algún tiempo en
obtener la ubicación del 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
}
Android 500
iOS 3000
Bajo
PLATAFORMA DISTANCIA (EN METROS)
Android 500
iOS 1000
iOS 100
UWP 30-500
Alto
PLATAFORMA DISTANCIA (EN METROS)
Android 0 - 100
iOS 10
UWP <= 10
Óptima
PLATAFORMA DISTANCIA (EN METROS)
Android 0 - 100
iOS ~0
UWP <= 10
if (location != null)
{
if(location.IsFromMockProvider)
{
// location is from a mock provider
}
}
API
Código fuente de Geolocation
Documentación de API para Geolocation
Xamarin.Essentials: Giroscopio
11/07/2019 • 2 minutes to read • Edit Online
La clase Gyroscope permite supervisar el sensor de giroscopio del dispositivo, que es la rotación sobre los tres
ejes principales del dispositivo.
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que
la biblioteca está correctamente instalada y configurada en los proyectos.
Uso de Gyroscope
Agregue una referencia a Xamarin.Essentials en su clase:
using Xamarin.Essentials;
La funcionalidad Gyroscope funciona mediante una llamada a los métodos Start y Stop para realizar escuchas
de los cambios realizados en el giroscopio. Los cambios se enviarán a través del evento ReadingChanged en rad/s.
A continuación le mostramos un ejemplo 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;
}
Velocidad de sensor
Más rápido: obtener los datos del sensor tan rápido como sea posible (no se garantiza la devolución en el
subproceso de interfaz de usuario).
Juego: velocidad adecuada para juegos (no se garantiza la devolución en el subproceso de interfaz de usuario).
Normal: velocidad predeterminada adecuada para los cambios de orientación de pantalla.
Interfaz de usuario: velocidad adecuada para la interfaz de usuario general.
Si no se garantiza la ejecución del controlador de eventos en el subproceso de interfaz de usuario y si el
controlador de eventos necesita tener acceso a elementos de la interfaz de usuario, use el método
MainThread.BeginInvokeOnMainThread para ejecutar ese código en el subproceso de interfaz de usuario.
API
Código fuente de Gyroscope
Documentación de API para Gyroscope
Xamarin.Essentials: Selector
11/07/2019 • 2 minutes to read • Edit Online
La clase Launcher permite que una aplicación abra un URI por el sistema. A menudo se usa al vincular en
profundidad en los esquemas de URI personalizados de otra aplicación. Si quiere abrir el explorador en un sitio
web, debe hacer referencia a la API Browser.
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que
la biblioteca está correctamente instalada y configurada en los proyectos.
Uso de Launcher
Agregue una referencia a Xamarin.Essentials en su clase:
using Xamarin.Essentials;
Para usar la funcionalidad Launcher, llame al método OpenAsync y pase un string o Uri para abrirla. Si quiere,
el método CanOpenAsync se puede usar para comprobar si el esquema de URI se puede administrar desde una
aplicación del dispositivo.
API
Código fuente de Launcher
Documentación de API para Launcher
Xamarin.Essentials: Magnetómetro
11/07/2019 • 2 minutes to read • Edit Online
La clase Magnetometer permite supervisar el sensor de magnetómetro del dispositivo, que indica la orientación
del dispositivo con respecto al campo magnético de la Tierra.
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que
la biblioteca está correctamente instalada y configurada en los proyectos.
Uso de Magnetometer
Agregue una referencia a Xamarin.Essentials en su clase:
using Xamarin.Essentials;
La funcionalidad Magnetometer funciona mediante una llamada a los métodos Start y Stop para realizar
escuchas de los cambios en el magnetómetro. Los cambios se enviarán a través del evento ReadingChanged . A
continuación le mostramos un ejemplo 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;
}
Velocidad de sensor
Más rápido: obtener los datos del sensor tan rápido como sea posible (no se garantiza la devolución en el
subproceso de interfaz de usuario).
Juego: velocidad adecuada para juegos (no se garantiza la devolución en el subproceso de interfaz de usuario).
Normal: velocidad predeterminada adecuada para los cambios de orientación de pantalla.
Interfaz de usuario: velocidad adecuada para la interfaz de usuario general.
Si no se garantiza la ejecución del controlador de eventos en el subproceso de interfaz de usuario y si el
controlador de eventos necesita tener acceso a elementos de la interfaz de usuario, use el método
MainThread.BeginInvokeOnMainThread para ejecutar ese código en el subproceso de interfaz de usuario.
API
Código fuente de Magnetometer
Documentación de API para Magnetometer
Xamarin.Essentials: MainThread
11/07/2019 • 5 minutes to read • Edit Online
La clase MainThread permite que las aplicaciones ejecuten código en el subproceso de ejecución principal y
determinen si un bloque de código determinado se ejecuta actualmente en el subproceso principal.
Fondo
La mayoría de los sistemas operativos, incluidos iOS, Android y Plataforma universal de Windows, usan un
modelo de un único subproceso para el código que participa en la interfaz de usuario. Este modelo resulta
necesario para serializar de manera adecuada los eventos de la interfaz de usuario, incluidas pulsaciones de
teclas y entradas táctiles. Con frecuencia, este subproceso se denomina el subproceso principal, el subproceso
de interfaz de usuario o el subproceso de UI. La desventaja que presenta este modelo es que todo el código
que accede a los elementos de la interfaz de usuario se deben ejecutar en el subproceso principal de la
aplicación.
Algunas veces, las aplicaciones deben usar eventos que llamar al controlador de eventos en un subproceso de
ejecución secundario. (Es posible que las clases Accelerometer , Compass , Gyroscope , Magnetometer y
OrientationSensor de Xamarin.Essentials devuelvan información en un subproceso secundario cuando se usa
con velocidades más rápidas). Si el controlador de eventos debe acceder a los elementos de la interfaz de
usuario, debe ejecutar ese código en el subproceso principal. La clase MainThread permite que la aplicación
ejecute este código en el subproceso principal.
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de
que la biblioteca está correctamente instalada y configurada en los proyectos.
using Xamarin.Essentials;
MainThread.BeginInvokeOnMainThread(() =>
{
// Code to run on the main thread
});
También es posible definir un método independiente para el código que se debe ejecutar en el subproceso
principal:
void MyMainThreadCode()
{
// Code to run on the main thread
}
Luego, para ejecutar este método en el subproceso principal, haga referencia a él en el método
BeginInvokeOnMainThread :
MainThread.BeginInvokeOnMainThread(MyMainThreadCode);
NOTE
Xamarin.Forms tiene un método llamado Device.BeginInvokeOnMainThread(Action) que hace lo mismo que
MainThread.BeginInvokeOnMainThread(Action) . Si bien puede usar cualquier método en una aplicación de
Xamarin.Forms, considere si el código de llamada necesita o no una dependencia de Xamarin.Forms. Si no es así,
MainThread.BeginInvokeOnMainThread(Action) probablemente sea una mejor opción.
if (MainThread.IsMainThread)
{
// Code to run if this is the main thread
}
else
{
// Code to run if this is a secondary thread
}
Tal vez se pregunte si debe comprobar que el código se esté ejecutando en un subproceso secundario antes
de llamar a BeginInvokeOnMainThread , por ejemplo, de esta manera:
if (MainThread.IsMainThread)
{
MyMainThreadCode();
}
else
{
MainThread.BeginInvokeOnMainThread(MyMainThreadCode);
}
Quizás sospeche que esta comprobación puede mejorar el rendimiento si el bloque de código ya se ejecuta en
el subproceso principal.
Sin embargo, esta comprobación no es necesaria. Las implementaciones de plataforma de los
BeginInvokeOnMainThread mismos comprueban si la llamada se realiza en el subproceso principal. La
penalización de rendimiento si llama a BeginInvokeOnMainThread cuando no es realmente necesario es muy
pequeña.
API
Código fuente de MainThread
Documentación de API de MainThread
Xamarin.Essentials: Asignación
11/07/2019 • 3 minutes to read • Edit Online
La clase Map permite que una aplicación abra la aplicación de mapas instalada en una ubicación o marca de
posición específica.
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que
la biblioteca está correctamente instalada y configurada en los proyectos.
Uso de Map
Agregue una referencia a Xamarin.Essentials en su clase:
using Xamarin.Essentials;
Map funciona mediante una llamada al método OpenAsync con Location o Placemark abierto con
MapLaunchOptions opcional.
Métodos de extensión.
Si ya tiene una referencia a Location o a Placemark , puede usar el método de extensión integrado OpenMapAsync
con MapLaunchOptions opcional:
Modo de instrucciones
Si llama a OpenMapAsync sin MapLaunchOptions , el mapa se iniciará en la ubicación especificada. Si quiere, puede
hacer que se calcule una ruta de navegación desde la posición actual del dispositivo. Para ello, establezca
NavigationMode en MapLaunchOptions :
API
Código fuente de Map
Documentación de API para Map
Vídeo relacionado
Encuentre más vídeos de Xamarin en Channel 9 y YouTube.
Xamarin.Essentials: Explorador
11/07/2019 • 2 minutes to read • Edit Online
La clase Browser permite que una aplicación abra un vínculo web en el explorador optimizado preferido del
sistema o en el explorador externo.
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que
la biblioteca está correctamente instalada y configurada en los proyectos.
Uso de Browser
Agregue una referencia a Xamarin.Essentials en su clase:
using Xamarin.Essentials;
La funcionalidad Browser funciona mediante una llamada al método OpenAsync con Uri y BrowserLaunchMode .
Este método devuelve un valor después de que el usuario inicie el explorador, a veces sin que tenga que llegar a
cerrarlo. El resultado bool indica si el inicio ha sido correcto o no.
Personalización
Al usar el explorador preferido por el sistema, tiene disponibles varias opciones de personalización para iOS y
Android, por ejemplo, TitleMode (solo en Android), preferencias para las opciones de color para la Toolbar (en
iOS y Android) y Controls que se muestran (solo en iOS ).
Estas opciones se especifican usando BrowserLaunchOptions al llamar a OpenAsync .
Externo
Se usará Intent para solicitar que se abra el URI a través del explorador normal del sistema.
API
Código fuente de Browser
Documentación de API para Browser
Vídeo relacionado
NOTE
Esta clase se usa para determinar la orientación de un dispositivo en un espacio tridimensional. Si tiene que determinar si la
visualización de vídeo del dispositivo está en modo vertical u horizontal, use la propiedad Orientation del objeto
ScreenMetrics disponible en la clase DeviceDisplay .
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que
la biblioteca está correctamente instalada y configurada en los proyectos.
Uso de OrientationSensor
Agregue una referencia a Xamarin.Essentials en su clase:
using Xamarin.Essentials;
OrientationSensor se habilita mediante una llamada al método Start para supervisar los cambios en la
orientación del dispositivo y se deshabilita al llamar al método Stop . Los cambios se enviarán a través del evento
ReadingChanged . Este es un uso de ejemplo:
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;
}
Las lecturas de OrientationSensor se informan como un Quaternion que describe la orientación del dispositivo
en función de dos sistemas de coordenadas tridimensionales:
El dispositivo (generalmente un teléfono o tableta) tiene un sistema de coordenadas tridimensional con los
siguientes ejes:
El eje X positivo apunta a la derecha de la visualización en modo vertical.
El eje Y positivo apunta a la parte de arriba del dispositivo en modo horizontal.
El eje Z positivo apunta fuera de la pantalla.
El sistema de coordenadas tridimensional de la Tierra tiene estos ejes:
El eje X positivo es tangente a la superficie de la Tierra y apunta al este.
El eje Y positivo también es tangente a la superficie de la Tierra y apunta al norte.
El eje Z positivo es perpendicular a la superficie de la Tierra y apunta hacia arriba.
Quaternion describe la rotación del sistema de coordenadas del dispositivo en relación con el sistema de
coordenadas de la Tierra.
Un valor Quaternion está estrechamente relacionado con la rotación alrededor de un eje. Si un eje de rotación es
el vector normalizado (ax, ay, az) y el ángulo de rotación es Θ, los componentes (X, Y, Z, W ) del cuaternión son:
(ax·sin(Θ/2), ay·sin(Θ/2), az·sin(Θ/2), cos(Θ/2))
x y z
Estos son los sistemas de coordenadas de la derecha por lo que, con el pulgar de la mano derecha apuntando en
la dirección positiva del eje de rotación, la curva de los dedos indica la dirección de la rotación de los ángulos
positivos.
Ejemplos:
Cuando el dispositivo está pantalla arriba sobre una mesa, con la parte superior del mismo (en el modo
vertical) apuntando al norte, los dos sistemas de coordenadas están alineados. El valor Quaternion
representa el cuaternión de identidad (0, 0, 0, 1). Todas las rotaciones se pueden analizar en relación con
esta posición.
Cuando el dispositivo está pantalla arriba sobre una mesa y la parte superior del mismo (en el modo
vertical) apunta al oeste, el valor de Quaternion es (0, 0, 0.707, 0.707). El dispositivo se giró 90 grados
alrededor del eje Z de la Tierra.
Cuando el dispositivo se sostiene de manera vertical, con la parte superior (en el modo vertical) apuntando
al cielo y la parte posterior orientada al norte, es porque el dispositivo se giró 90 grados alrededor del eje
X. El valor de Quaternion es (0.707, 0, 0, 0.707).
Si el dispositivo se coloca de manera tal que el borde izquierdo esté sobre una mesa y la parte superior
apunte al norte, es porque el dispositivo se giró –90 grados alrededor del eje Y (o 90 grados alrededor del
eje Y negativo). El valor de Quaternion es (0, -0.707, 0, 0.707).
Velocidad de sensor
Más rápido: obtener los datos del sensor tan rápido como sea posible (no se garantiza la devolución en el
subproceso de interfaz de usuario).
Juego: velocidad adecuada para juegos (no se garantiza la devolución en el subproceso de interfaz de usuario).
Normal: velocidad predeterminada adecuada para los cambios de orientación de pantalla.
Interfaz de usuario: velocidad adecuada para la interfaz de usuario general.
Si no se garantiza la ejecución del controlador de eventos en el subproceso de interfaz de usuario y si el
controlador de eventos necesita tener acceso a elementos de la interfaz de usuario, use el método
MainThread.BeginInvokeOnMainThread para ejecutar ese código en el subproceso de interfaz de usuario.
API
Código fuente de OrientationSensor
Documentación de API de OrientationSensor
Xamarin.Essentials: Marcador telefónico
11/07/2019 • 2 minutes to read • Edit Online
La clase PhoneDialer permite que una aplicación abra un número de teléfono en el marcador telefónico.
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que
la biblioteca está correctamente instalada y configurada en los proyectos.
using Xamarin.Essentials;
La funcionalidad de marcador telefónico funciona mediante una llamada al método Open con un número de
teléfono con el que abrir el marcador. Cuando se solicita Open , la API intentará automáticamente dar formato al
número en función del código de país, si se especifica.
API
Código fuente del marcador telefónico
Documentación de API para PhoneDialer
Xamarin.Essentials: extensiones de plataforma
11/07/2019 • 2 minutes to read • Edit Online
Xamarin.Essentials ofrece varios métodos de extensión de plataforma al trabajar con tipos de plataforma como
Rect, Size y Point. Esto significa que puede convertir la versión System de estos tipos a tipos específicos de iOS,
Android y UWP.
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que
la biblioteca está correctamente instalada y configurada en los proyectos.
using Xamarin.Essentials;
Todas las extensiones de plataforma solo se pueden llamar desde proyectos UWP, iOS o Android.
Punto
// Back to System.Drawing.Size
var system2 = platform.ToSystemSize();
Tamaño
// Back to System.Drawing.Size
var system2 = platform.ToSystemSize();
Rectángulo
// Back to System.Drawing.Size
var system2 = platform.ToSystemSize();
API
Código fuente de los convertidores
Documentación sobre la API de los convertidores de puntos
Documentación sobre la API de los convertidores de rectángulos
Documentación sobre la API de los convertidores de tamaño
Xamarin.Essentials: Preferencias
11/07/2019 • 4 minutes to read • Edit Online
La clase Preferences ayuda a almacenar las preferencias de la aplicación en un almacén de clave y valor.
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que
la biblioteca está correctamente instalada y configurada en los proyectos.
Uso de Preferences
Agregue una referencia a Xamarin.Essentials en su clase:
using Xamarin.Essentials;
Preferences.Set("my_key", "my_value");
Preferences.Remove("my_key");
Preferences.Clear();
Además de estos métodos, cada una toma un valor sharedName opcional que se puede usar para crear
contenedores adicionales para la preferencia. Lea los detalles de implementación de la plataforma a continuación.
Persistencia
Al desinstalar la aplicación se quitarán todas las Preferencias. Hay una excepción, para las aplicaciones que se
destinan y se ejecutan en Android 6.0 (nivel de API 23) o versiones posteriores en las que se usa Copia de
seguridad automática. Esta característica está activada de forma predeterminada y conserva los datos de
aplicación, incluidas las preferencias compartidas, que son las que usa la API Preferences. Se puede
deshabilitar si se sigue la documentación de Google.
Limitaciones
Cuando se almacena una cadena, esta API está pensada para almacenar pequeñas cantidades de texto. El
rendimiento puede ser inferior si se intenta usar para almacenar grandes cantidades de texto.
API
Código fuente de Preferences
Documentación de API para Preferences
Vídeo relacionado
Encuentre más vídeos de Xamarin en Channel 9 y YouTube.
Xamarin.Essentials: Almacenamiento seguro
11/07/2019 • 8 minutes to read • Edit Online
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que
la biblioteca está correctamente instalada y configurada en los proyectos.
Para acceder a la funcionalidad SecureStorage, se requiere la siguiente configuración específica para la
plataforma:
Android
iOS
UWP
TIP
Copia de seguridad para aplicaciones es una característica de Android 6.0 (nivel de API 23) y versiones posteriores que crea
copias de seguridad de los datos de aplicación del usuario (preferencias compartidas, archivos en el almacenamiento interno
de la aplicación y otros archivos específicos). Los datos se restauran cuando se reinstala o instala una aplicación en un
dispositivo nuevo. Esto puede afectar a SecureStorage , que utiliza las preferencias compartidas de las que se creó una
copia de seguridad y que no se pueden descifrar cuando se realiza la restauración. Xamarin.Essentials controla
automáticamente este caso al quitar la clave para que se pueda restablecer, pero puede dar un paso adicional si deshabilita
Copia de seguridad automática.
<application ...
android:fullBackupContent="@xml/auto_backup_rules">
</application>
2. Cree un archivo XML denominado auto_backup_rules.xml en el directorio Resources/xml con la acción
de compilación AndroidResource. Luego, establezca este contenido que incluye todas las preferencias
compartidas, excepto SecureStorage :
using Xamarin.Essentials;
try
{
await SecureStorage.SetAsync("oauth_token", "secret-oauth-token-value");
}
catch (Exception ex)
{
// Possible that device doesn't support secure storage on device.
}
try
{
var oauthToken = await SecureStorage.GetAsync("oauth_token");
}
catch (Exception ex)
{
// Possible that device doesn't support secure storage on device.
}
NOTE
Si no hay ningún valor asociado con la clave solicitada, GetAsync devolverá null .
SecureStorage.Remove("oauth_token");
SecureStorage.RemoveAll();
Limitaciones
Esta API está pensada para almacenar pequeñas cantidades de texto. El rendimiento puede ser lento si intenta
usarla para almacenar grandes cantidades de texto.
API
Código fuente de SecureStorage
Documentación de API de SecureStorage
Vídeo relacionado
La clase Share permite que una aplicación comparta datos como texto y vínculos web con otras aplicaciones del
dispositivo.
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que
la biblioteca está correctamente instalada y configurada en los proyectos.
Uso de Share
Agregue una referencia a Xamarin.Essentials en su clase:
using Xamarin.Essentials;
Share funciona mediante una llamada al método RequestAsync con una carga de solicitud de datos que incluye
información para compartir con otras aplicaciones. Se pueden combinar texto y Uri, cada plataforma controlara el
filtrado basado en el contenido.
Interfaz de usuario para compartir con una aplicación externa que aparece cuando se realiza la solicitud:
Diferencias entre plataformas
Android
iOS
UWP
La propiedad Subject se usa para el asunto deseado de un mensaje.
Archivos
El uso compartido de archivos está disponible como versión preliminar experimental en Xamarin.Essentials
versión 1.1.0. Esta característica permite que una aplicación comparta archivos con otras aplicaciones del
dispositivo. Para habilitar esta característica, establezca la siguiente propiedad en el código de inicio de la
aplicación:
ExperimentalFeatures.Enable(ExperimentalFeatures.ShareFileRequest);
Una vez que se haya habilitado la característica, se puede compartir cualquier archivo. Xamarin.Essentials
detectará automáticamente el tipo de archivo (MIME ) y solicitará el uso compartido. Cada plataforma podría
admitir únicamente determinadas extensiones de archivo.
A continuación se muestra un ejemplo en el que se escribe texto en el disco y se comparte con otras aplicaciones:
var fn = "Attachment.txt";
var file = Path.Combine(FileSystem.CacheDirectory, fn);
File.WriteAllText(file, "Hello World");
Vídeo relacionado
Encuentre más vídeos de Xamarin en Channel 9 y YouTube.
Xamarin.Essentials: SMS
11/07/2019 • 2 minutes to read • Edit Online
La clase SMS permite que una aplicación abra la aplicación SMS predeterminada con un mensaje especificado
para enviar un destinatario.
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que
la biblioteca está correctamente instalada y configurada en los proyectos.
Uso de SMS
Agregue una referencia a Xamarin.Essentials en su clase:
using Xamarin.Essentials;
La funcionalidad SMS funciona mediante una llamada al método ComposeAsync , un SmsMessage que contiene el
destinatario del mensaje y el cuerpo del mismo, ambos opcionales.
API
Código fuente de SMS
Documentación de API para SMS
Xamarin.Essentials: Texto a voz
11/07/2019 • 3 minutes to read • Edit Online
La clase TextToSpeech permite que una aplicación utilice los motores de texto a voz para responder a texto del
dispositivo y también para consultar los idiomas disponibles que el motor puede admitir.
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que
la biblioteca está correctamente instalada y configurada en los proyectos.
Uso de Text-to-Speech
Agregue una referencia a Xamarin.Essentials en su clase:
using Xamarin.Essentials;
Text-to-Speech funciona mediante una llamada al método SpeakAsync con parámetros opcionales y de texto y se
devuelve una vez que finaliza la declaración.
}, TaskScheduler.FromCurrentSynchronizationContext());
}
Este método toma un elemento CancellationToken opcional para detener la declaración una vez que se inicia.
CancellationTokenSource cts;
public async Task SpeakNowDefaultSettings()
{
cts = new CancellationTokenSource();
await TextToSpeech.SpeakAsync("Hello World", cancelToken: cts.Token);
// Cancel speech if a cancellation token exists & hasn't been already requested.
public void CancelSpeech()
{
if (cts?.IsCancellationRequested ?? true)
return;
cts.Cancel();
}
Text-to-Speech pondrá automáticamente en la cola las solicitudes de voz del mismo subproceso.
Configuración de voz
Para más información sobre cómo se responde el audio, SpeechOptions permite ajustar el volumen, el tono y la
configuración regional.
Tono 0 2.0
PARÁMETRO MÍNIMA MÁXIMO
Volumen 0 1.0
Limitaciones
No se garantiza la cola de declaraciones si se llama a través de varios subprocesos.
La reproducción de audio en segundo plano no se admite de manera oficial.
API
Código fuente de TextToSpeech
Documentación de TextToSpeech API
Xamarin.Essentials: convertidores de unidades
11/07/2019 • 2 minutes to read • Edit Online
La clase UnitConverters proporciona varios convertidores de unidades para ayudar a los desarrolladores que
usan Xamarin.Essentials.
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que
la biblioteca está correctamente instalada y configurada en los proyectos.
using Xamarin.Essentials;
Todos los convertidores de unidades están disponibles mediante el uso de la clase estática UnitConverters de
Xamarin.Essentials. Por ejemplo, puede convertir fácilmente grados Fahrenheit a Celsius.
API
Código fuente de los convertidores de unidades
Documentación sobre la API de los convertidores de unidades
Xamarin.Essentials: Seguimiento de versiones
11/07/2019 • 2 minutes to read • Edit Online
La clase VersionTracking permite comprobar los números de versión y compilación de las aplicaciones además
de ver información adicional, por ejemplo si es la primera vez que se ha iniciado la aplicación o para la versión
actual, obtener información de la compilación anterior y mucho más.
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que
la biblioteca está correctamente instalada y configurada en los proyectos.
using Xamarin.Essentials;
La primera vez que use la clase VersionTracking, se iniciará el seguimiento de la versión actual. Solo se debe
llamar a Track al principio de la aplicación cada vez que se cargue para asegurarse de que se realiza el
seguimiento de la información de versión actual:
VersionTracking.Track();
API
Código fuente de VersionTracking
Documentación de API para VersionTracking
Vídeo relacionado
La clase Vibration permite iniciar y detener la funcionalidad de vibración durante un período de tiempo
determinado.
Primeros pasos
Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que
la biblioteca está correctamente instalada y configurada en los proyectos.
Para acceder a la funcionalidad de Vibration, se requiere la siguiente configuración específica para la plataforma.
Android
iOS
UWP
El permiso Vibrate (Vibrar) es necesario y se debe configurar en el proyecto de Android. Se puede agregar de las
siguientes maneras:
Abra el archivo AssemblyInfo.cs de la carpeta Propiedades y agregue lo siguiente:
[assembly: UsesPermission(Android.Manifest.Permission.Vibrate)]
O haga clic con el botón derecho en el proyecto de Android y abra las propiedades del proyecto. En Manifiesto
de Android, busque el área Permisos requeridos: y active el permiso VIBRATE (Vibrar). Esto actualizará
automáticamente el archivo AndroidManifest.xml.
Uso de Vibration
Agregue una referencia a Xamarin.Essentials en su clase:
using Xamarin.Essentials;
La funcionalidad de Vibration se puede solicitar para un período de tiempo concreto o el valor predeterminado de
500 milisegundos.
try
{
// Use default vibration length
Vibration.Vibrate();
try
{
Vibration.Cancel();
}
catch (FeatureNotSupportedException ex)
{
// Feature not supported on device
}
catch (Exception ex)
{
// Other error has occurred.
}
API
Código fuente de Vibration
Documentación de API para Vibration
Xamarin.Essentials: Solución de problemas
11/07/2019 • 2 minutes to read • Edit Online
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).
El problema es que no coinciden las dependencias de los dos paquetes NuGet. Esto se puede resolver agregando
de forma manual una versión específica de la dependencia (en este caso Xamarin.Android.Support.Compat)
que puede admitir los dos.
Para ello, agregue de forma manual el paquete NuGet que es el origen del conflicto y use la lista Versión para
seleccionar una versión específica. Actualmente, la versión 28.0.0.1 del paquete NuGet
Xamarin.Android.Support.Compat & Xamarin.Android.Support.Core.Util resolverá este error.
Consulte esta entrada de blog para obtener más información y ver un vídeo sobre cómo resolver el problema.
Si surge algún problema o encuentra un error, notifíquelo en el repositorio de Xamarin.Essentials de GitHub.
Almacenamiento de datos local de Xamarin.Forms
11/07/2019 • 2 minutes to read • Edit Online
Archivos
El control de archivos con Xamarin.Forms puede lograrse mediante código en una biblioteca de .NET Standard o
con recursos incrustados. En este artículo se explica cómo realizar operaciones de control de código compartido en
una aplicación de Xamarin.Forms.
descargar el ejemplo
El control de archivos con Xamarin.Forms puede lograrse mediante código en una biblioteca de .NET Standard o
con recursos incrustados.
Información general
El código de Xamarin.Forms se ejecuta en varias plataformas, cada una con su propio sistema de archivos.
Anteriormente, esto significaba que las acciones de leer y escribir en archivos se realizaban con mayor facilidad
mediante las API de archivo nativas de cada plataforma. Como alternativa, los recursos incrustados son una
solución más sencilla para distribuir archivos de datos con una aplicación. Pero, con .NET Standard 2.0, se puede
compartir el código de acceso a archivos en bibliotecas de .NET Standard.
Para obtener información sobre cómo controlar archivos de imagen, vea la página Trabajar con imágenes.
File.WriteAllText(fileName, text);
La ruta del archivo en cada plataforma puede determinarse desde una biblioteca de .NET Standard mediante el
uso de un valor de la enumeración Environment.SpecialFolder como el primer argumento para el método
Environment.GetFolderPath . Después, esto puede combinarse con un nombre de archivo con el método
Path.Combine :
Estas operaciones se demuestran en la aplicación de ejemplo, donde se incluye una página que guarda y carga
texto:
Cargar archivos insertados como recursos
Para insertar un archivo en un ensamblado de .NET Standard, cree o agregue un archivo y asegúrese de usar
esta acción de compilación: EmbeddedResource.
Visual Studio
Visual Studio para Mac
Después, la variable text puede usarse para mostrar el texto o, en cualquier caso, usarlo en el código. En esta
captura de pantalla de la aplicación de ejemplo, se muestra el texto representado en un control Label .
Cargar y deserializar código XML es igual de sencillo. En el código siguiente, se muestra un archivo XML que se
carga y se deserializa desde un recurso y, después, se enlaza a ListView para mostrarlo. El archivo XML contiene
una matriz de objetos Monkey (la clase se define en el código de ejemplo).
#if __IOS__
var resourcePrefix = "WorkingWithFiles.iOS.";
#endif
#if __ANDROID__
var resourcePrefix = "WorkingWithFiles.Droid.";
#endif
Organización de recursos
En los ejemplos anteriores, se da por supuesto que el archivo está insertado en el directorio raíz del proyecto de la
biblioteca de .NET Standard, por lo que el identificador de recurso tendría el formato
EspacioDeNombres.NombreDeArchivo.Extensión, como WorkingWithFiles.PCLTextResource.txt y
WorkingWithFiles.iOS.SharedTextResource.txt .
Los recursos incrustados se pueden organizar en carpetas. Cuando un recurso incrustado se coloca en una
carpeta, el nombre de carpeta se convierte en parte del identificador de recurso (separado por puntos), de forma
que el formato del identificador de recurso se convierte en
EspacioDeNombres.Carpeta.NombreDeArchivo.Extensión. Al colocar los archivos usados en la aplicación
de ejemplo en una carpeta MyFolder, los identificadores de recurso correspondientes serían
WorkingWithFiles.MyFolder.PCLTextResource.txt y WorkingWithFiles.iOS.MyFolder.SharedTextResource.txt .
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);
}
Resumen
En este artículo, se muestran algunas operaciones de archivo sencillas para guardar y cargar texto en el dispositivo
y para cargar recursos incrustados. Con .NET Standard 2.0, se puede compartir el código de acceso a archivos en
bibliotecas de .NET Standard.
Vínculos relacionados
FilesSample
Xamarin.Forms Samples (Ejemplos de Xamarin.Forms)
Trabajar con el sistema de archivos en Xamarin.iOS
Bases de datos locales de Xamarin.Forms
11/07/2019 • 4 minutes to read • Edit Online
descargar el ejemplo
Xamarin.Forms admite aplicaciones de base de datos que usan el motor de base de datos de SQLite, lo que
permite cargar y guardar los objetos en código compartido. En este artículo se describe cómo las aplicaciones de
Xamarin.Forms pueden leer y escribir datos en una base de datos de SQLite local mediante SQLite.Net.
Información general
Las aplicaciones de Xamarin.Forms pueden usar el paquete de NuGet SQLite.NET PCL para incorporar las
operaciones de base de datos en el código compartido haciendo referencia a las clases SQLite que se incluyen en
el NuGet. Las operaciones de base de datos se pueden definir en el proyecto de biblioteca de .NET Standard de la
solución de Xamarin.Forms.
La aplicación de ejemplo acompañante es una sencilla aplicación de lista de tareas. Las siguientes capturas de
pantalla muestran cómo el ejemplo aparece en cada plataforma:
Uso de SQLite
Para agregar compatibilidad de SQLite a una biblioteca de .NET Standard de Xamarin.Forms, use la función de
búsqueda de NuGet para buscar sqlite-net-pcl e instalar el paquete más reciente:
Hay una serie de paquetes de NuGet con nombres similares, el paquete correcto tiene estos atributos:
Creado por: Frank A. Krueger
Id.: sqlite-net-pcl
Vínculo de NuGet: sqlite-net-pcl
NOTE
Independientemente del nombre del paquete, utilice el paquete de NuGet sqlite-net-pcl incluso en los proyectos de .NET
Standard.
Una vez agregada la referencia, agregue una propiedad a la clase App que devuelve una ruta de acceso local para
almacenar la base de datos:
El constructor TodoItemDatabase , que toma la ruta de acceso del archivo de base de datos como un argumento, se
muestra a continuación:
La ventaja de exponer la base de datos como un singleton es que se crea una conexión de base de datos única que
se mantiene abierta mientras la aplicación se ejecuta, lo que evita el gasto de abrir y cerrar el archivo de base de
datos cada vez que se realiza una operación de base de datos.
El resto de la clase TodoItemDatabase contiene consultas de SQLite que se ejecutan entre plataformas. Debajo se
muestra el código de ejemplo de consulta (puede encontrar más información sobre la sintaxis en Uso de
SQLite.NET con Xamarin.iOS.
public Task<List<TodoItem>> GetItemsAsync()
{
return database.Table<TodoItem>().ToListAsync();
}
NOTE
La ventaja de usar la API de SQLite.Net asincrónica es que las operaciones de base de datos se mueven a subprocesos en
segundo plano. Además, no es necesario escribir código de control de simultaneidad adicional porque la API se encarga de
ello.
Resumen
Xamarin.Forms admite aplicaciones de base de datos que usan el motor de base de datos de SQLite, lo que
permite cargar y guardar los objetos en código compartido.
Este artículo se centra en el acceso a una base de datos SQLite mediante Xamarin.Forms. Para obtener más
información sobre cómo trabajar con SQLite.Net, vea la documentación de SQLite.NET en Android o SQLite.NET
en iOS.
Vínculos relacionados
Todo Sample (Ejemplo de tareas)
Xamarin.Forms Samples (Ejemplos de Xamarin.Forms)
Xamarin.Forms y servicios de Azure
11/07/2019 • 3 minutes to read • Edit Online
descargar el ejemplo
Una base de datos de documentos de Azure Cosmos DB es una base de datos NoSQL que proporciona acceso de
baja latencia a los documentos JSON, que ofrece un servicio de base de datos rápido, alta disponibilidad y
escalabilidad para aplicaciones que requieren replicación global y escala sin problemas. En este artículo se explica
cómo usar la biblioteca de cliente estándar de .NET de Azure Cosmos DB para integrar una base de datos de
documentos de Azure Cosmos DB en una aplicación de Xamarin.Forms.
Programa de instalación
El proceso para integrar una base de datos de documentos de Azure Cosmos DB en una aplicación de
Xamarin.Forms es como sigue:
1. Cree una cuenta de Cosmos DB. Para obtener más información, consulte crear una cuenta de Azure Cosmos
DB.
2. Agregar el biblioteca de cliente de .NET Standard de Azure Cosmos DB paquete NuGet a los proyectos de
plataforma en la solución de Xamarin.Forms.
3. Agregar using directivas para el Microsoft.Azure.Documents , Microsoft.Azure.Documents.Client , y
Microsoft.Azure.Documents.Linq espacios de nombres a las clases que tendrá acceso a la cuenta de Cosmos DB.
Después de realizar estos pasos, la biblioteca de cliente estándar de .NET de Azure Cosmos DB puede utilizarse
para configurar y ejecutar solicitudes en la base de datos del documento.
NOTE
La biblioteca estándar de .NET de Azure Cosmos DB de cliente solo puede instalarse en los proyectos de plataforma y no en
un proyecto de biblioteca de clases portables (PCL). Por lo tanto, la aplicación de ejemplo es un proyecto de acceso
compartido (SAP) para evitar la duplicación de código. Sin embargo, la DependencyService clase puede usarse en un
proyecto PCL para invocar código de biblioteca de cliente estándar de .NET de Azure Cosmos DB incluido en proyectos
específicos de plataforma.
Deben proporcionarse el Uri de Cosmos DB y la clave principal para el DocumentClient constructor. Estos pueden
obtenerse desde el Portal de Azure. Para obtener más información, consulte conectar a una cuenta de Azure
Cosmos DB.
Creación de una base de datos
Una base de datos de documento es un contenedor lógico para las colecciones de documentos y los usuarios y
puede ser creado en el Portal de Azure, o utilizando mediante programación el
DocumentClient.CreateDatabaseIfNotExistsAsync método:
NOTE
El CreateDatabaseIfNotExistsAsync método devuelve un Task<ResourceResponse<Database>> objeto y el código de
estado de la respuesta pueden comprobarse para determinar si una base de datos se creó o se ha devuelto una base de
datos existente.
NOTE
El CreateDocumentCollectionIfNotExistsAsync método devuelve un Task<ResourceResponse<DocumentCollection>>
objeto y el código de estado de la respuesta pueden comprobarse para determinar si una colección de documentos se creó o
se devuelve una colección de documentos existentes.
IMPORTANT
Tenga en cuenta que el CreateDocumentCollectionIfNotExistsAsync creará una nueva colección con un rendimiento
reservado, lo cual tiene implicaciones de precios.
Esta consulta recupera todos los documentos de la colección especificada asincrónicamente y coloca los
documentos en un List<TodoItem> colección para su presentación.
El CreateDocumentQuery<T> método especifica un Uri argumento que representa la colección que se debe
consultar para los documentos. En este ejemplo, el collectionLink variable es un campo de nivel de clase que
especifica el Uri que representa la colección de documentos para recuperar documentos desde:
Esta consulta recupera todos los documentos de la colección cuya Done es igual a la propiedad false .
Insertar un documento en una colección de documentos
Documentos son contenido JSON de definidos por el usuario y se pueden insertar en una colección de
documentos con el DocumentClient.CreateDocumentAsync método:
El CreateDocumentAsync método especifica un Uri argumento que representa la colección debe insertarse el
documento, y un object argumento que representa el documento que se va a insertar.
Reemplazar un documento en una colección de documentos
Se pueden reemplazar documentos en una colección de documentos con el 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);
...
}
El ReplaceDocumentAsync método especifica un Uri argumento que representa el documento de la colección que
se debe reemplazar, y un object argumento que representa los datos de documento actualizado.
Eliminación de un documento de una colección de documentos
Se puede eliminar un documento de una colección de documentos con el DocumentClient.DeleteDocumentAsync
método:
El DeleteDocumentAsync método especifica un Uri argumento que representa el documento en la colección que se
debe eliminar.
Eliminación de una colección de documentos
Se puede eliminar una colección de documentos de una base de datos con el
DocumentClient.DeleteDocumentCollectionAsync método:
await client.DeleteDocumentCollectionAsync(collectionLink);
await client.DeleteDatabaseAsync(UriFactory.CreateDatabaseUri(Constants.DatabaseName));
El DeleteDatabaseAsync método especifica un Uri argumento que representa la base de datos que va a eliminar.
Tenga en cuenta que al invocar este método también eliminará las colecciones de documentos almacenadas en la
base de datos y los documentos almacenados en las colecciones de documentos.
Resumen
En este artículo se explica cómo usar la biblioteca de cliente estándar de .NET de Azure Cosmos DB para integrar
una base de datos de documentos de Azure Cosmos DB en una aplicación de Xamarin.Forms. Una base de datos
de documentos de Azure Cosmos DB es una base de datos NoSQL que proporciona acceso de baja latencia a los
documentos JSON, que ofrece un servicio de base de datos rápido, alta disponibilidad y escalabilidad para
aplicaciones que requieren replicación global y escala sin problemas.
Vínculos relacionados
Lista de tareas de Azure Cosmos DB (ejemplo)
Documentación de Azure Cosmos DB
Biblioteca de cliente de Azure Cosmos DB .NET Standard
API de Azure Cosmos DB
Enviar y recibir notificaciones push con Azure
Notification Hubs y Xamarin.Forms
11/07/2019 • 29 minutes to read • Edit Online
descargar el ejemplo
Insertar información de entrega de notificaciones desde un sistema back-end en una aplicación móvil. Apple,
Google y otras plataformas tienen su propio servicio de notificación de inserción (PNS ). Azure Notification Hubs le
permiten centralizar las notificaciones entre plataformas para que la aplicación de back-end pueda comunicarse
con un único concentrador, que se encargará de distribuir las notificaciones para cada PNS específicos de la
plataforma.
Integrar Azure Notification Hubs en aplicaciones móviles siguiendo estos pasos:
1. Configurar los servicios de notificaciones Push y Azure Notification Hub.
2. Descubra cómo utilizar etiquetas y plantillas.
3. Crear una aplicación de Xamarin.Forms multiplataforma.
4. Configurar el proyecto nativo de Android para notificaciones de inserción.
5. Configurar el proyecto de iOS nativo para las notificaciones de inserción.
6. Probar las notificaciones mediante el centro de notificaciones de Azure.
7. Crear una aplicación de back-end para enviar notificaciones.
La aplicación de ejemplo contiene un AppConstants.cs archivo, que define propiedades utilizadas por los
proyectos de plataforma. Este archivo debe personalizarse con valores desde el centro de notificaciones de Azure.
El siguiente código muestra la AppConstants.cs archivo:
public static class AppConstants
{
public static string NotificationChannelName { get; set; } = "XamarinNotifyChannel";
public static string NotificationHubName { get; set; } = "< Insert your Azure Notification Hub name >";
public static string ListenConnectionString { get; set; } = "< Insert your
DefaultListenSharedAccessSignature >";
public static string DebugTag { get; set; } = "XamarinNotify";
public static string[] SubscriptionTags { get; set; } = { "default" };
public static string FCMTemplateBody { get; set; } = "{\"data\":{\"message\":\"$(messageParam)\"}}";
public static string APNTemplateBody { get; set; } = "{\"aps\":{\"alert\":\"$(messageParam)\"}}";
}
Personalizar los siguientes valores en AppConstants para conectar la aplicación de ejemplo en el centro de
notificaciones de Azure:
NotificationHubName : Utilice el nombre del centro de notificaciones de Azure que creó en el portal de Azure.
ListenConnectionString : Este valor se encuentra en el centro de notificaciones de Azure en las directivas de
acceso.
Captura de pantalla siguiente se muestra dónde se encuentran estos valores en el portal de Azure:
SendRegistrationToServer(token);
}
// register device with Azure Notification Hub using the token from FCM
Registration reg = hub.Register(token, AppConstants.SubscriptionTags);
if (message.GetNotification() != null)
{
messageBody = message.GetNotification().Body;
}
// NOTE: test messages sent via the Azure portal will be received here
else
{
messageBody = message.Data.Values.First();
}
Los mensajes entrantes se convierten en una notificación local con el SendLocalNotification método. Este método
crea un nuevo Intent y coloca el mensaje contenido en el Intent como un string Extra . Cuando el usuario
pulsa la notificación local, si la aplicación está en primer plano o en segundo plano, el MainActivity se inicia y se
tiene acceso al contenido de mensaje a través de la Intent objeto.
La notificación local y Intent ejemplo requiere que el usuario realizar la acción de puntear en la notificación. Esto
es conveniente cuando el usuario debe tomar medidas antes de los cambios de estado de la aplicación. Sin
embargo, es posible que desee tener acceso a los datos del mensaje sin necesidad de una acción del usuario en
algunos casos. El ejemplo anterior también envía el mensaje directamente a la actual MainPage instancia con el
SendMessageToMainPage método. En producción, si implementa ambos métodos para un tipo de mensaje único, el
MainPage objeto obtendrán los mensajes duplicados si el usuario pulsa la notificación.
NOTE
La aplicación de Android solo recibirá notificaciones de inserción si se está ejecutando en segundo plano o el primer plano.
Para recibir notificaciones de inserción cuando el método main Activity es no se está ejecutando, debe implementar un
servicio, que está fuera del ámbito de este ejemplo. Para obtener más información, consulte crear servicios de Android
base.OnCreate(savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
if (IsPlayServiceAvailable() == false)
{
throw new Exception("This device does not have Google Play Services and cannot receive push
notifications.");
}
CreateNotificationChannel();
}
base.OnNewIntent(intent);
}
bool IsPlayServiceAvailable()
{
int resultCode = GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(this);
if (resultCode != ConnectionResult.Success)
{
if (GoogleApiAvailability.Instance.IsUserResolvableError(resultCode))
Log.Debug(AppConstants.DebugTag, GoogleApiAvailability.Instance.GetErrorString(resultCode));
else
{
Log.Debug(AppConstants.DebugTag, "This device is not supported");
}
return false;
}
return true;
}
}
void CreateNotificationChannel()
{
// Notification channels are new as of "Oreo".
// There is no need to create a notification channel on older versions of Android.
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
var channelName = AppConstants.NotificationChannelName;
var channelDescription = String.Empty;
var channel = new NotificationChannel(channelName, channelName, NotificationImportance.Default)
{
Description = channelDescription
};
El Activity atributo establece la aplicación LaunchMode a SingleTop . Este modo de lanzamiento dice al SO
Android para permitir únicamente una sola instancia de esta actividad. Con este modo de lanzamiento, entrante
Intent datos se enrutan a la OnNewIntent método, que extrae datos del mensaje y lo envía a la MainPage instancia
a través de la AddMessage método. Si la aplicación utiliza un modo de inicio diferente, debe controlar Intent datos
de forma diferente.
El OnCreate método usa un método auxiliar llamado IsPlayServiceAvailable para asegurarse de que el
dispositivo es compatible con Google Play Services. Los emuladores o dispositivos que no son compatibles con
Google Play Services no pueden recibir notificaciones de inserción de Firebase.
base.FinishedLaunching(app, options);
RegisterForRemoteNotifications();
return true;
}
void RegisterForRemoteNotifications()
{
// register for remote notifications based on system version
if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
{
UNUserNotificationCenter.Current.RequestAuthorization(UNAuthorizationOptions.Alert |
UNAuthorizationOptions.Sound |
UNAuthorizationOptions.Sound,
(granted, error) =>
{
if (granted)
InvokeOnMainThread(UIApplication.SharedApplication.RegisterForRemoteNotifications);
});
}
else if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
{
var pushSettings = UIUserNotificationSettings.GetSettingsForTypes(
UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound,
new NSSet());
UIApplication.SharedApplication.RegisterUserNotificationSettings(pushSettings);
UIApplication.SharedApplication.RegisterForRemoteNotifications();
}
else
{
UIRemoteNotificationType notificationTypes = UIRemoteNotificationType.Alert |
UIRemoteNotificationType.Badge | UIRemoteNotificationType.Sound;
UIApplication.SharedApplication.RegisterForRemoteNotificationTypes(notificationTypes);
}
}
var templateExpiration =
DateTime.Now.AddDays(120).ToString(System.Globalization.CultureInfo.CreateSpecificCulture("en-US"));
Hub.RegisterTemplateAsync(deviceToken, "defaultTemplate", AppConstants.APNTemplateBody,
templateExpiration, tags, (errorCallback) =>
{
if (errorCallback != null)
{
if (errorCallback != null)
{
Debug.WriteLine($"RegisterTemplateAsync error: {errorCallback}");
}
}
});
});
}
NOTE
Registrar las notificaciones remotas puede producir errores en situaciones como sin conexión de red. Puede elegir invalidar el
FailedToRegisterForRemoveNotifications método para controlar el error de registro.
if (!string.IsNullOrWhiteSpace(payload))
{
(App.Current.MainPage as MainPage)?.AddMessage(payload);
}
}
else
{
Debug.WriteLine($"Received request to process notification but there was no payload.");
}
}
Debe configurar el DispatcherConstants.cs para que coincida con la configuración del centro de notificaciones de
Azure. El valor de la SubscriptionTags propiedad debe coincidir con los valores utilizados en las aplicaciones
cliente. El propiedad es el nombre de la instancia de centro de notificaciones de Azure. El
NotificationHubName
FullAccessConnectionString propiedad es la clave de acceso se encuentra en el centro de notificaciones las
directivas de acceso. Captura de pantalla siguiente muestra la ubicación de la NotificationHubName y
FullAccessConnectionString propiedades en el portal de Azure:
La aplicación de consola recorre SubscriptionTags de valor y envía notificaciones a los suscriptores mediante una
instancia de la NotificationHubClient clase. El código siguiente muestra la aplicación de consola Program clase:
class Program
{
static int messageCount = 0;
messageCount++;
// Send a template notification to each tag. This will go to any devices that
// have subscribed to this tag with a template that includes "messageParam"
// as a parameter
foreach (var tag in DispatcherConstants.SubscriptionTags)
{
templateParameters["messageParam"] = $"Notification #{messageCount} to {tag} category
subscribers!";
try
{
await hub.SendTemplateNotificationAsync(templateParameters, tag);
Console.WriteLine($"Sent message to {tag} subscribers.");
}
catch (Exception ex)
{
Console.WriteLine($"Failed to send template notification: {ex.Message}");
}
}
Cuando se ejecuta la aplicación de consola de ejemplo, puede presionar la barra espaciadora para enviar mensajes.
Los dispositivos que ejecutan el cliente deben recibir aplicaciones notificaciones numeradas, proporciona están
configurados correctamente.
Vínculos relacionados
Plantillas de notificación de inserción.
Administración de registros de dispositivo.
Enrutamiento y expresiones de etiqueta.
Tutorial de Xamarin.Android Azure Notification Hubs.
Tutorial de Xamarin.iOS Azure Notification Hubs.
Store y acceder a los datos en Azure Storage de
Xamarin.Forms
11/07/2019 • 18 minutes to read • Edit Online
descargar el ejemplo
Azure Storage es una solución de almacenamiento en la nube escalable que puede utilizarse para almacenar
datos estructurados y no estructurados. En este artículo se muestra cómo usar Xamarin.Forms para almacenar
datos binarios y texto en el almacenamiento de Azure y cómo tener acceso a los datos.
Azure Storage proporciona cuatro servicios de almacenamiento:
Almacenamiento de blobs. Un blob puede ser texto o datos binarios, como las copias de seguridad, las
máquinas virtuales, archivos multimedia o documentos.
Table Storage es un almacén de clave-atributo NoSQL.
Queue Storage es un servicio de mensajería para el procesamiento de flujo de trabajo y comunicación entre
servicios en la nube.
Almacenamiento de archivos ofrece almacenamiento compartido mediante el protocolo SMB.
Hay dos tipos de cuentas de almacenamiento:
Una cuenta de almacenamiento de uso general proporciona acceso a servicios de Azure Storage desde una sola
cuenta.
Una cuenta de almacenamiento de Blob es una cuenta de almacenamiento especializada para almacenar blobs.
Se recomienda este tipo de cuenta cuando necesite almacenar los datos blob.
En este artículo y que acompaña a la aplicación de ejemplo muestra cómo cargar archivos de texto e imágenes a
blob storage y descargarlos. Además, también se muestra al recuperar una lista de archivos desde blob storage y
eliminar archivos.
Para obtener más información sobre el almacenamiento de Azure, consulte Introducción al almacenamiento.
NOTE
Tenga en cuenta que las cuentas de almacenamiento de blobs admiten bloques y anexar blobs, pero no los blobs en páginas.
Un blob se carga en Azure Storage y descargado de Azure Storage, como una secuencia de bytes. Por lo tanto, los
archivos se deben convertir en una secuencia de bytes antes de la carga y convertido de nuevo a su representación
original después de la descarga.
Cada objeto que se almacena en el almacenamiento de Azure tiene una dirección URL única. El nombre de cuenta
de almacenamiento forma el subdominio de esa dirección y la combinación de nombre de dominio y subdominio
forms un extremo para la cuenta de almacenamiento. Por ejemplo, si la cuenta de almacenamiento se denomina
mystorageaccount, el extremo de blob predeterminado para la cuenta de almacenamiento es
https://mystorageaccount.blob.core.windows.net .
La dirección URL para tener acceso a un objeto en una cuenta de almacenamiento se crea anexando la ubicación
del objeto en la cuenta de almacenamiento para el punto de conexión. Por ejemplo, una dirección de blob tendrá el
formato https://mystorageaccount.blob.core.windows.net/mycontainer/myblob .
Programa de instalación
El proceso para integrar una cuenta de almacenamiento de Azure en una aplicación de Xamarin.Forms es como
sigue:
1. Cree una cuenta de almacenamiento. Para obtener más información, consulte crear una cuenta de
almacenamiento.
2. Agregar el biblioteca de cliente de Azure Storage a la aplicación de Xamarin.Forms.
3. Configurar la cadena de conexión de almacenamiento. Para obtener más información, consulte conectarse a
Azure Storage.
4. Agregar using directivas para el Microsoft.WindowsAzure.Storage y Microsoft.WindowsAzure.Storage.Blob
espacios de nombres a las clases que tendrá acceso a Azure Storage.
NOTE
Azure Storage admite HTTP y HTTPS en una cadena de conexión. Sin embargo, se recomienda utilizar HTTPS.
UseDevelopmentStorage=true
Para obtener más información sobre el emulador de almacenamiento de Azure, consulte usar el emulador de
almacenamiento de Azure para desarrollo y pruebas.
Conectarse a Azure Storage mediante una clave compartida
El siguiente formato de cadena de conexión se debe usar para conectarse a Azure Storage con una clave
compartida:
DefaultEndpointsProtocol=[http|https];AccountName=myAccountName;AccountKey=myAccountKey
NOTE
Uso compartido cuando la autenticación de clave, el nombre de cuenta y la clave de cuenta se distribuirá a cada persona que
usa la aplicación, que proporcionará acceso de lectura/escritura completo a la cuenta de almacenamiento. Por lo tanto, use la
autenticación de clave compartida solo con fines de prueba y nunca distribuir claves a otros usuarios.
myBlobEndpoint debe reemplazarse por la dirección URL del extremo de blob, y mySharedAccessSignature debe
reemplazarse por la SAS. La SAS proporciona el protocolo, el punto de conexión de servicio y las credenciales
para acceder al recurso.
NOTE
Se recomienda la autenticación de SAS para aplicaciones de producción. Sin embargo, en una aplicación de producción se
debe recuperar la SAS de un servicio back-end a petición, en lugar de que se incluye con la aplicación.
Para obtener más información sobre las firmas de acceso compartido, consulte utilizando firmas de acceso
compartido (SAS ).
Creación de un contenedor
El GetContainer método se usa para recuperar una referencia a un contenedor con nombre, que puede usarse
para recuperar los blobs del contenedor o a agregar al contenedor de blobs. El siguiente ejemplo de código
muestra la GetContainer método:
NOTE
Los nombres de contenedor deben estar en minúsculas y deben empezar por una letra o un número. Además, solo puede
contener letras, números y guiones y debe tener entre 3 y 63 caracteres.
El CloudBlobContainer instancia, a continuación, se puede usar para crear un contenedor si aún no existe:
await container.CreateIfNotExistsAsync();
De forma predeterminada, un contenedor recién creado es privado. Esto significa que se debe especificar una clave
de acceso de almacenamiento para recuperar los blobs del contenedor. Para obtener información acerca de cómo
realizar los blobs dentro de un público de contenedor, consulte crear un contenedor.
return name;
}
Después de recuperar una referencia de contenedor, el método crea el contenedor si aún no existe. Un nuevo Guid
, a continuación, se crea para que actúe como un nombre de blob único y una referencia de blob en bloques se
recupera como una CloudBlockBlob instancia. El flujo de datos, a continuación, se carga en el blob mediante el
UploadFromStreamAsync método, que crea el blob si todavía no existe o lo sobrescribe si ya existe.
Antes de poder cargar un archivo con este método de almacenamiento de blobs, primero debe convertirse en una
secuencia de bytes. Esto se muestra en el ejemplo de código siguiente:
El datos se convierten en una matriz de bytes que se encapsula como una secuencia que se pasa a la
text
UploadFileAsync método.
Después de recuperar una referencia de contenedor, el método recupera una referencia de blob para los datos
almacenados. Si existe el blob, sus propiedades se recuperan mediante el FetchAttributesAsync método. Se crea
una matriz de bytes del tamaño correcto y se descarga el blob como una matriz de bytes que se devuelve al
método de llamada.
Después de descargar los datos de blob de bytes, deben convertirse en su representación original. Esto se muestra
en el ejemplo de código siguiente:
var byteData = await AzureStorage.GetFileAsync(ContainerType.Text, uploadedFilename);
string text = Encoding.UTF8.GetString(byteData);
Se recupera la matriz de bytes de almacenamiento de Azure mediante el GetFileAsync método antes de que se
convierta a un UTF8 cadena codificada.
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;
}
Después de recuperar una referencia de contenedor, el método recupera una referencia de blob para el blob
especificado. A continuación, se elimina el blob con el DeleteIfExistsAsync método.
Vínculos relacionados
Almacenamiento de Azure (ejemplo)
Introducción al almacenamiento
Cómo usar Blob Storage desde Xamarin
Uso de firmas de acceso compartido (SAS )
Windows Azure Storage (NuGet)
Buscar datos con Azure Search y Xamarin.Forms
11/07/2019 • 20 minutes to read • Edit Online
descargar el ejemplo
Azure Search es un servicio en la nube que proporciona la indización y consulta las capacidades de los datos
cargados. Esto quita los requisitos de infraestructura y la complejidad de algoritmo de búsqueda tradicionalmente
asociada con la implementación de la funcionalidad de búsqueda en una aplicación. En este artículo se muestra
cómo usar la biblioteca de Microsoft Azure Search para integrar la búsqueda de Azure en una aplicación de
Xamarin.Forms.
Información general
Los datos se almacenan en Azure Search como índices y documentos. Un índice es un almacén de datos que se
pueden buscar por el servicio Azure Search y es conceptualmente similar a una tabla de base de datos. Un
documento es una unidad única de datos en un índice de búsqueda y es conceptualmente similar a una fila de la
base de datos. Al cargar los documentos y enviar las consultas de búsqueda para Azure Search, las solicitudes se
realizan en un índice específico en el servicio de búsqueda.
Cada solicitud realizada a Azure Search debe incluir el nombre del servicio y una clave de API. Hay dos tipos de
clave de API:
Las claves de administración conceder derechos completos para todas las operaciones. Esto incluye la
administración del servicio, crear y eliminar orígenes de datos y los índices.
Claves de consulta conceder acceso de solo lectura a índices y documentos y debe usarse en aplicaciones que
emiten solicitudes de búsqueda.
La solicitud más comunes para Azure Search es ejecutar una consulta. Hay dos tipos de consulta que se pueden
enviar:
Un búsqueda consulta busca uno o más elementos en todos los campos de búsqueda en un índice. Las
consultas de búsqueda se crean con la sintaxis simplificada, o la sintaxis de consulta de Lucene. Para obtener
más información, consulte sintaxis de consulta Simple en Azure Search, y sintaxis de consulta de Lucene en
Azure Search.
Un filtro consulta evalúa una expresión booleana en todos los campos filtrables de un índice. Filtrar las
consultas se crean con un subconjunto del lenguaje de filtro de OData. Para obtener más información, consulte
sintaxis de expresiones de OData para Azure Search.
Las consultas de búsqueda y filtrar las consultas pueden utilizarse por separado o conjuntamente. Cuando se usan
juntas, la consulta de filtro se aplica primero a todo el índice y, a continuación, se realiza la consulta de búsqueda en
los resultados de la consulta de filtro.
Azure Search también admite recuperar sugerencias basadas en la entrada de búsqueda. Para obtener más
información, consulte sugerencia consultas.
Programa de instalación
El proceso de integración de Azure Search en una aplicación de Xamarin.Forms es como sigue:
1. Crear un servicio Azure Search. Para obtener más información, consulte crear un servicio de Azure Search
mediante el Portal de Azure.
2. Quitar Silverlight como una plataforma de destino de la biblioteca de clases portables (PCL ) de la solución de
Xamarin.Forms. Esto puede realizarse al cambiar el perfil PCL a cualquier perfil que admite el desarrollo
multiplataforma, pero no es compatible con Silverlight, como el perfil de 151 o 92.
3. Agregar el biblioteca de Microsoft Azure Search paquete NuGet al proyecto PCL en la solución de
Xamarin.Forms.
Después de realizar estos pasos, la API de biblioteca de Microsoft Search puede usarse para administrar los
orígenes de datos y los índices de búsqueda, cargar y administrar documentos y ejecutar consultas.
var searchClient =
new SearchServiceClient(Constants.SearchServiceName, new SearchCredentials(Constants.AdminApiKey));
NOTE
Una sola SearchServiceClient instancia debe utilizarse en una aplicación para evitar que se abra demasiadas conexiones a
Azure Search.
Un índice está definido por el Index de objeto, como se muestra en el ejemplo de código siguiente:
searchClient.Indexes.Create(index);
}
El Index.Name propiedad debe establecerse en el nombre del índice y el Index.Fields propiedad debe
establecerse en una matriz de Field objetos. Cada Field instancia especifica un nombre, un tipo y las
propiedades, que especifican cómo se usa el campo. Estas propiedades incluyen:
IsKey : indica si el campo es la clave del índice. Solo un campo en el índice de tipo DataType.String , debe
designarse como campo de clave.
IsFacetable : indica si es posible llevar a cabo la navegación por facetas en este campo. El valor
predeterminado es false .
IsFilterable : indica si el campo se puede usar en las consultas de filtro. El valor predeterminado es false .
IsRetrievable : indica si se puede recuperar el campo en los resultados de búsqueda. El valor predeterminado
es true .
IsSearchable : indica si el campo está incluido en las búsquedas de texto completo. El valor predeterminado es
false .
IsSortable : indica si el campo se puede utilizar en OrderBy expresiones. El valor predeterminado es false .
NOTE
Cambio de un índice después de su implementación implica volver a generar y volver a cargar los datos.
Un Index objeto opcionalmente, puede especificar un Suggesters propiedad, que define los campos en el índice
que se usará para admitir Autocompletar o sugerencia consultas de búsqueda. El Suggesters propiedad debe
establecerse en una matriz de Suggester objetos que definen los campos que se utilizan para generar resultados
de la sugerencia de la búsqueda.
Después de crear el Index objeto, el índice se crea mediante una llamada a Indexes.Create en el
SearchServiceClient instancia.
NOTE
Al crear un índice de una aplicación que debe mantenerse con capacidad de respuesta, use el Indexes.CreateAsync
método.
Para obtener más información, consulte crear un índice de Azure Search mediante el SDK de .NET.
searchClient.Indexes.Delete(Constants.Index);
Datos que se importarán en el índice se empaquetan como un IndexBatch objeto, que encapsula una colección de
IndexAction objetos. Cada IndexAction instancia contiene un documento y una propiedad que indica qué acción
va a realizar en el documento de Azure Search. En el ejemplo de código anterior, el IndexAction.Upload acción que
se especifica, los resultados en el documento que se inserta en el índice si es nuevo, o reemplaza si ya existe. El
IndexBatch objeto, a continuación, se envía al índice mediante una llamada a la Documents.Index método en el
SearchIndexClient objeto. Para obtener información acerca de otras acciones de indexación, consulte decidir qué
acción de indexación para usar.
NOTE
Solo 1000 documentos pueden incluirse en una única solicitud de indexación.
Tenga en cuenta que en el ejemplo de código anterior, el monkeyList colección se crea como un objeto anónimo de
una colección de Monkey objetos. Esto crea los datos para el id campo y se resuelve como la asignación de
mayúsculas y minúsculas Pascal Monkey los nombres de campo de índice de búsqueda de nombres de propiedad
a mayúsculas y minúsculas. Como alternativa, esta asignación también puede realizarse agregando el
[SerializePropertyNamesAsCamelCase] atributo a la Monkey clase.
Para obtener más información, consulte cargar datos en Azure Search mediante el SDK de .NET.
El SearchIndexClient sobrecarga de constructor toma un nombre de servicio de búsqueda, el nombre del índice y
un SearchCredentials objeto como argumentos, con el SearchCredentials ajuste objeto el clave de consulta para
el servicio Azure Search.
Consultas de búsqueda
El índice se puede consultar mediante una llamada a la Documents.SearchAsync método en el SearchIndexClient de
instancia, tal como se muestra en el ejemplo de código siguiente:
Esta consulta de filtro se aplica a todo el índice y quita los documentos de los resultados donde el location campo
no es igual a China y no es igual a Vietnam. Después de filtrado, la consulta de búsqueda se realiza en los
resultados de la consulta de filtro.
NOTE
Para filtrar sin buscar, pasar * como el argumento de texto de búsqueda.
El SearchAsync método devuelve un DocumentSearchResult objeto que contiene los resultados de consulta. Este
objeto es de tipo enumerado con cada Document objeto se crea como un Monkey de objetos y agregado a la
Monkeys ObservableCollection para su presentación. Los siguientes capturas de pantalla show consulta resultados
de búsqueda de Azure Search:
Para obtener más información acerca de la búsqueda y filtrado, consulte consultas del índice de Azure Search con
el SDK de .NET.
Consultas de sugerencia
Azure Search permite a las sugerencias que se soliciten basándose en una consulta de búsqueda, mediante una
llamada a la Documents.SuggestAsync método en el SearchIndexClient instancia. Esto se muestra en el ejemplo de
código siguiente:
async Task AzureSuggestions(string text)
{
Suggestions.Clear();
var suggestionResults =
await indexClient.Documents.SuggestAsync<Monkey>(text, "nameSuggester", parameters);
El SuggestAsync método toma un argumento de texto de búsqueda, el nombre del proveedor de sugerencias para
usar (que se define en el índice), y un elemento opcional SuggestParameters objeto que se puede usar para refinar
la consulta. El SuggestParameters instancia establece las propiedades siguientes:
UseFuzzyMatching : cuando se establece en true , Azure Search encontrará sugerencias incluso si hay un
carácter sustituido o no encontrado en el texto de búsqueda.
HighlightPreTag : la etiqueta a la que se antepone a resultados de la sugerencia.
HighlightPostTag : la etiqueta a la que se anexa a la sugerencia de visitas.
MinimumCoverage : representa el porcentaje del índice que debe estar cubierto por una consulta de sugerencia
para la consulta notifica un estado correcto. El valor predeterminado es 80.
Top : el número de sugerencias para recuperar. Debe ser un entero entre 1 y 100, con un valor predeterminado
de 5.
El efecto general es que se devolverán los primeros 10 resultados del índice con resaltado de referencias y los
resultados incluirán documentos que contengan los términos de búsqueda de la ortografía del mismo modo.
El SuggestAsync método devuelve un DocumentSuggestResult objeto que contiene los resultados de consulta. Este
objeto es de tipo enumerado con cada Document objeto se crea como un Monkey de objetos y agregado a la
Monkeys ObservableCollection para su presentación. Las capturas de pantalla siguientes muestran los resultados
de sugerencia obtenidos de Azure Search:
Tenga en cuenta que en la aplicación de ejemplo, el SuggestAsync método solo se invoca cuando el usuario
termina de escribir un término de búsqueda. Sin embargo, también puede usarse para admitir las consultas de
búsqueda de autocompletado ejecutando en cada keypress.
Resumen
En este artículo se muestra cómo usar la biblioteca de Microsoft Azure Search para integrar la búsqueda de Azure
en una aplicación de Xamarin.Forms. Azure Search es un servicio en la nube que proporciona la indización y
consulta las capacidades de los datos cargados. Esto quita los requisitos de infraestructura y la complejidad de
algoritmo de búsqueda tradicionalmente asociada con la implementación de la funcionalidad de búsqueda en una
aplicación.
Vínculos relacionados
Búsqueda de Azure (ejemplo)
Documentación de Azure Search
Biblioteca de Microsoft Azure Search
Introducción a Azure Functions
11/07/2019 • 2 minutes to read • Edit Online
descargar el ejemplo
Comience a crear su primera función de Azure que interactúa con Xamarin.Forms.
Visual Studio 2019
Visual Studio 2017
Visual Studio para Mac
Vínculos relacionados
Documentos de Azure Functions
Implementación de una simple función de Azure con un cliente de Xamarin.Forms (ejemplo)
Azure SignalR Service con Xamarin.Forms
11/07/2019 • 19 minutes to read • Edit Online
descargar el ejemplo
ASP.NET Core SignalR es un modelo de aplicación que simplifica el proceso de incorporación de comunicación en
tiempo real a las aplicaciones. Azure SignalR Service permite el rápido desarrollo e implementación de
aplicaciones escalables de SignalR. Las funciones de Azure son los métodos de código sin servidor y de corta
duración que se pueden combinar con aplicaciones de forma escalable, controlado por eventos.
Este artículo y el ejemplo muestran cómo combinar Azure SignalR Service y Azure Functions con Xamarin.Forms,
para entregar mensajes en tiempo real a los clientes conectados.
NOTE
El Negotiate y hablar funciones en la aplicación de ejemplo se pueden ejecutar localmente mediante Visual Studio de 2019
y las herramientas de Azure en tiempo de ejecución. Sin embargo, no se emula localmente Azure SignalR Service y resulta
difícil exponer hospedados localmente Azure Functions a dispositivos físicos o virtuales para las pruebas. Se recomienda
implementar las funciones de Azure a una instancia de la aplicación de Azure Functions, ya que esto permite que las pruebas
multiplataforma. Para obtener detalles de implementación, consulte implementar Azure Functions con Visual Studio de 2019.
Esta cadena de conexión se usa para implementar Azure Functions con Visual Studio de 2019.
Crear una aplicación de Azure Functions
Para probar la aplicación de ejemplo, debe crear una nueva aplicación de Azure Functions en Azure portal. Tome
nota de la nombre de la aplicación como esta dirección URL se utiliza en la aplicación de ejemplo Constants.cs
archivo. Captura de pantalla siguiente muestra la creación de una nueva aplicación de las funciones de Azure
denominado "xdocsfunctions":
Las funciones de Azure pueden implementarse en una instancia de la aplicación de Azure Functions de Visual
Studio de 2019. Las secciones siguientes describen la implementación de dos funciones en la aplicación de
ejemplo a una instancia de la aplicación de Azure Functions.
Crear Azure Functions en Visual Studio de 2019
La aplicación de ejemplo contiene una biblioteca de clases denominada ChatServer, que incluye dos funciones de
Azure sin servidor en archivos denominados Negotiate.cs y Talk.cs.
El Negotiatefunción responde a solicitudes web con un SignalRConnectionInfo objeto que contiene un
AccessToken propiedad y un Url propiedad. La aplicación móvil usa estos valores para registrarse con el centro
de SignalR. El código siguiente muestra el Negotiate función:
[FunctionName("Negotiate")]
public static SignalRConnectionInfo GetSignalRInfo(
[HttpTrigger(AuthorizationLevel.Anonymous,"get",Route = "negotiate")]
HttpRequest req,
[SignalRConnectionInfo(HubName = "simplechat")]
SignalRConnectionInfo connectionInfo)
{
return connectionInfo;
}
El Talk función responde a las solicitudes de HTTP POST que proporcionan un objeto de mensaje en el cuerpo
de POST. El cuerpo de POST se transforma en un SignalRMessage y se reenvía al centro de SignalR. El código
siguiente muestra el Talk función:
[FunctionName("Talk")]
public static async Task<IActionResult> Run(
[HttpTrigger(
AuthorizationLevel.Anonymous,
"post",
Route = "talk")]
HttpRequest req,
[SignalR(HubName = "simplechat")]
IAsyncCollector<SignalRMessage> questionR,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
try
{
string json = await new StreamReader(req.Body).ReadToEndAsync();
dynamic obj = JsonConvert.DeserializeObject(json);
await questionR.AddAsync(
new SignalRMessage
{
Target = "newMessage",
Arguments = new[] { jObject }
});
Para obtener más información acerca de las funciones de Azure y Azure Functions Apps, consulte documentación
de Azure Functions.
Implementación de Azure Functions con Visual Studio de 2019
2019 de Visual Studio le permite implementar las funciones en una aplicación de Azure Functions. Hospedado en
Azure functions facilitan las pruebas multiplataforma al proporcionar un punto de conexión de prueba accesible
para todos los dispositivos.
Haciendo clic en la aplicación de las funciones de ejemplo y elegir publicar inicia el cuadro de diálogo para
publicar las funciones en la aplicación de Azure Functions. Si ha seguido los pasos anteriores para configurar una
aplicación de función de Azure, puede elegir seleccionar existente para publicar las aplicaciones de ejemplo para
la aplicación de Azure Functions. Captura de pantalla siguiente muestra la publicación opciones del cuadro de
diálogo en Visual Studio de 2019:
Una vez que haya iniciado sesión con tu cuenta Microsoft, puede buscar y elegir la aplicación de Azure Functions
como el destino de publicación. Captura de pantalla siguiente muestra un ejemplo de aplicación de Azure
Functions en el cuadro de diálogo de publicación de Visual Studio de 2019:
Después de seleccionar una aplicación de Azure Functions se muestran la instancia, la dirección URL del sitio,
configuración y otra información sobre el destino de la aplicación de Azure Functions. Elija editar la
configuración de Azure App Service y escriba la cadena de conexión en el remoto campo. La cadena de
conexión está usando el Negotiate y hablar funciones para conectarse a Azure SignalR Service y está disponible
en el claves sección de Azure SignalR Servicio en el portal de Azure. Para obtener más información acerca de la
cadena de conexión, consulte crear un servicio de Azure SignalR .
Una vez haya escrito la cadena de conexión, haga clic en publicar para implementar las funciones a la aplicación
de Azure Functions. Una vez que haya finalizado, se enumerarán las funciones en la aplicación de Azure Functions
en Azure portal. Captura de pantalla siguiente muestra las funciones publicadas en el portal de Azure:
Integrar el servicio Azure SignalR con Xamarin.Forms
La integración entre Azure SignalR Service y la aplicación de Xamarin.Forms es una clase de servicio de SignalR
que se crea una instancia en el MainPage clase con controladores de eventos asignados a los tres eventos. Para
obtener más información acerca de estos controladores de eventos, consulte utilizar la clase de servicio de SignalR
en Xamarin.Forms.
La aplicación de ejemplo incluye un Constants.cs clase que debe personalizarse con el punto de conexión de
dirección URL de la aplicación de Azure Functions. Establezca el valor de la HostName propiedad a su dirección de
la aplicación de Azure Functions. El siguiente código muestra la Constants.cs propiedades con un ejemplo
HostName valor:
NOTE
El Username propiedad en la aplicación de ejemplo Constants.cs archivo utiliza el dispositivo RuntimePlatform valor como
el nombre de usuario. Esto facilita probar dispositivos entre plataformas e identificar qué dispositivo está enviando el
mensaje. En una aplicación real, este valor sería un nombre de usuario único, recopilados durante un inicio de sesión de
seguridad o inicie sesión en proceso.
IsBusy = false;
}
El ConnectAsync método en el SignalRService clase realiza una solicitud HTTP GET a la Negotiate función
hospedado en la aplicación de Azure Functions. El Negotiate función devuelve JSON que se deserializa en una
instancia de la NegotiateInfo clase. Una vez el NegotiateInfo se recupera el objeto, se usa para registrar
directamente con Azure SignalR Service mediante una instancia de la HubConnection clase.
SignalR de ASP.NET Core traduce los datos de entrada de la conexión abierta en mensajes y permite a los
desarrolladores definir tipos de mensajes y enlazar controladores de eventos a los mensajes entrantes por tipo. El
ConnectAsync método registra un controlador de eventos para el nombre de mensaje definido en la aplicación de
ejemplo Constants.cs archivo, que es "newMessage" de forma predeterminada.
En el código siguiente se muestra el método ConnectAsync :
connection.On<JObject>(Constants.MessageName, AddNewMessage);
await connection.StartAsync();
IsConnected = true;
IsBusy = false;
El AddNewMessage método se enlaza como el controlador de eventos en el ConnectAsync del mensaje como se
muestra en el código anterior. Cuando se recibe un mensaje, el AddNewMessage se llama al método con los datos del
mensaje proporcionados como un JObject . El AddNewMessage método convierte el JObject a una instancia de la
Message clase y, a continuación, invoca el controlador para NewMessageReceived si uno se ha enlazado. En el código
siguiente se muestra el método AddNewMessage :
NewMessageReceived?.Invoke(this, messageModel);
}
El Connected eventos en el SignalRService clase se desencadena cuando una conexión SignalR se completó
correctamente. El ConnectionFailed eventos en el SignalRService clase se desencadena cuando se produce un
error en una conexión de SignalR. El SignalR_ConnectionChanged está enlazado el método controlador de eventos
para eventos en el MainPage constructor. Este controlador de eventos actualiza los Estados del botón Conectar y
envío basándose en la conexión success argumento y agrega el mensaje proporcionado por el evento a la cola de
chat mediante el AddMessage método. El código siguiente muestra el SignalR_ConnectionChanged método
controlador de eventos:
El AddMessage método agrega un nuevo mensaje como un Label objeto a la cola de chat. El AddMessage método
se suele denominar los controladores de eventos desde fuera el subproceso principal de la interfaz de usuario, por
lo que obliga a las actualizaciones de la interfaz de usuario que se produzca en el subproceso principal para evitar
excepciones. En el código siguiente se muestra el método AddMessage :
void AddMessage(string message)
{
Device.BeginInvokeOnMainThread(() =>
{
Label label = new Label
{
Text = message,
HorizontalOptions = LayoutOptions.Start,
VerticalOptions = LayoutOptions.Start
};
messageList.Children.Add(label);
});
}
Probar la aplicación
Puede probar la aplicación de chat de SignalR en iOS, Android y UWP siempre que tenga:
1. Crea un servicio de Azure SignalR.
2. Crea una aplicación de Azure Functions.
3. Personalizar el Constants.cs archivo con el punto de conexión de la aplicación de Azure Functions.
Una vez completados estos pasos y se ejecuta la aplicación, haga clic en el Connect botón forma una conexión con
Azure SignalR Service. Escribe un mensaje y haga clic en el enviar resultados de botón en mensajes que aparecen
en la cola de chat en cualquier conectado aplicaciones móviles.
Vínculos relacionados
Creación de aplicaciones móviles en tiempo real con Xamarin y SignalR
Introducción a SignalR
Introducción a Azure Functions
Documentación de Azure Functions
Ejemplo de chat de SignalR MVVM
Xamarin.Forms y Azure Cognitive Services
11/07/2019 • 2 minutes to read • Edit Online
Introducción
Microsoft Cognitive Services son un conjunto de API, SDK y servicios disponibles para los desarrolladores para
que sus aplicaciones más inteligentes mediante la adición de características como reconocimiento facial,
reconocimiento de voz y comprensión del lenguaje. En este artículo se proporciona una introducción a la aplicación
de ejemplo que muestra cómo invocar algunas de las API de Microsoft Cognitive Service desde las aplicaciones de
Xamarin.Forms.
Reconocimiento de voz
Microsoft Speech API es una API basada en la nube que proporciona algoritmos para procesar el lenguaje oral. En
este artículo se explica cómo usar la API de REST de reconocimiento de voz de Microsoft para convertir audio en
texto en una aplicación de Xamarin.Forms.
Corrector ortográfico
Bing Spell Check realiza contextual corrector ortográfico para el texto, que proporciona sugerencias de en línea
para palabras mal escritas. En este artículo se explica cómo usar Bing Spell Check REST API para corregir errores
ortográficos en una aplicación de Xamarin.Forms.
Traducción de texto
Microsoft Translator API puede usarse para traducir el texto de voz y a través de una API de REST. En este artículo
se explica cómo usar Microsoft Translator Text API para traducir texto de un idioma a otro en una aplicación de
Xamarin.Forms.
Reconocimiento de emociones
Face API toma una expresión facial de una imagen como entrada y devuelve los datos que incluyen los niveles de
confianza a través de un conjunto de emociones para cada cara de la imagen. En este artículo se explica cómo usar
Face API para que reconozca las emociones para evaluar una aplicación de Xamarin.Forms.
Introducción a Cognitive Services Xamarin.Forms y
Azure
11/07/2019 • 10 minutes to read • Edit Online
descargar el ejemplo
Microsoft Cognitive Services son un conjunto de API, SDK y servicios disponibles para los desarrolladores para
que sus aplicaciones más inteligentes mediante la adición de características como reconocimiento facial,
reconocimiento de voz y comprensión del lenguaje. En este artículo se proporciona una introducción a la
aplicación de ejemplo que muestra cómo invocar algunas de las API de Microsoft Cognitive Service.
Información general
El ejemplo adjunto es una aplicación de lista de tareas que proporciona funcionalidad para:
Ver una lista de tareas.
Agregar y editar tareas mediante el teclado en pantalla, o bien al realizar el reconocimiento de voz con la API de
voz de Microsoft. Para obtener más información acerca de cómo realizar el reconocimiento de voz, consulte
reconocimiento de voz con la API de Microsoft Speech.
Revisión ortográfica con Bing Spell Check API de tareas de comprobación. Para obtener más información,
consulte ortográfica con Bing Spell Check API.
Traducir las tareas del inglés al alemán mediante la API del traductor. Para obtener más información, consulte
traducción de texto mediante la API del traductor.
Eliminar las tareas.
Establece el estado de una tarea a 'listo'.
Valore la aplicación con reconocimiento de emociones, mediante Face API. Para obtener más información,
consulte mediante Face API de reconocimiento de emociones.
Las tareas se almacenan en una base de datos SQLite local. Para obtener más información sobre el uso de una
base de datos SQLite local, consulte trabajar con una base de datos Local.
El TodoListPage se muestra cuando se inicia la aplicación. Esta página muestra una lista de las tareas que se
almacenan en la base de datos local y permite al usuario para crear una nueva tarea o para clasificar la solicitud:
Se pueden crear nuevos elementos, haga clic en el + botón, que se desplaza a la TodoItemPage . Esta página
también se puede navegar a seleccionando una tarea:
El TodoItemPage permite crear, editar, revisar, tareas traducido, se guardan y se eliminan. El reconocimiento de voz
se puede usar para crear o editar una tarea. Esto se logra al presionar el botón de micrófono para iniciar la
grabación y presionando el botón mismo una segunda vez para detener la grabación, que envía la grabación a la
API de reconocimiento de voz de Bing.
Al hacer clic en el botón emoticones en el TodoListPage navega a la RateAppPage , que se usa para realizar el
reconocimiento de emociones en una imagen de una expresión facial:
El RateAppPage permite al usuario tomar una foto de su cara, que se envía a Face API con la emoción devuelta que
se muestran.
CARPETA PROPÓSITO
Servicios Contiene las interfaces y clases que se usan para tener acceso
a diferentes Microsoft Cognitive Service APIs, junto con
interfaces que se usan por el DependencyService clase para
buscar las clases que implementan las interfaces en los
proyectos de plataforma.
ARCHIVO PROPÓSITO
Paquetes NuGet
La aplicación de ejemplo usa los siguientes paquetes NuGet:
Newtonsoft.Json : proporciona un marco JSON para. NET.
PCLStorage : proporciona un conjunto de archivos local las API de E/S de multiplataforma.
sqlite-net-pcl : proporciona almacenamiento de base de datos de SQLite.
Xam.Plugin.Media : proporciona las API de selección y toma de fotografía de multiplataforma.
El ID propiedad se utiliza para identificar de forma única cada TodoItem de instancia y está decorado con
atributos de SQLite que hacen que la propiedad de una clave principal de incremento automático de la base de
datos.
Invocar operaciones de base de datos
El TodoItemRepository clase implementa las operaciones de base de datos y una instancia de la clase se puede
acceder mediante el App.TodoManager propiedad. La TodoItemRepository clase proporciona los métodos siguientes
para invocar operaciones de base de datos:
GetAllItemsAsync : recupera todos los elementos de la base de datos SQLite local.
GetItemAsync : recupera un elemento especificado de la base de datos SQLite local.
SaveItemAsync : crea o actualiza un elemento de la base de datos SQLite local.
DeleteItemAsync : elimina el elemento especificado de la base de datos SQLite local.
Implementaciones de proyecto de plataforma
El Services carpeta en el proyecto de código compartido contiene la IFileHelper y IAudioRecorderService
interfaces que se usan por el DependencyService clase para buscar las clases que implementan las interfaces en los
proyectos de plataforma.
El IFileHelper interfaz se implementa mediante el FileHelper clase en cada proyecto de la plataforma. Esta clase
consta de un único método, GetLocalFilePath , que devuelve una ruta de acceso local para almacenar la base de
datos de SQLite.
El IAudioRecorderService interfaz se implementa mediante el AudioRecorderService clase en cada proyecto de la
plataforma. Esta clase consta de StartRecording , StopRecording y que admiten métodos, que use las API de
plataforma para grabar audio desde el micrófono del dispositivo y almacenan como un archivo wav. En iOS, el
AudioRecorderService usa el AVFoundation API para grabar audio. En Android, el AudioRecordService usa el
AudioRecord API para grabar audio. En la plataforma Universal de Windows ( UWP ), el AudioRecorderService usa
el AudioGraph API para grabar audio.
Invocar servicios cognitivos
La aplicación de ejemplo invoca los servicios cognitivos de Microsoft siguiente:
Microsoft Speech API. Para obtener más información, consulte reconocimiento de voz con la API de Microsoft
Speech.
Bing Spell Check API. Para obtener más información, consulte ortográfica con Bing Spell Check API.
Traducir API. Para obtener más información, consulte traducción de texto mediante la API del traductor.
Face API. Para obtener más información, consulte mediante Face API de reconocimiento de emociones.
Vínculos relacionados
Documentación de Microsoft Cognitive Services
Todo Cognitive Services (ejemplo)
Reconocimiento de voz con la API de Microsoft
Speech
11/07/2019 • 9 minutes to read • Edit Online
descargar el ejemplo
Microsoft Speech API es una API basada en la nube que proporciona algoritmos para procesar el lenguaje oral.
En este artículo se explica cómo usar la API de REST de reconocimiento de voz de Microsoft para convertir audio
en texto en una aplicación de Xamarin.Forms.
Información general
Microsoft Speech API tiene dos componentes:
Un reconocimiento de voz API para convertir las palabras habladas en texto. El reconocimiento de voz puede
realizarse a través de una API de REST, la biblioteca de cliente o la biblioteca de servicio.
Un texto a voz API para convertir texto en palabras habladas. Conversión de texto a voz se realiza a través de
una API de REST.
En este artículo se centra en realizar el reconocimiento de voz a través de la API de REST. Mientras que las
bibliotecas de cliente y el servicio admiten la devolución de resultados parciales, la API de REST solo puede
devolver un resultado de reconocimiento único, sin los resultados parciales.
Para usar la API de voz de Microsoft, se debe obtener una clave de API. Esto se puede obtener desde Azure
portal. Para obtener más información, consulte crear una cuenta de Cognitive Services en el portal de Azure.
Para obtener más información acerca de la API de voz de Microsoft, consulte documentación de Microsoft
Speech API.
Autenticación
Todas las solicitudes realizadas a la API de REST de voz de Microsoft requieren un token de acceso JSON Web
Token (JWT), que puede obtenerse desde el servicio de token de cognitive services en
https://api.cognitive.microsoft.com/sts/v1.0/issueToken . Se puede obtener un token mediante una solicitud
POST al servicio de token, especificando un Ocp-Apim-Subscription-Key encabezado que contiene la clave de API
como su valor.
En el ejemplo de código siguiente se muestra cómo solicitar un acceso token al servicio 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();
}
El token de acceso devuelta, que es texto Base64, tiene una fecha de expiración de 10 minutos. Por lo tanto, la
aplicación de ejemplo renueva el token de acceso cada 9 minutos.
Debe especificarse el token de acceso en cada API de REST de Microsoft Speech llamar como una Authorization
el prefijo con la cadena de encabezado Bearer , tal y como se muestra en el ejemplo de código siguiente:
Un error pasar un token de acceso válido a la API de REST de Microsoft Speech provocará un error de 403
respuesta.
fileStream.Dispose();
return speechResult;
}
Audio se registra en cada proyecto específico de plataforma como datos wav PCM y el RecognizeSpeechAsync
método usa el PCLStorage paquete NuGet para abrir el archivo de audio como una secuencia. Se recupera la
solicitud de reconocimiento de voz se genera el URI y un token de acceso al servicio de token. La solicitud de
reconocimiento de voz se registra en el recognition API, que devuelve una respuesta JSON que contiene el
resultado. La respuesta JSON se deserializa, con lo que se devuelve al método de llamada para su presentación.
Configurar el reconocimiento de voz
El proceso de reconocimiento de voz se puede configurar mediante la especificación de parámetros de consulta
HTTP:
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);
A continuación, se envía la solicitud POST a recognition API. La respuesta, a continuación, lee y devuelve al
método de llamada.
El recognition API enviará el código de estado HTTP 200 (OK) en la respuesta, siempre que la solicitud es válida,
lo que indica que la solicitud es correcta y que la información solicitada está en la respuesta. Para obtener una lista
de posibles respuestas de error, consulte Troubleshooting.
Procesamiento de la respuesta
La respuesta de API se devuelve en formato JSON, con el texto reconocido que esté incluido en la name etiqueta.
Los siguientes datos JSON muestran un mensaje de respuesta correcta típico:
{
"RecognitionStatus":"Success",
"DisplayText":"Go shopping tomorrow.",
"Offset":16000000,
"Duration":17100000
}
Resumen
En este artículo se explica cómo usar la API de REST de voz de Microsoft para convertir audio en texto en una
aplicación de Xamarin.Forms. Además de realizar el reconocimiento de voz, Speech API de Microsoft también
puede convertir texto en palabras habladas.
Vínculos relacionados
Documentación de Microsoft Speech API.
Consumir un servicio Web RESTful
Todo Cognitive Services (ejemplo)
La revisión ortográfica con Bing Spell Check API
11/07/2019 • 9 minutes to read • Edit Online
descargar el ejemplo
Bing Spell Check realiza contextual corrector ortográfico para el texto, que proporciona sugerencias de en línea
para palabras mal escritas. En este artículo se explica cómo usar Bing Spell Check REST API para corregir errores
ortográficos en una aplicación de Xamarin.Forms.
Información general
Bing Spell Check REST API tiene dos modos de funcionamiento y un modo debe especificarse al realizar una
solicitud a la API:
Spell corrige un texto breve (de hasta 9 palabras) sin realizar ningún cambio de mayúsculas y minúsculas.
Proof corrige texto largo, proporciona correcciones de mayúsculas y minúsculas y puntuación básica y
suprime correcciones agresivas.
Para usar Bing Spell Check API, se debe obtener una clave de API. Esto puede obtenerse en pruebe Cognitive
Services
Para obtener una lista de los idiomas admitidos por Bing Spell Check API, consulte idiomas admitidos. Para
obtener más información acerca de Bing Spell Check API, consulte documentación de Bing Spell comprobar.
Autenticación
Cada solicitud realizada a Bing Spell Check API necesita una clave de API que se debe especificar como el valor
de la Ocp-Apim-Subscription-Key encabezado. En el ejemplo de código siguiente se muestra cómo agregar la clave
de API para el Ocp-Apim-Subscription-Key encabezado de una solicitud:
public BingSpellCheckService()
{
httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", Constants.BingSpellCheckApiKey);
}
Error al pasar una clave de API válida a Bing Spell Check API se producirá un error en la 401 respuesta.
El SpellCheckTextAsync método genera un URI de solicitud y, a continuación, envía la solicitud para el SpellCheck
API, que devuelve una respuesta JSON que contiene el resultado. La respuesta JSON se deserializa, con lo que se
devuelve al método de llamada para su presentación.
Configurar el corrector ortográfico
El proceso de revisión ortográfica puede configurarse mediante la especificación de parámetros de consulta
HTTP:
Este método establece el texto que se puede comprobar la ortografía y el modo de comprobación de corrección
ortográfica.
Para obtener más información acerca de Bing Spell Check REST API, consulte referencia de Spell Check API v7.
Enviar la solicitud
El SendRequestAsync método realiza la solicitud GET a Bing Spell Check REST API y devuelve la respuesta:
Este método envía la solicitud GET a la SpellCheck API con la URL de solicitud especifica el texto que se deben
traducir y el modo de comprobación de corrección ortográfica. La respuesta, a continuación, lee y devuelve al
método de llamada.
El SpellCheck API enviará el código de estado HTTP 200 (OK) en la respuesta, siempre que la solicitud es válida,
lo que indica que la solicitud es correcta y que la información solicitada está en la respuesta. Para obtener una lista
de objetos de respuesta, consulte objetos de respuesta.
Procesamiento de la respuesta
Se devuelve la respuesta de API en formato JSON. Los siguientes datos JSON muestran el mensaje de respuesta
para el texto mal escrito 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"
}
El flaggedTokens matriz contiene una matriz de palabras del texto que se han marcado como no se ha escrito
correctamente o que están gramaticalmente incorrecto. La matriz estará vacía si no hay errores ortográficos o
gramaticales se encuentran. Las etiquetas dentro de la matriz son:
offset – un desplazamiento de base cero desde el principio de la cadena de texto a la palabra que se marcó.
token : la palabra en la cadena de texto que no se ha escrito correctamente o no es correcta gramaticalmente.
type : el tipo de error que provocó la palabra que se marcará. Hay dos valores posibles: RepeatedToken y
UnknownToken .
suggestions : una matriz de palabras que se corregirá el error de ortografía o gramática. La matriz está
formada por un suggestion y un score , lo que indica el nivel de confianza de que la corrección sugerida es
correcta.
En la aplicación de ejemplo, la respuesta JSON se deserializa en un SpellCheckResult instancia, con lo que se
devuelve al método de llamada para su presentación. El siguiente ejemplo de código muestra cómo el
SpellCheckResult instancia se procesa para su presentación:
Este código recorre el FlaggedTokens colección y reemplaza cualquier mal escrita o palabras gramaticalmente
incorrectas en el texto de origen con la primera sugerencia. Las capturas de pantalla siguientes se muestran antes
y después de la revisión ortográfica:
NOTE
El ejemplo anterior usa Replace por motivos de simplicidad, pero a través de una gran cantidad de texto podría
reemplazar el token erróneo. La API proporciona el offset valor que debe usarse en aplicaciones de producción para
identificar la ubicación correcta en el texto de origen para realizar una actualización.
Resumen
En este artículo se explica cómo usar Bing Spell Check REST API para corregir errores ortográficos en una
aplicación de Xamarin.Forms. Bing Spell Check realiza contextual corrector ortográfico para el texto, que
proporciona sugerencias de en línea para palabras mal escritas.
Vínculos relacionados
Documentación de Bing Spell Check
Consumir un servicio Web RESTful
Todo Cognitive Services (ejemplo)
Referencia de Bing Spell Check API v7
Traducción de texto mediante la API del traductor
11/07/2019 • 8 minutes to read • Edit Online
descargar el ejemplo
Microsoft Translator API puede usarse para traducir el texto de voz y a través de una API de REST. En este
artículo se explica cómo usar Microsoft Translator Text API para traducir texto de un idioma a otro en una
aplicación de Xamarin.Forms.
Información general
La API del traductor tiene dos componentes:
Una API de REST para traducir texto de un idioma en el texto de otro idioma de traducción de texto. La API
detecta automáticamente el idioma del texto que se ha enviado antes de trasladarlo.
Una API de REST para transcriba la voz de un idioma en el texto de otro idioma de traducción de voz. La API
también integra capacidades de texto a voz para hablar de vuelta el texto traducido.
En este artículo se centra en traducir el texto de un idioma a otro utilizando Translator Text API.
Para usar Translator Text API, se debe obtener una clave de API. Esto puede obtenerse en cómo suscribirse a
Microsoft Translator Text API.
Para obtener más información acerca de Microsoft Translator Text API, consulte documentación de Translator Text
API.
Autenticación
Cada solicitud realizada a Translator Text API requiere un token de acceso JSON Web Token (JWT), que puede
obtenerse desde el servicio de token de cognitive services en
https://api.cognitive.microsoft.com/sts/v1.0/issueToken . Se puede obtener un token mediante una solicitud
POST al servicio de token, especificando un Ocp-Apim-Subscription-Key encabezado que contiene la clave de API
como su valor.
En el ejemplo de código siguiente se muestra cómo solicitar un acceso token al servicio de token:
El token de acceso devuelta, que es texto Base64, tiene una fecha de expiración de 10 minutos. Por lo tanto, la
aplicación de ejemplo renueva el token de acceso cada 9 minutos.
Debe especificarse el token de acceso en cada Translator Text API llamar como una Authorization el prefijo con la
cadena de encabezado Bearer , tal y como se muestra en el ejemplo de código siguiente:
Para obtener más información sobre el servicio de token de cognitive services, consulte API de Token de
autenticación.
El TranslateTextAsync método genera un URI de solicitud y recupera un token de acceso al servicio de token. A
continuación, se envía la solicitud de traducción de texto a la translate API, que devuelve una respuesta XML
que contiene el resultado. Se analiza la respuesta XML y se devuelve el resultado de la traducción al método de
llamada para su presentación.
Para obtener más información acerca de las API de REST de traducción de texto, consulte Microsoft Translator
Text API.
Configurar la traducción de texto
El proceso de traducción de texto se puede configurar mediante la especificación de parámetros de consulta
HTTP:
Este método establece el texto que se deben traducir y el idioma para traducir el texto para. Para obtener una lista
de los idiomas compatibles con Microsoft Translator, consulte idiomas admitidos en Microsoft Translator Text API.
NOTE
Si una aplicación necesita saber qué idioma está el texto, el Detect API se puede llamar para detectar el idioma de la
cadena de texto.
Enviar la solicitud
El SendRequestAsync método realiza la solicitud GET a la API de REST de traducción de texto y devuelve la
respuesta:
Este método basa la solicitud GET mediante la adición de token de acceso para el Authorization encabezado, el
prefijo con la cadena Bearer . A continuación, se envía la solicitud GET a la translate API con la URL de solicitud
especifica el texto que se deben traducir y el idioma para traducir el texto a. La respuesta, a continuación, lee y
devuelve al método de llamada.
El translate API enviará el código de estado HTTP 200 (OK) en la respuesta, siempre que la solicitud es válida,
lo que indica que la solicitud es correcta y que la información solicitada está en la respuesta. Para obtener una lista
de posibles respuestas de error, vea los mensajes de respuesta en obtener traducir.
Procesamiento de la respuesta
La respuesta de API se devuelve en formato XML. Los siguientes datos XML muestran un mensaje de respuesta
correcta típico:
En la aplicación de ejemplo, se analiza la respuesta XML en un XDocument instancia, con el valor de la raíz XML
que se devuelve al método de llamada para su presentación, como se muestra en las capturas de pantalla
siguiente:
Resumen
En este artículo se explica cómo usar Microsoft Translator Text API traducir texto de un idioma al texto de otro
idioma en una aplicación de Xamarin.Forms. Además de traducir el texto, Microsoft Translator API también
pueden transcribir voz de un idioma en el texto de otro idioma.
Vínculos relacionados
Documentación de Translator Text API.
Consumir un servicio Web RESTful
Todo Cognitive Services (ejemplo)
Microsoft Translator Text API.
Reconocimiento de emociones con la Face API
11/07/2019 • 10 minutes to read • Edit Online
descargar el ejemplo
Face API toma una expresión facial de una imagen como entrada y devuelve los datos que incluyen los niveles de
confianza a través de un conjunto de emociones para cada cara de la imagen. En este artículo se explica cómo
usar Face API para que reconozca las emociones para evaluar una aplicación de Xamarin.Forms.
Información general
Face API puede realizar la detección de emociones para detectar la ira, desprecio, asco, miedo, felicidad,
neutralidad, tristeza y sorpresa, en una expresión facial. Universalmente y culturas estas emociones se comunican
a través de las mismas expresiones faciales básicas. Además de devolver un resultado de emociones para una
expresión facial, Face API puede también devuelve un rectángulo de selección de caras detectadas. Tenga en
cuenta que se debe obtener una clave de API para usar Face API. Esto puede obtenerse en pruebe Cognitive
Services.
Reconocimiento de emociones puede realizarse a través de una biblioteca de cliente y una API de REST. En este
artículo se centra en realizar el reconocimiento de emociones a través de la API de REST. Para obtener más
información acerca de la API de REST, consulte Face API de REST.
Face API puede usarse también para reconocer las expresiones faciales de personas en vídeo y puede devolver un
resumen de sus emociones. Para obtener más información, consulte cómo analizar vídeos en tiempo real.
Para obtener más información acerca de Face API, consulte Face API.
Autenticación
Cada solicitud realizada a Face API necesita una clave de API que se debe especificar como el valor de la
Ocp-Apim-Subscription-Key encabezado. En el ejemplo de código siguiente se muestra cómo agregar la clave de
API para el Ocp-Apim-Subscription-Key encabezado de una solicitud:
public FaceRecognitionService()
{
_client = new HttpClient();
_client.DefaultRequestHeaders.Add("ocp-apim-subscription-key", Constants.FaceApiKey);
}
Error al pasar una clave de API válida para Face API producirá un error en la 401 respuesta.
NOTE
Formatos de archivo de imagen admitidos son JPEG, PNG, GIF y BMP, y el tamaño de archivo permitido es de 1KB a 4MB.
Esta llamada al método especifica la secuencia que contiene los datos de imagen, que se deben devolver faceIds,
que no deben devolverse faciales, y que se debe analizar la emoción de la imagen. También especifica que los
resultados se devolverán como una matriz de Face objetos. A su vez, el DetectAsync método invoca el detect
API de REST que realiza el reconocimiento de emociones:
Este método genera un URI de solicitud y, a continuación, envía la solicitud para el detect API a través de la
SendRequestAsync método.
NOTE
Debe usar la misma región en las llamadas de Face API que utilizó para obtener las claves de suscripción. Por ejemplo, si ha
obtenido las claves de suscripción desde el westus región, que será el punto de conexión de detección de caras
https://westus.api.cognitive.microsoft.com/face/v1.0/detect .
Enviar la solicitud
El SendRequestAsync método realiza la solicitud POST a Face API y devuelve el resultado como un 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");
}
}
Si la imagen se proporciona a través de una secuencia, el método basa la solicitud POST ajustando el flujo de
imagen en un StreamContent instancia, que proporciona contenido HTTP basado en una secuencia. Como
alternativa, si la imagen se proporciona a través de una dirección URL, el método crea la solicitud POST
ajustando la dirección URL en un StringContent instancia, que proporciona contenido HTTP basado en una
cadena.
A continuación, se envía la solicitud POST a detect API. La respuesta es leer, se deserializa y se devuelve al
método de llamada.
El detect API enviará el código de estado HTTP 200 (OK) en la respuesta, siempre que la solicitud es válida, lo
que indica que la solicitud es correcta y que la información solicitada está en la respuesta. Para obtener una lista
de posibles respuestas de error, consulte Face API de REST.
Procesamiento de la respuesta
Se devuelve la respuesta de API en formato JSON. Los siguientes datos JSON muestran un mensaje de
respuesta correcta típico que proporciona los datos solicitados por la aplicación de ejemplo:
[
{
"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
}
}
}
]
Un mensaje de respuesta correcta se compone de una matriz de entradas de cara ordenados según el tamaño del
rectángulo de cara en orden descendente, mientras que una respuesta vacía no indica ningún caras detectadas.
Cada uno de ellos reconoce cara incluye una serie de atributos de cara opcional, que se especifican mediante el
returnFaceAttributes argumento para el DetectAsync método.
En la aplicación de ejemplo, la respuesta JSON se deserializa en una matriz de Face objetos. Al interpretar los
resultados de Face API, las emociones detectadas se deben interpretar como la emoción con la puntuación más
alta, como las puntuaciones se normalizan para que sumen uno. Por lo tanto, la aplicación de ejemplo muestra la
emoción reconocida con la puntuación más alta para la cara detectada más grande en la imagen. Esto se consigue
con el código siguiente:
emotionResultLabel.Text = faces.FirstOrDefault().FaceAttributes.Emotion.ToRankedList().FirstOrDefault().Key;
Captura de pantalla siguiente muestra el resultado del proceso de reconocimiento de emociones en la aplicación
de ejemplo:
Resumen
En este artículo se explica cómo usar Face API para que reconozca las emociones para evaluar una aplicación de
Xamarin.Forms. Face API toma una expresión facial de una imagen como entrada y devuelve los datos que
incluyen la confianza entre un conjunto de emociones para cada cara de la imagen.
Vínculos relacionados
Face API.
Todo Cognitive Services (ejemplo)
Face API de REST
Xamarin.Forms y servicios Web
11/07/2019 • 2 minutes to read • Edit Online
Introducción
En este artículo se ofrece un tutorial de la aplicación de ejemplo de Xamarin.Forms que muestra cómo comunicar
con los servicios web diferentes. Los temas tratados incluyen la Anatomía de la aplicación, las páginas, el modelo
de datos y la invocación de operaciones del servicio web.
descargar el ejemplo
En este tema se ofrece un tutorial de la aplicación de ejemplo de Xamarin.Forms que muestra cómo comunicar
con los servicios web diferentes. Aunque cada servicio web utiliza una aplicación de ejemplo independiente, todos
son funcionalmente similares y comparten clases comunes.
La aplicación de lista de tareas pendientes de ejemplo que se describe a continuación se usa para demostrar
cómo obtener acceso a diferentes tipos de back-ends de web service con Xamarin.Forms. Proporciona
funcionalidad para:
Ver una lista de tareas.
Agregar, editar y eliminar tareas.
Establece el estado de una tarea a 'listo'.
Diga a los campos de nombre y las notas de la tarea.
En todos los casos, las tareas se almacenan en un back-end que se accede a través de un servicio web.
Cuando se inicia la aplicación, se muestra una página que enumera las tareas que se recuperan desde el servicio
web y permite al usuario crear una nueva tarea. Al hacer clic en una tarea desplaza a la aplicación a una segunda
página, donde la tarea puede se puede editar, se guardan, eliminan y habla. A continuación se muestra la
aplicación final:
Cada tema de esta guía proporciona un vínculo de descarga a un diferentes versión de la aplicación que se
muestra un tipo específico de back-end de web service. Descargue el código de ejemplo correspondiente en la
página de cada estilo de servicio web.
CARPETA PROPÓSITO
El proyecto de código compartido para cada aplicación también consta de un número de archivos importantes:
ARCHIVO PROPÓSITO
Páginas de vista
La mayoría de las aplicaciones de ejemplo contienen al menos dos páginas:
TodoListPage : esta página muestra una lista de TodoItem instancias y un icono de marca si la TodoItem.Done
propiedad es true . Al hacer clic en un elemento se desplaza a la TodoItemPage . Además, se pueden crear
nuevos elementos, haga clic en el + símbolos.
TodoItemPage : esta página muestra los detalles para el seleccionado TodoItem y permite que se puede
editar, guardar, elimina y habla.
Además, algunas aplicaciones de ejemplo contienen páginas adicionales que se usan para administrar el proceso
de autenticación de usuario.
Los datos del modelo
Cada aplicación de ejemplo usa el TodoItem clase para modelar los datos que se muestran y se envía al servicio
web para el almacenamiento. En el ejemplo de código siguiente se muestra la clase TodoItem :
El ID propiedad se utiliza para identificar de forma única cada TodoItem de instancia y cada servicio web sirve
para identificar los datos que se va a actualizar o eliminar.
Invocar operaciones de servicio web
Se tiene acceso a las operaciones del servicio Web a través de la TodoItemManager clase y una instancia de la clase
se pueden acceder mediante el App.TodoManager propiedad. La TodoItemManager clase proporciona los métodos
siguientes para invocar las operaciones del servicio web:
GetTasksAsync : este método se usa para rellenar el ListView control en el TodoListPage con el TodoItem
instancias recuperados del servicio web.
SaveTaskAsync : este método se utiliza para crear o actualizar un TodoItem instancia del servicio web.
DeleteTaskAsync : este método se usa para eliminar un TodoItem instancia del servicio web.
Además, algunas aplicaciones de ejemplo contienen métodos adicionales en el TodoItemManager (clase), que se
usan para administrar el proceso de autenticación de usuario.
En lugar de invocar las operaciones del servicio web directamente, el TodoItemManager métodos invocan métodos
en una clase dependiente que se inserta en la TodoItemManager constructor. Por ejemplo, una aplicación de
ejemplo inserta la RestService clase en el TodoItemManager constructor para proporcionar la implementación
que usa las API de REST para acceder a los datos.
Vínculos relacionados
ASMX (ejemplo)
WCF (ejemplo)
REST (ejemplo)
Consumir un servicio Web ASP.NET (ASMX)
11/07/2019 • 12 minutes to read • Edit Online
descargar el ejemplo
ASMX proporciona la capacidad de crear servicios web que envían mensajes mediante el protocolo Simple de
acceso de objetos (SOAP ). SOAP es un protocolo independiente de la plataforma y lenguaje para crear y obtener
acceso a servicios web. Los consumidores de un servicio de ASMX no es necesario saber nada acerca de la
plataforma, el modelo de objetos o el lenguaje de programación usado para implementar el servicio. Sólo
necesitan entender cómo enviar y recibir mensajes SOAP. En este artículo se muestra cómo consumir un servicio
de ASMX SOAP desde una aplicación de Xamarin.Forms.
Un mensaje SOAP es un documento XML que contiene los siguientes elementos:
Un elemento raíz denominado sobres que identifica el documento XML como un mensaje SOAP.
Opcional encabezado elemento que contiene información específica de la aplicación, como datos de
autenticación. Si el encabezado elemento está presente debe ser el primer elemento secundario de la sobres
elemento.
Obligatoria cuerpo elemento que contiene el mensaje SOAP, diseñado para el destinatario.
Opcional error elemento que se usa para indicar los mensajes de error. Si el error elemento está presente, debe
ser un elemento secundario de la cuerpo elemento.
SOAP puede operar en muchos protocolos de transporte, incluidos HTTP, SMTP, TCP y UDP. Sin embargo, un
servicio de ASMX solo puede funcionar a través de HTTP. La plataforma Xamarin es compatible con las
implementaciones estándar de SOAP 1.1 a través de HTTP, y esto incluye compatibilidad con muchas de las
configuraciones estándar de servicio ASMX.
Este ejemplo incluye las aplicaciones móviles que se ejecutan en dispositivos físicos o emulados y un servicio de
ASMX que proporciona métodos para obtener, agregar, editar y eliminar datos. Cuando se ejecutan las
aplicaciones móviles, se conectan al servicio ASMX alojado localmente como se muestra en la captura de pantalla
siguiente:
NOTE
En iOS 9 y versiones posteriores, App Transport Security (ATS) exige que las conexiones seguras entre los recursos de internet
(por ejemplo, el servidor back-end de la aplicación) y la aplicación, lo que impide la divulgación accidental de información
confidencial. Puesto que ATS está habilitada de forma predeterminada en las aplicaciones compiladas para iOS 9, todas las
conexiones estará sujeto a los requisitos de seguridad ATS. Si las conexiones no cumplen estos requisitos, se producirá un
error con una excepción. Se puede optar por en ATS de si no es posible usar la HTTPS del protocolo y proteger la
comunicación de los recursos de internet. Esto puede lograrse mediante la actualización de la aplicación Info.plist archivo.
Para obtener más información, consulte App Transport Security.
Para obtener más información sobre el modelo de datos utilizado en la aplicación, consulte los datos de modelado.
public SoapService ()
{
todoService = new ASMXService.TodoService ();
todoService.Url = Constants.SoapUrl;
...
}
}
Este método crea un nuevo ASMService.TodoItem de instancia y establece cada propiedad a la propiedad idéntica
desde el TodoItem instancia.
De forma similar, cuando se recuperan datos desde el servicio web, se debe convertir desde el proxy generado
TodoItem tipo a un TodoItem instancia. Esto se consigue con la FromASMXServiceTodoItem método, como se
muestra en el ejemplo de código siguiente:
Este método recupera los datos desde el proxy generado TodoItem escriba y lo establece en recién creado
TodoItem instancia.
Recuperar datos
El ISoapService interfaz espera el RefreshDataAsync método devuelva un Task con la colección de elementos. Sin
embargo, el TodoService.GetTodoItemsAsync método devuelve void. Para satisfacer el patrón de interfaz, debe
llamar a GetTodoItemsAsync , espere a que el GetTodoItemsCompleted eventos se activan y rellene la colección. Esto
permite devolver una colección válida a la interfaz de usuario.
El ejemplo siguiente crea un nuevo TaskCompletionSource , comienza la llamada asincrónica en el RefreshDataAsync
método y espera el Task proporcionada por el TaskCompletionSource . Cuando el
TodoService_GetTodoItemsCompleted se invoca el controlador de eventos rellena el Items colección y las
actualizaciones de la TaskCompletionSource :
public class SoapService : ISoapService
{
TaskCompletionSource<bool> getRequestComplete = null;
...
public SoapService()
{
...
todoService.GetTodoItemsCompleted += TodoService_GetTodoItemsCompleted;
}
...
}
Para obtener más información, consulte modelo de programación asincrónica y TPL y la programación tradicional
de .NET Framework asincrónicas.
Crear o editar datos
Al crear o editar datos, se debe implementar la ISoapService.SaveTodoItemAsync método. Este método detecta si el
TodoItem es un elemento nuevo o actualizado y llama al método apropiado en el todoService objeto. El
CreateTodoItemCompleted y EditTodoItemCompleted también se deberían implementar controladores de eventos
para que sepa cuándo el todoService ha recibido una respuesta desde el servicio ASMX (estos se pueden
combinar en un único controlador puesto que realizan la misma operación). El ejemplo siguiente muestra las
implementaciones de controlador de interfaz y eventos, así como el TaskCompletionSource objeto usado para
funcionar de forma asincrónica:
public class SoapService : ISoapService
{
TaskCompletionSource<bool> saveRequestComplete = null;
...
public SoapService()
{
...
todoService.CreateTodoItemCompleted += TodoService_SaveTodoItemCompleted;
todoService.EditTodoItemCompleted += TodoService_SaveTodoItemCompleted;
}
...
}
Eliminar datos
Eliminación de datos requiere una implementación similar. Definir un TaskCompletionSource , implemente un
controlador de eventos y el ISoapService.DeleteTodoItemAsync método:
public class SoapService : ISoapService
{
TaskCompletionSource<bool> deleteRequestComplete = null;
...
public SoapService()
{
...
todoService.DeleteTodoItemCompleted += TodoService_DeleteTodoItemCompleted;
}
...
}
Vínculos relacionados
TodoASMX (ejemplo)
IAsyncResult
Consumir un servicio Web de Windows
Communication Foundation (WCF)
11/07/2019 • 24 minutes to read • Edit Online
descargar el ejemplo
WCF es el marco unificado de Microsoft para crear aplicaciones orientadas a servicios. Permite a los
desarrolladores crear aplicaciones distribuidas seguras, confiables, transacciones e interoperables. En este artículo
se muestra cómo consumir un servicio de Protocolo Simple de acceso de objetos (SOAP ) de WCF desde una
aplicación de Xamarin.Forms.
WCF describe un servicio con una variedad de contratos diferentes incluidas:
Los contratos de datos : definir las estructuras de datos que forman la base para el contenido dentro de un
mensaje.
Contratos de mensaje – redactar mensajes de los contratos de datos existente.
Contratos de error : permitir que los errores de SOAP personalizados que se especifique.
Contratos de servicio : especificar las operaciones que admiten servicios y los mensajes necesarios para
interactuar con cada operación. También especifique ningún comportamiento de error personalizado que se
puede asociar con las operaciones en cada servicio.
Existen diferencias entre los servicios Web de ASP.NET (ASMX) y WCF, pero WCF admite las mismas
funcionalidades que proporciona ASMX: los mensajes SOAP a través de HTTP. Para obtener más información
sobre cómo usar un servicio de ASMX, consulte consumir servicios de Web de ASP.NET (ASMX) .
IMPORTANT
La compatibilidad con la plataforma de Xamarin para WCF se limita a los mensajes codificados en texto SOAP a través de
HTTP/HTTPS mediante la BasicHttpBinding clase.
Compatibilidad con WCF requiere el uso de herramientas solo está disponibles en un entorno de Windows para generar al
proxy y hospedar el TodoWCFService. Compilar y probar la aplicación de iOS requiere implementar el TodoWCFService en un
equipo Windows o como un servicio web de Azure.
Aplicaciones nativas de Xamarin Forms suelen compartan el código con una biblioteca de clases .NET Standard. Sin embargo,
.NET Core no admite actualmente WCF para que el proyecto compartido debe ser una biblioteca de clases Portable heredada.
Para obtener información sobre la compatibilidad WCF en .NET Core, vea selección entre .NET Core y .NET Framework para
aplicaciones de servidor.
La solución de aplicación de ejemplo incluye un servicio WCF que se puede ejecutar localmente y se muestra en la
captura de pantalla siguiente:
NOTE
En iOS 9 y versiones posteriores, App Transport Security (ATS) exige que las conexiones seguras entre los recursos de internet
(por ejemplo, el servidor back-end de la aplicación) y la aplicación, lo que impide la divulgación accidental de información
confidencial. Puesto que ATS está habilitada de forma predeterminada en las aplicaciones compiladas para iOS 9, todas las
conexiones estará sujeto a los requisitos de seguridad ATS. Si las conexiones no cumplen estos requisitos, se producirá un
error con una excepción.
Se puede optar por en ATS de si no es posible usar la HTTPS del protocolo y proteger la comunicación de los recursos de
internet. Esto puede lograrse mediante la actualización de la aplicación Info.plist archivo. Para obtener más información,
consulte App Transport Security.
public SoapService ()
{
todoService = new TodoServiceClient (
new BasicHttpBinding (),
new EndpointAddress (Constants.SoapUrl));
}
...
}
El TodoServiceClient instancia está configurada con una dirección de extremo y la información de enlace. Un
enlace se utiliza para especificar el transporte, codificación y detalles protocolares requeridos para que las
aplicaciones y servicios para comunicarse entre sí. El BasicHttpBinding especifica que se enviarán los mensajes
codificados en texto SOAP a través del protocolo de transporte HTTP. Especificación de una dirección de punto de
conexión permite a la aplicación para conectarse a distintas instancias del servicio WCF, siempre que hay varias
instancias publicadas.
Para obtener más información sobre la configuración de la referencia de servicio, consulte configuración de la
referencia de servicio.
Crear objetos de transferencia de datos
La aplicación de ejemplo usa el TodoItem clase para modelar los datos. Para almacenar un TodoItem elemento en
el servicio web debe convertirse primero en el proxy generado TodoItem tipo. Esto se consigue mediante la
ToWCFServiceTodoItem método, como se muestra en el ejemplo de código siguiente:
Este método simplemente crea un nuevo TodoWCFService.TodoItem de instancia y establece cada propiedad a la
propiedad idéntica desde el TodoItem instancia.
De forma similar, cuando se recuperan datos desde el servicio web, se debe convertir desde el proxy generado
TodoItem tipo a un TodoItem instancia. Esto se consigue con la FromWCFServiceTodoItem método, como se muestra
en el ejemplo de código siguiente:
Este método simplemente recupera los datos desde el proxy generado TodoItem escriba y lo establece en recién
creado TodoItem instancia.
Recuperar datos
El TodoServiceClient.BeginGetTodoItems y TodoServiceClient.EndGetTodoItems métodos se usan para llamar a la
GetTodoItems operación proporcionada por el servicio web. Estos métodos asincrónicos se encapsulan en un
Task de objeto, como se muestra en el ejemplo de código siguiente:
public async Task<List<TodoItem>> RefreshDataAsync ()
{
...
var todoItems = await Task.Factory.FromAsync <ObservableCollection<TodoWCFService.TodoItem>> (
todoService.BeginGetTodoItems,
todoService.EndGetTodoItems,
null,
TaskCreationOptions.None);
2. Configurar IIS Express para las conexiones remotas acepte. Puede configurar IIS Express editando el
archivo de configuración de IIS Express en [directorio de la
solución].vs\config\applicationhost.config. Buscar el site elemento con el nombre TodoWCFService .
Debería ser similar al siguiente XML:
Deberá agregar dos binding elementos para abrir el puerto 49393 para el tráfico externo y el emulador de
Android. El enlace utiliza un [IP address]:[port]:[hostname] formato que especifica cómo IIS Express
responderá a las solicitudes. Las solicitudes externas tendrán nombres de host que se deben especificar
como un binding . Agregue el siguiente código XML para el bindings elemento, reemplazando la dirección
IP con su propia dirección IP:
Después de los cambios del bindings elemento debe ser similar al siguiente:
IMPORTANT
De forma predeterminada, IIS Express no aceptará las conexiones de orígenes externos por motivos de seguridad.
Para habilitar las conexiones procedentes de dispositivos remotos deben ejecutar IIS Express con permisos
administrativos. La manera más fácil de hacerlo es ejecutar Visual Studio 2017 con permisos administrativos. Esto
iniciará IIS Express con permisos administrativos al ejecutar el TodoWCFService.
Con estos pasos completados, debe ser capaz de ejecutar el TodoWCFService y conectarse desde otros
dispositivos de la subred. Puede probar esto mediante la ejecución de la aplicación y visitar
http://localhost:49393/TodoService.svc . Si se produce un solicitud incorrecta error al visitar esa dirección
URL, su bindings puede ser incorrecto en la configuración de IIS Express (la solicitud está llegando a IIS
Express, pero se ha rechazado). Si se produce un error diferente, es posible que no se está ejecutando la
aplicación o el firewall está configurado incorrectamente.
Para permitir que IIS Express mantener la ejecución y ofrecer el servicio, desactive la editar y continuar
opción las propiedades del proyecto > Web > depuradores.
3. Personalizar el punto de conexión de dispositivos usan para tener acceso al servicio. Este paso
implica la configuración de la aplicación cliente, que se ejecuta en un dispositivo físico o emulado, para
acceder al servicio WCF.
El emulador de Android usa un proxy interno que impide que el emulador de obtener acceso directamente a
la máquina host localhost dirección. En su lugar, la dirección 10.0.2.2 en el emulador se enruta a
localhost en el equipo host a través de un proxy interno. Estas solicitudes procesadas por el proxy tendrá
127.0.0.1 como nombre de host en el encabezado de solicitud, que es la razón por la que creó el enlace de
IIS Express para este nombre de host en los pasos anteriores.
IOS Simulator se ejecuta en un equipo Mac compilar host, incluso si usas el remoto de iOS Simulator para
Windows. Las solicitudes de red desde el simulador tendrá su dirección IP de la estación de trabajo en la red
local como el nombre de host (en este ejemplo tiene 192.168.1.143 , pero la dirección IP real
probablemente serán diferente). Se trata de por qué creó el enlace de IIS Express para este nombre de host
en los pasos anteriores.
Asegúrese del SoapUrl propiedad en el Constants.cs archivo en el proyecto TodoWCF (Portable) tienen
valores que son correctos para la red:
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;
}
}
Una vez que haya configurado el Constants.cs con los puntos de conexión adecuadas, debe ser capaz de
conectarse a la TodoWCFService que se ejecuta en la estación de trabajo de Windows 10 desde dispositivos
físicos o virtuales.
Vínculos relacionados
TodoWCF (ejemplo)
Cómo: Crear a un cliente de Windows Communication Foundation
ServiceModel Metadata Utility Tool (svcutil.exe)
Consumir un servicio Web RESTful
11/07/2019 • 15 minutes to read • Edit Online
descargar el ejemplo
Integrar un servicio web en una aplicación es un escenario común. En este artículo se muestra cómo consumir un
servicio web de RESTful desde una aplicación de Xamarin.Forms.
Representational State Transfer (REST) es un estilo de arquitectura para la creación de servicios web. Solicitudes
REST se realizan a través de HTTP utilizando los mismos verbos HTTP que los exploradores web que se usan
para recuperar las páginas web y para enviar datos a los servidores. Los verbos son:
OBTENER : esta operación se usa para recuperar datos desde el servicio web.
POST : esta operación se usa para crear un nuevo elemento de datos en el servicio web.
COLOCAR : esta operación se usa para actualizar un elemento de datos en el servicio web.
REVISIÓN : esta operación se usa para actualizar un elemento de datos en el servicio web con la descripción
de un conjunto de instrucciones sobre cómo se debe modificar el elemento. No se utiliza este verbo en la
aplicación de ejemplo.
ELIMINAR : esta operación se usa para eliminar un elemento de datos en el servicio web.
Se llama a las API de RESTful API que se adhieren a REST del servicio Web y se definen mediante:
Un URI base.
Métodos HTTP, como GET, POST, PUT, PATCH o DELETE.
Tipo de medio de los datos, como JavaScript Object Notation (JSON ).
Servicios web rESTful normalmente utilizan mensajes JSON para devolver datos al cliente. JSON es un formato
de intercambio de datos basado en texto que genera cargas compactas, lo que reducción los requisitos de ancho
de banda al enviar datos. La aplicación de ejemplo usa el código abierto biblioteca de NewtonSoft JSON.NET
para serializar y deserializar los mensajes.
La simplicidad de REST ha ayudado a hacer el método principal para tener acceso a servicios web en aplicaciones
móviles.
Cuando se ejecuta la aplicación de ejemplo, se conectará a un servicio REST hospedado localmente, como se
muestra en la captura de pantalla siguiente:
NOTE
En iOS 9 y versiones posteriores, App Transport Security (ATS) exige que las conexiones seguras entre los recursos de
internet (por ejemplo, el servidor back-end de la aplicación) y la aplicación, lo que impide la divulgación accidental de
información confidencial. Puesto que ATS está habilitada de forma predeterminada en las aplicaciones compiladas para iOS 9,
todas las conexiones estará sujeto a los requisitos de seguridad ATS. Si las conexiones no cumplen estos requisitos, se
producirá un error con una excepción.
Se puede optar por en ATS de si no es posible usar el HTTPS protocolo y proteger la comunicación de los recursos de
internet. Esto puede lograrse mediante la actualización de la aplicación Info.plist archivo. Para obtener más información,
consulte App Transport Security.
La mayoría de los URI incluyen el TodoItem ID en la ruta de acceso. Por ejemplo, para eliminar la TodoItem cuyo
identificador es 6bb8a868-dba1-4f1a-93b7-24ebce87e243 , el cliente envía una solicitud DELETE
http://hostname/api/todoitems/6bb8a868-dba1-4f1a-93b7-24ebce87e243 . Para obtener más información acerca del
modelo de datos usado en la aplicación de ejemplo, vea los datos de modelado.
Cuando el marco API Web recibe una solicitud enruta la solicitud a una acción. Estas acciones son métodos
públicos simplemente en el TodoItemsController clase. El marco de trabajo usa una tabla de enrutamiento para
determinar qué acción va a invocar en respuesta a una solicitud, que se muestra en el ejemplo de código
siguiente:
config.Routes.MapHttpRoute(
name: "TodoItemsApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { controller="todoitems", id = RouteParameter.Optional }
);
La tabla de enrutamiento contiene una plantilla de ruta, y cuando el marco API Web recibe una solicitud HTTP,
intenta coincidir con el URI en la plantilla de ruta en la tabla de enrutamiento. Si una coincidencia de ruta no se
encuentra que el cliente recibe un error 404 (no encontrado). Si se encuentra una ruta coincidente, Web API
selecciona el controlador y la acción siguiente:
Para buscar el controlador, Web API agrega "controller" en el valor de la {controller } variable.
Para buscar la acción, API Web examina el método HTTP y examina las acciones de controlador que se
decoran con el mismo método HTTP como un atributo.
El {id } variable de marcador de posición se asigna a un parámetro de acción.
El servicio REST usa la autenticación básica. Para obtener más información, consulte autenticar un servicio web
RESTful. Para obtener más información sobre el enrutamiento de ASP.NET Web API, consulte Routing in
ASP.NET Web API en el sitio Web ASP.NET. Para obtener más información acerca de cómo crear el servicio
REST mediante ASP.NET Core, consulte crear servicios back-end para aplicaciones móviles nativas.
La HttpClient clase se utiliza para enviar y recibir solicitudes a través de HTTP. Proporciona funcionalidad para
enviar solicitudes HTTP y recibir respuestas HTTP de un URI identifica el recurso. Cada solicitud se envía como
una operación asincrónica. Para obtener más información acerca de las operaciones asincrónicas, vea información
general de soporte técnico de Async.
La HttpResponseMessage clase representa un mensaje de respuesta HTTP recibido del servicio web después de
realizar una solicitud HTTP. Contiene información acerca de la respuesta, incluido el código de estado, los
encabezados y cualquier cuerpo. El HttpContent clase representa el cuerpo HTTP y encabezados de contenido,
como Content-Type y Content-Encoding . El contenido se puede leer utilizando cualquiera de los ReadAs métodos,
como ReadAsStringAsync y ReadAsByteArrayAsync , dependiendo del formato de los datos.
Crear el objeto HTTPClient
El HttpClient instancia se declara en el nivel de clase para que se encuentra el objeto para siempre y cuando la
aplicación necesita para realizar solicitudes HTTP, como se muestra en el ejemplo de código siguiente:
public RestService ()
{
_client = new HttpClient ();
}
...
}
Recuperar datos
El HttpClient.GetAsync método se utiliza para enviar la solicitud GET al servicio web especificado por el
identificador URI y, a continuación, recibir la respuesta del servicio web, como se muestra en el ejemplo de código
siguiente:
...
var json = JsonConvert.SerializeObject (item);
var content = new StringContent (json, Encoding.UTF8, "application/json");
if (response.IsSuccessStatusCode)
{
Debug.WriteLine (@"\tTodoItem successfully saved.");
}
...
}
El TodoItem instancia se convierte en una carga JSON para enviar al servicio web. Esta carga, a continuación, se
inserta en el cuerpo de contenido HTTP que se enviará al servicio web antes de realizar la solicitud con el
PostAsync método.
La operación de la PutAsync es idéntico al método el PostAsync método que se usa para crear datos en el
servicio web. Sin embargo, se diferencian las posibles respuestas enviadas desde el servicio web.
El servicio REST envía un código de estado HTTP en el HttpResponseMessage.IsSuccessStatusCode propiedad para
indicar si la solicitud HTTP se realizó correctamente o no. Las respuestas comunes para esta operación son:
204 (sin contenido) : se ha procesado correctamente la solicitud y la respuesta está intencionadamente en
blanco.
400 (solicitud incorrecta) : el servidor no entiende la solicitud.
404 (no encontrado) : el recurso solicitado no existe en el servidor.
Eliminar datos
El HttpClient.DeleteAsync método se utiliza para enviar la solicitud DELETE al servicio web especificado por el
identificador URI y, a continuación, recibir la respuesta del servicio web, como se muestra en el ejemplo de código
siguiente:
Vínculos relacionados
Creación de servicios back-end para aplicaciones móviles nativas
TodoREST (ejemplo)
HttpClient
Autenticación del servicio Web de Xamarin.Forms
11/07/2019 • 2 minutes to read • Edit Online
HTTP es compatible con el uso de varios mecanismos de autenticación para controlar el acceso a los recursos.
Autenticación básica proporciona acceso a recursos solo a los clientes que tienen las credenciales correctas. En
este artículo se muestra cómo usar la autenticación básica para proteger el acceso a recursos de servicio web
RESTful.
NOTE
En iOS 9 y versiones posteriores, App Transport Security (ATS) exige que las conexiones seguras entre los recursos de
internet (por ejemplo, el servidor back-end de la aplicación) y la aplicación, lo que impide la divulgación accidental de
información confidencial. Puesto que ATS está habilitada de forma predeterminada en las aplicaciones compiladas para iOS 9,
todas las conexiones estará sujeto a los requisitos de seguridad ATS. Si las conexiones no cumplen estos requisitos, se
producirá un error con una excepción. Se puede optar por en ATS de si no es posible usar la HTTPS del protocolo y
proteger la comunicación de los recursos de internet. Esto puede lograrse mediante la actualización de la aplicación
Info.plist archivo. Para obtener más información, consulte App Transport Security.
Si un servicio web recibe una solicitud para un recurso protegido, con el Authorization encabezado
correctamente establecido, el web servicio responde con un código de estado HTTP 200, lo que indica que la
solicitud es correcta y que la información solicitada está en la respuesta. Este escenario se muestra en el
diagrama siguiente:
NOTE
Sólo debe utilizarse la autenticación básica a través de una conexión HTTPS. Cuando se utiliza en una conexión HTTP, el
Authorization encabezado puede descodificar fácilmente si un atacante captura el tráfico HTTP.
public RestService ()
{
var authData = string.Format ("{0}:{1}", Constants.Username, Constants.Password);
var authHeaderValue = Convert.ToBase64String (Encoding.UTF8.GetBytes (authData));
A continuación, cuando se realiza una solicitud a una operación de servicio web se firma la solicitud con el
Authorization encabezado, que indica si el usuario tiene permiso para invocar la operación.
NOTE
Si bien este código almacena las credenciales como constantes, no se almacenan en un formato no seguro en una aplicación
publicada. El Xamarith.Auth NuGet proporciona funcionalidad para almacenar las credenciales de forma segura. Para obtener
más información, consulte almacenar y recuperar información de cuenta en los dispositivos.
NOTE
Autenticación básica no se diseñó para administrar el cierre de sesión. Por lo tanto, el enfoque de autenticación básica
estándar para el cierre de sesión es para finalizar la sesión.
Vínculos relacionados
Consumir un servicio web RESTful
HttpClient
Autenticar a los usuarios con un proveedor de
identidades
11/07/2019 • 26 minutes to read • Edit Online
descargar el ejemplo
Xamarin.Auth es un SDK multiplataforma para autenticar a los usuarios y sus cuentas de almacenamiento.
Incluye los autenticadores de OAuth que proporcionan compatibilidad para consumir los proveedores de
identidades como Microsoft, Google, Facebook y Twitter. Este artículo explica cómo usar Xamarin.Auth para
administrar el proceso de autenticación en una aplicación de Xamarin.Forms.
OAuth es un estándar abierto para la autenticación y permite un propietario del recurso notificar a un proveedor
de recursos que se debe conceder permiso a un tercero para tener acceso a su información sin compartir la
identidad de los propietarios de recursos. Un ejemplo de esto sería la habilitación de un usuario notificar a un
proveedor de identidades (por ejemplo, Google, Microsoft, Facebook o Twitter) que se debe conceder permiso a
una aplicación para acceder a sus datos, sin compartir la identidad del usuario. Normalmente se usa como un
enfoque para los usuarios para iniciar sesión en sitios Web y aplicaciones mediante un proveedor de identidades,
pero sin exponer su contraseña para el sitio Web o aplicación.
Una descripción general del flujo de autenticación al consumir un proveedor de identidades de OAuth es como
sigue:
1. La aplicación navega en un explorador a una dirección URL de proveedor de identidad.
2. El proveedor de identidades controla la autenticación de usuario y devuelve un código de autorización a la
aplicación.
3. La aplicación intercambia el código de autorización para un token de acceso del proveedor de identidades.
4. La aplicación utiliza el token de acceso para acceder a las API en el proveedor de identidades, como una API
para solicitar datos de usuario básica.
La aplicación de ejemplo muestra cómo usar Xamarin.Auth para implementar un flujo de autenticación nativa con
Google. Mientras se usa Google como proveedor de identidades en este tema, el enfoque es igualmente aplicable
a otros proveedores de identidades. Para obtener más información sobre la autenticación mediante el punto de
conexión de Google OAuth 2.0, consulte utilizando OAuth2.0 para el acceso a Google APIs en el sitio Web de
Google.
NOTE
En iOS 9 y versiones posteriores, App Transport Security (ATS) exige que las conexiones seguras entre los recursos de
internet (por ejemplo, el servidor back-end de la aplicación) y la aplicación, lo que impide la divulgación accidental de
información confidencial. Puesto que ATS está habilitada de forma predeterminada en las aplicaciones compiladas para iOS 9,
todas las conexiones estará sujeto a los requisitos de seguridad ATS. Si las conexiones no cumplen estos requisitos, se
producirá un error con una excepción. Se puede optar por en ATS de si no es posible usar la HTTPS del protocolo y
proteger la comunicación de los recursos de internet. Esto puede lograrse mediante la actualización de la aplicación
Info.plist archivo. Para obtener más información, consulte App Transport Security.
La aplicación realiza una solicitud de autenticación para usar Google el OAuth2Authenticator clase. Se devuelve
una respuesta de autenticación, una vez que el usuario se ha autenticado correctamente con Google a través de su
página de inicio de sesión, que incluye un token de acceso. A continuación, la aplicación realiza una solicitud a
Google para datos de usuario básica, mediante el OAuth2Request (clase), con el token de acceso que se incluye en
la solicitud.
Programa de instalación
Debe crearse un proyecto de consola de API de Google para integrar el inicio de sesión de Google con una
aplicación de Xamarin.Forms. Esto se puede lograr de la siguiente manera:
1. Vaya a la consola de API de Google sitio Web e inicie sesión con credenciales de cuenta de Google.
2. En la lista desplegable proyecto, seleccione un proyecto existente o crear uno nuevo.
3. En la barra lateral en "Administrador de API", seleccione credenciales, a continuación, seleccione el ficha de
pantalla de consentimiento de OAuth. Elija un dirección de correo electrónico, especifique un nombre
de producto que se muestra a los usuariosy presione guardar.
4. En el credenciales ficha, seleccione el crear credenciales desplegable lista y elija Id. de cliente de OAuth.
5. En tipo de aplicación, seleccione la plataforma que se ejecutará la aplicación móvil (iOS o Android).
6. Rellene los detalles necesarios y seleccione el crear botón.
NOTE
Un identificador de cliente permite que una aplicación tener acceso a habilitado APIs Google y para las aplicaciones móviles
es único para una sola plataforma. Por lo tanto, un identificador de cliente OAuth debe crearse para cada plataforma que
va a usar inicio de sesión de Google.
Después de realizar estos pasos, Xamarin.Auth puede utilizarse para iniciar un flujo de autenticación de OAuth2
con Google.
Crear y configurar un autenticador
De Xamarin.Auth OAuth2Authenticator clase es responsable de controlar el flujo de autenticación de OAuth. En el
ejemplo de código siguiente se muestra la creación de instancias de la OAuth2Authenticator clase al realizar la
autenticación mediante el explorador web del dispositivo:
authenticator.Completed += OnAuthCompleted;
Este evento se desencadenará cuando el usuario se autentica correctamente o cancela el inicio de sesión.
Opcionalmente, un controlador de eventos para el OAuth2Authenticator.Error también se pueden registrar
eventos.
Presentar la interfaz de usuario de inicio de sesión
La interfaz de usuario de inicio de sesión se puede presentar al usuario mediante el uso de un presentador de
inicio de sesión de Xamarin.Auth, lo que debe inicializarse en cada proyecto de la plataforma. El ejemplo de código
siguiente muestra cómo inicializar un presentador de inicio de sesión en el AppDelegate clase en el proyecto de
iOS:
global::Xamarin.Auth.Presenters.XamarinIOS.AuthenticationConfiguration.Init();
El ejemplo de código siguiente muestra cómo inicializar un presentador de inicio de sesión en el MainActivity
clase en el proyecto de Android:
global::Xamarin.Auth.Presenters.XamarinAndroid.AuthenticationConfiguration.Init(this, bundle);
El proyecto de biblioteca estándar. NET, a continuación, puede invocar el presentador de inicio de sesión como
sigue:
Cuando el explorador web recibe una respuesta del proveedor de identidad que contiene una combinación de
dirección URL personalizada, intenta cargar la dirección URL, que se producirá un error. En su lugar, el esquema
de dirección URL personalizado se notifica al sistema operativo al generar un evento. El sistema operativo, a
continuación, se comprueba para esquemas registrados, y si encuentra uno, el sistema operativo se inicia la
aplicación que registra el esquema y enviarlo en la dirección URL de redireccionamiento.
El mecanismo para registrar un esquema de dirección URL personalizado con el sistema operativo y el esquema
de control es específico para cada plataforma.
iOS
En iOS, se registra una combinación de dirección URL personalizada en Info.plist, tal y como se muestra en la
captura de pantalla siguiente:
El identificador valor puede ser cualquier cosa y el rol valor debe establecerse en Visor. El esquemas Url valor,
que comienza con com.googleusercontent.apps , puede obtenerse desde el identificador de cliente de iOS para el
proyecto en consola de API de Google.
Cuando el proveedor de identidades completa la solicitud de autorización, redirige a la dirección URL de
redireccionamiento de la aplicación. Dado que la dirección URL usa un esquema personalizado, da como
resultado de iniciar la aplicación de iOS, pasando la dirección URL como un parámetro de inicio, donde se
procesó la OpenUrl la invalidación de la aplicación AppDelegate (clase), que se muestra en el ejemplo de código
siguiente:
return true;
}
El OpenUrl método convierte la dirección URL recibida desde un NSUrl a .NET Uri , antes de procesar la
dirección URL de redireccionamiento con el OnPageLoading método para un público OAuth2Authenticator objeto.
Esto hace que Xamarin.Auth para cerrar la pestaña del explorador web y analizar los datos recibidos de OAuth.
Android
En Android, se registra un esquema de dirección URL personalizado mediante la especificación de un
IntentFilter atributo el Activity que va a controlar el esquema. Cuando el proveedor de identidades completa
la solicitud de autorización, redirige a la dirección URL de redireccionamiento de la aplicación. Como la dirección
URL utiliza un esquema personalizado, da como resultado de iniciar la aplicación de Android, pasando la dirección
URL como un parámetro de inicio, donde se procesó la OnCreate método de la Activity registrado para
controlar el esquema de dirección URL personalizado. El ejemplo de código siguiente muestra la clase de la
aplicación de ejemplo que controla el esquema de dirección 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);
Finish();
}
}
IMPORTANT
En Android, se utiliza Xamarin.Auth el CustomTabs API para comunicarse con el sistema operativo y el explorador web. Sin
embargo, no se garantiza que un CustomTabs explorador compatible se instalará en el dispositivo del usuario.
// 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);
}
Así como el método HTTP y la dirección URL de API, el OAuth2Request instancia especifica también una Account
instancia que contiene el token de acceso que firma la solicitud a la dirección URL especificada por el
Constants.UserInfoUrl propiedad. El proveedor de identidades, a continuación, devuelve los datos básicos de
usuario como una respuesta JSON, incluidos el nombre de los usuarios y la dirección de correo electrónico,
siempre que se reconoce como válido el token de acceso. La respuesta JSON, a continuación, se lee y
deserializarse la user variable.
Para obtener más información, consulte una llamada a una API de Google en el portal de desarrolladores de
Google.
Almacenar y recuperar información de cuenta en los dispositivos
Almacena de forma segura Xamarin.Auth Account objetos en una cuenta de almacén para que las aplicaciones no
tienen siempre que vuelva a autenticar a los usuarios. El AccountStore clase es responsable de almacenar
información de la cuenta y está respaldado por servicios de la cadena de claves en iOS y el KeyStore clase en
Android.
El siguiente ejemplo de código muestra cómo un Account objeto se guarda de forma segura:
Guardado de las cuentas se identifican mediante una clave compuesta por la cuenta Username propiedad y un
identificador de servicio, que es una cadena que se utiliza cuando capturando cuentas desde el almacén de
cuentas. Si un Account guardado anteriormente, una llamada a la Save método nuevo sobrescribirá.
Account los objetos para un servicio se puede recuperar mediante una llamada a la FindAccountsForService
método, como se muestra en el ejemplo de código siguiente:
Resumen
En este artículo se explica cómo usar Xamarin.Auth para administrar el proceso de autenticación en una aplicación
de Xamarin.Forms. Xamarin.Auth proporciona el OAuth2Authenticator y OAuth2Request clases que son usadas por
las aplicaciones de Xamarin.Forms para consumir los proveedores de identidades como Microsoft, Google,
Facebook y Twitter.
Vínculos relacionados
OAuthNativeFlow (ejemplo)
OAuth 2.0 para aplicaciones nativas
Uso de OAuth2.0 para tener acceso a las API de Google
Xamarin.Auth (NuGet)
Xamarin.Auth (GitHub)
Autenticar a los usuarios con Azure Active Directory
B2C
11/07/2019 • 17 minutes to read • Edit Online
descargar el ejemplo
Azure B2C de Active Directory proporciona administración de identidad en la nube para aplicaciones móviles y
web orientadas al consumidor. En este artículo se muestra cómo usar Azure Active Directory B2C para integrar la
administración de identidad en una aplicación móvil con la biblioteca de autenticación de Microsoft.
Información general
Azure B2C de Active Directory (ADB2C ) es un servicio de administración de identidades para aplicaciones
orientadas al consumidor. Permite que los usuarios inicien sesión su aplicación con sus cuentas sociales existentes
o las credenciales personalizadas, como correo electrónico o nombre de usuario y contraseña. Las cuentas de
credenciales personalizadas se conocen como local cuentas.
El proceso para integrar el servicio de administración de identidades de Azure Active Directory B2C en una
aplicación móvil es como sigue:
1. Crear a un inquilino de Azure Active Directory B2C
2. Registrar la aplicación móvil con el inquilino de Azure Active Directory B2C
3. Crear directivas de registro e inicio de sesión y ha olvidado flujos de usuario de contraseña
4. Use la biblioteca de autenticación de Microsoft (MSAL ) para iniciar un flujo de trabajo de autenticación con el
inquilino de Azure Active Directory B2C.
NOTE
Azure B2C de Active Directory admite varios proveedores de identidades, incluidos Microsoft, GitHub, Facebook, Twitter y
mucho más. Para obtener más información sobre las capacidades de Azure Active Directory B2C, consulte documentación de
Azure Active Directory B2C.
Biblioteca de autenticación de Microsoft admite varias arquitecturas de aplicaciones y plataformas. Para obtener información
sobre las capacidades MSAL, consulte biblioteca de autenticación de Microsoft en GitHub.
public App()
{
InitializeComponent();
AuthenticationClient = PublicClientApplicationBuilder.Create(Constants.ClientId)
.WithIosKeychainSecurityGroup(Constants.IosKeychainSecurityGroups)
.WithB2CAuthority(Constants.AuthoritySignin)
.Build();
...
...
}
El OnLoginButtonClicked controlador de eventos (que se desencadena cuando se hace clic en el botón de inicio de
sesión) llamadas AcquireTokenAsync . La biblioteca MSAL automáticamente abre el Explorador de dispositivos
móviles y navega a la página de inicio de sesión. La URL de inicio de sesión, denominada una autoridad, es una
combinación del nombre de inquilino y las directivas se definen en el Constants.cs archivo. Si el usuario elige el
olvidó la opción de contraseña, se devuelven a la aplicación con una excepción, que inicia la olvidó la experiencia de
contraseña. El ejemplo siguiente muestra el proceso de autenticación:
public partial class LoginPage : ContentPage
{
...
...
}
El OnForgotPassword método es similar al proceso de inicio de sesión, pero implementa una directiva
personalizada. OnForgotPassword utiliza una sobrecarga diferente del AcquireTokenAsync , que le permite
proporcionar un determinado autoridad. El ejemplo siguiente muestra cómo especificar un personalizado
autoridad al adquirir un token:
while (accounts.Any())
{
await App.AuthenticationClient.RemoveAsync(accounts.First());
accounts = await App.AuthenticationClient.GetAccountsAsync();
}
await Navigation.PopAsync();
}
}
iOS
En iOS, el esquema de dirección URL personalizado que se registró con Azure Active Directory B2C debe estar
registrado en Info.plist. MSAL espera que el esquema de dirección URL para adherirse a un modelo específico, se
ha descrito anteriormente en registrar la aplicación móvil con Azure Active Directory B2C. Captura de pantalla
siguiente muestra el esquema de dirección URL personalizado en Info.plist.
MSAL también requiere derechos de la cadena de claves en iOS, registrados en el Entitilements.plist, tal y como
se muestra en la captura de pantalla siguiente:
Cuando Azure Active Directory B2C se completa la solicitud de autorización, redirige a la URL de
redireccionamiento registrados. Da como resultado el esquema de dirección URL personalizado en iOS iniciando
la aplicación móvil y pasarle la dirección URL como un parámetro de inicio, donde se procesó la OpenUrl la
invalidación de la aplicación AppDelegate clase y devuelve el control de la experiencia de MSAL. El OpenUrl
implementación se muestra en el ejemplo de código siguiente:
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 base.OpenUrl(app, url, options);
}
}
}
Android
En Android, el esquema de dirección URL personalizado que se registró con Azure Active Directory B2C debe
estar registrado en el AndroidManifest.xml. MSAL espera que el esquema de dirección URL para adherirse a un
modelo específico, se ha descrito anteriormente en registrar la aplicación móvil con Azure Active Directory B2C. El
ejemplo siguiente muestra el esquema de dirección URL personalizado en el AndroidManifest.xml.
El MainActivity clase debe modificarse para proporcionar la UIParent objeto a la aplicación durante la OnCreate
llamar. Cuando Azure Active Directory B2C se completa la solicitud de autorización, se redirige a la combinación
de dirección URL registrada desde el AndroidManifest.xml. Da como resultado el esquema URI registrado en
Android que llama a la OnActivityResult método con la dirección URL como un parámetro de inicio, donde se
procesó la SetAuthenticationContinuationEventArgs método.
public class MainActivity : FormsAppCompatActivity
{
protected override void OnCreate(Bundle bundle)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(bundle);
Forms.Init(this, bundle);
LoadApplication(new App());
App.UIParent = this;
}
Vínculos relacionados
AzureADB2CAuth (ejemplo)
Azure Active Directory B2C
Biblioteca de autenticación de Microsoft
Documentación de la biblioteca de autenticación de Microsoft
Autenticar a los usuarios con una base de datos de
documentos de Azure Cosmos DB y Xamarin.Forms
12/07/2019 • 23 minutes to read • Edit Online
Descargar el ejemplo
Azure bases de datos de documento de Cosmos DB admiten colecciones con particiones, que pueden abarcar
varios servidores y particiones, al tiempo que admite almacenamiento ilimitado y rendimiento. En este artículo se
explica cómo combinar el control de acceso con las colecciones con particiones, para que un usuario sólo puede
tener acceso a sus propios documentos en una aplicación de Xamarin.Forms.
Información general
Una clave de partición debe especificarse al crear una colección con particiones y documentos con la misma clave
de partición se almacenarán en la misma partición. Por lo tanto, especificar la identidad del usuario como una clave
de partición dará como resultado de una colección con particiones que sólo van a almacenar documentos de ese
usuario. Esto también garantiza que la base de datos de documentos de Azure Cosmos DB se escalará a medida el
número de usuarios y aumentar los elementos.
Se debe conceder acceso a cualquier colección, y el modelo de control de acceso de API de SQL define dos tipos
de construcciones de acceso:
Las claves maestras habilitar el acceso administrativo completo a todos los recursos dentro de una cuenta de
Cosmos DB y se crean cuando se crea una cuenta de Cosmos DB.
Los tokens de recursos capturan la relación entre el usuario de una base de datos y el permiso el usuario tiene
para un recurso específico de Cosmos DB, como una colección o un documento.
Exponer una clave maestra, abre una cuenta de Cosmos DB a la posibilidad de un uso negligente o
malintencionado. Sin embargo, los tokens de recursos de Azure Cosmos DB proporcionan un mecanismo seguro
para permitir que los clientes leer, escribir y eliminar recursos específicos en una cuenta de Azure Cosmos DB
según los permisos concedidos.
Un enfoque típico para solicitar, generar y entregar tokens de recursos a una aplicación móvil es usar a un agente
de token de recurso. El siguiente diagrama muestra una descripción general de cómo la aplicación de ejemplo usa
a un agente de tokens de recursos para administrar el acceso a los datos de la base de datos de documento:
La resource token broker es un servicio de API Web de nivel intermedio, hospedado en Azure App Service, que
tiene la clave maestra de la cuenta de Cosmos DB. La aplicación de ejemplo usa a la resource token broker para
administrar el acceso a la base de datos de documento como sigue:
1. En el inicio de sesión, la aplicación de Xamarin.Forms se pone en contacto con Azure App Service para iniciar
un flujo de autenticación.
2. Azure App Service realiza un flujo de autenticación de OAuth con Facebook. Una vez que se complete el flujo
de autenticación, la aplicación de Xamarin.Forms recibe un token de acceso.
3. La aplicación de Xamarin.Forms utiliza el token de acceso para solicitar un token de recurso de la resource
token broker.
4. La resource token broker usa el token de acceso para solicitar la identidad del usuario de Facebook. La
identidad del usuario, a continuación, se usa para solicitar un token de recurso de Cosmos DB, que se usa para
conceder acceso de lectura/escritura a la colección con particiones del usuario autenticado.
5. La aplicación de Xamarin.Forms utiliza el token de recurso para acceder directamente a los recursos de Cosmos
DB con los permisos definidos por el token de recurso.
NOTE
Cuando expira el token de recurso, las solicitudes de base de datos de documento posterior recibirá una excepción 401 no
autorizado. En este momento, las aplicaciones de Xamarin.Forms deben volver a establecer la identidad y solicitar un nuevo
token de recurso.
Para obtener más información acerca de la partición de Cosmos DB, consulte partición y escalado en Azure
Cosmos DB. Para obtener más información acerca del control de acceso de Cosmos DB, consulte protección del
acceso a datos de Cosmos DB y control de acceso en la API de SQL.
Programa de instalación
El proceso para integrar a la resource token broker en una aplicación de Xamarin.Forms es como sigue:
1. Cree una cuenta de Cosmos DB que se va a usar el control de acceso. Para obtener más información, consulte
Cosmos DB configuración.
2. Cree un Azure App Service para hospedar a la resource token broker. Para obtener más información, consulte
configuración de Azure App Service.
3. Creación de una aplicación de Facebook para realizar la autenticación. Para obtener más información, consulte
Facebook App Configuration.
4. Configurar el servicio de aplicación de Azure para llevar a cabo la autenticación con Facebook fácil. Para
obtener más información, consulte configuración de autenticación de Azure App Service.
5. Configure la aplicación de ejemplo de Xamarin.Forms para comunicarse con Azure App Service y Cosmos DB.
Para obtener más información, consulte configuración de la aplicación de Xamarin.Forms.
Configuración de Azure Cosmos DB
El proceso de creación de una cuenta de Cosmos DB que se va a usar el control de acceso es como sigue:
1. Cree una cuenta de Cosmos DB. Para obtener más información, consulte crear una cuenta de Azure Cosmos
DB.
2. En la cuenta de Cosmos DB, crear una nueva colección denominada UserItems , especificar una clave de
partición de /userid .
Configuración de Azure App Service
El proceso para hospedar a la resource token broker en Azure App Service es como sigue:
1. En el portal de Azure, cree una nueva aplicación web de App Service. Para obtener más información,
consulte crear una aplicación web en un entorno de App Service.
2. En el portal de Azure, abra la hoja de configuración de la aplicación de la aplicación web y agregue la
siguiente configuración:
accountUrl : el valor debe ser la dirección URL de cuenta de Cosmos DB en la hoja de claves de la
cuenta de Cosmos DB.
accountKey : el valor debe ser la clave maestra para Cosmos DB (principal o secundaria) en la hoja de
claves de la cuenta de Cosmos DB.
databaseId : el valor debe ser el nombre de la base de datos de Cosmos DB.
collectionId : el valor debe ser el nombre de la colección de Cosmos DB (en este caso, UserItems ).
hostUrl : el valor debe ser la dirección URL de la aplicación web en la hoja de información general de la
cuenta de servicio de aplicación.
Captura de pantalla siguiente muestra esta configuración:
3. Publicar la solución de resource token broker en la aplicación web de Azure App Service.
Configuración de la aplicación de Facebook
El proceso de creación de una aplicación de Facebook para realizar la autenticación es el siguiente:
1. Creación de una aplicación de Facebook. Para obtener más información, consulte registrar y configurar una
aplicación en el Centro para desarrolladores de Facebook.
2. Agregar el producto de inicio de sesión de Facebook a la aplicación. Para obtener más información, consulte
agregar inicio de sesión de Facebook a la aplicación o sitio Web en el Centro para desarrolladores de Facebook.
3. Configurar el inicio de sesión de Facebook como sigue:
Habilitar el inicio de sesión de cliente OAuth.
Habilitar el inicio de sesión de OAuth de Web.
Establece el URI para el URI de la aplicación web de App Service, de redirección de OAuth válido con
/.auth/login/facebook/callback anexado.
Captura de pantalla siguiente muestra esta configuración:
La aplicación web de App Service también debe configurarse para comunicarse con la aplicación de Facebook para
habilitar el flujo de autenticación. Esto puede realizarse seleccionando el proveedor de identidades de Facebook, y
especificando el Id. de aplicación y secreto de la aplicación los valores de la configuración de la aplicación de
Facebook en el Centro para desarrolladores de Facebook. Para obtener más información, consulte Facebook
agregar información a la aplicación.
Configuración de la aplicación de Xamarin.Forms
El proceso para configurar la aplicación de ejemplo de Xamarin.Forms es como sigue:
1. Abra la solución Xamarin.Forms.
2. Abra Constants.cs y actualice los valores de las siguientes constantes:
EndpointUri : el valor debe ser la dirección URL de cuenta de Cosmos DB en la hoja de claves de la
cuenta de Cosmos DB.
DatabaseName : el valor debe ser el nombre de la base de datos del documento.
CollectionName : el valor debe ser el nombre de la colección de base de datos de documentos (en este
caso, UserItems ).
ResourceTokenBrokerUrl : el valor debe ser la dirección URL de la aplicación de web resource token
broker en la hoja de información general de la cuenta de servicio de aplicación.
Esto hace que un flujo de autenticación de OAuth que se inicie entre Azure App Service y Facebook, que muestra la
página de inicio de sesión de Facebook:
Se puede cancelar el inicio de sesión presionando el cancelar botón en iOS o presionando el volver botón en
Android, en cuyo caso permanece sin autenticar el usuario y la interfaz de usuario del proveedor de identidad es
Quita de la pantalla.
Para obtener más información acerca de Xamarin.Auth, consulte la autenticación de usuarios con un proveedor de
identidades.
if (!string.IsNullOrWhiteSpace(resourceToken))
{
client = new DocumentClient(new Uri(Constants.EndpointUri), resourceToken);
...
}
...
}
}
};
NOTE
Un usuario de base de datos de documento es un recurso asociado con una base de datos de documento, y cada base de
datos puede contener cero o más usuarios. Un permiso de base de datos de documento es un recurso asociado con un
usuario de base de datos de documento y cada usuario puede contener cero o más permisos. Un recurso de permiso
proporciona acceso a un token de seguridad que requiere que el usuario cuando se intenta tener acceso a un recurso como
un documento.
Si el resourcetoken API se completa correctamente, enviará el código de estado HTTP 200 (OK) en la respuesta,
junto con un documento JSON que contiene el token de recurso. Los siguientes datos JSON muestran un mensaje
de respuesta correcta 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"
}
Recuperación de documentos
Recuperar documentos que pertenecen sólo al usuario autenticado puede lograrse mediante la creación de una
consulta de documento que incluye el identificador del usuario como clave de partición y se muestra en el ejemplo
de código siguiente:
La consulta recupera todos los documentos que pertenecen al usuario autenticado, de la colección especificada,
asincrónicamente y los coloca en un List<TodoItem> colección para su presentación.
El CreateDocumentQuery<T> método especifica un Uri argumento que representa la colección que se debe
consultar documentos, y un FeedOptions objeto. La FeedOptions objeto especifica que se puede devolver un
número ilimitado de elementos por la consulta y el identificador del usuario como clave de partición. Esto
garantiza que se devuelven únicamente los documentos en la colección del usuario con particiones en el resultado.
NOTE
Tenga en cuenta que los documentos de permiso, que son creados por la resource token broker, se almacenan en la misma
colección de documentos que los documentos creados por la aplicación de Xamarin.Forms. Por lo tanto, la consulta de
documento contiene un Where cláusula que se aplica un predicado de filtrado a la consulta en la colección de documentos.
Esta cláusula garantiza que los documentos de permiso no se devuelven de la colección de documentos.
Para obtener más información acerca de cómo recuperar documentos desde una colección de documentos,
consulte recuperar documentos de colección de documentos.
Inserción de documentos
Antes de insertar un documento en una colección de documentos, el TodoItem.UserId propiedad debe actualizarse
con el valor utilizado como clave de partición, como se muestra en el ejemplo de código siguiente:
item.UserId = UserId;
await client.CreateDocumentAsync(collectionLink, item);
Esto garantiza que se insertará el documento en la colección del usuario con particiones.
Para obtener más información sobre cómo insertar un documento en una colección de documentos, consulte
insertar documentos en una colección de documentos.
Eliminación de documentos
El valor de clave de partición debe especificarse al eliminar un documento de una colección con particiones, como
se muestra en el ejemplo de código siguiente:
await client.DeleteDocumentAsync(UriFactory.CreateDocumentUri(Constants.DatabaseName,
Constants.CollectionName, id),
new RequestOptions
{
PartitionKey = new PartitionKey(UserId)
});
Esto garantiza que Cosmos DB sabe que particiones colección para eliminar el documento de.
Para obtener más información sobre cómo eliminar un documento de una colección de documentos, consulte
eliminar un documento de una colección de documentos.
Resumen
En este artículo se explica cómo combinar el control de acceso con las colecciones con particiones, para que un
usuario sólo puede tener acceso a sus propios documentos de base de datos de documento en una aplicación de
Xamarin.Forms. Especificar la identidad del usuario como una clave de partición garantiza que una colección con
particiones solo puede almacenar documentos de ese usuario.
Vínculos relacionados
Todo Azure Cosmos DB Auth (ejemplo)
Consumo de una base de datos de documentos de Cosmos Azure DB
Protección del acceso a datos de Azure Cosmos DB
Control de acceso en la API de SQL.
Cómo crear particiones y escalado en Azure Cosmos DB
Biblioteca de cliente de Azure Cosmos DB
API de Azure Cosmos DB
Implementación y pruebas de Xamarin.Forms
11/07/2019 • 2 minutes to read • Edit Online
Rendimiento
Existen muchas técnicas para aumentar el rendimiento de aplicaciones de Xamarin.Forms. En conjunto, estas
técnicas pueden reducir considerablemente la cantidad de trabajo que está realizando una CPU y la cantidad de
memoria consumida por una aplicación.
Este documento contiene información general sobre las técnicas de distribución que están disponibles para las
aplicaciones Xamarin.iOS y actúa como un punto de partida a documentos más detallados sobre el tema.
Una vez que se ha desarrollado una aplicación de Xamarin.iOS, el siguiente paso del ciclo de vida de desarrollo de
software es distribuirla a los usuarios, como se muestra en la sección destacada del siguiente diagrama:
Apple proporciona los siguientes métodos para distribuir una aplicación de iOS, que son compatibles con
Xamarin.iOS:
1. La App Store
2. Interna (Enterprise)
3. Ad Hoc
Todos estos escenarios requieren que las aplicaciones se aprovisionen mediante el correspondiente perfil de
aprovisionamiento. Los perfiles de aprovisionamiento son archivos que contienen información de firma de código,
así como la identidad de la aplicación y el mecanismo de distribución previsto. También contienen información
sobre en qué dispositivos se puede implementar la aplicación para la distribución que no se realice a través del
App Store.
Se trata de la forma principal mediante la que se distribuyen las aplicaciones de iOS a los consumidores en
dispositivos iOS. Todas las aplicaciones que se envían a la App Store requieren la aprobación de Apple.
Las aplicaciones se envían a la App Store a través de un portal llamado iTunes Connect. La guía Configurar la
aplicación en iTunes Connect proporciona más información sobre cómo configurar y usar este portal para
preparar una aplicación de Xamarin.iOS para su publicación en el App Store.
Es importante tener en cuenta que solo los desarrolladores que pertenecen al Programa para desarrolladores
de Apple tienen acceso a iTunes Connect. Los miembros del Programa para desarrolladores empresariales de
Apple no tienen acceso.
Para obtener más información, visite la guía Distribución a través del App Store.
Distribución interna
A veces denominada Distribución empresarial, la distribución interna permite a los miembros del Programa para
desarrolladores empresariales de Apple distribuir aplicaciones internamente a otros miembros de la misma
organización. La distribución interna tiene las ventajas de no requerir una revisión de la App Store y no tener
ningún límite en el número de dispositivos en los que se puede instalar una aplicación. Sin embargo, es importante
tener en cuenta que los miembros del Programa para desarrolladores empresariales de Apple no tienen
acceso a iTunes Connect y, por lo tanto, el licenciatario es responsable de distribuir la aplicación.
Para obtener más información sobre cómo configurar y cómo distribuir una aplicación de forma interna, consulte
la Guía de distribución interna.
Distribución ad hoc
Los usuarios pueden probar las aplicaciones de Xamarin.iOS a través de la distribución ad hoc, que está disponible
tanto en el Programa para desarrolladores de Apple y el Programa para desarrolladores empresariales de
Apple, y permite realizar la prueba en un máximo de 100 dispositivos iOS. El mejor caso de uso para la
distribución ad hoc es la distribución dentro de una empresa cuando iTunes Connect no es una opción.
Para obtener más información sobre cómo configurar y cómo distribuir una aplicación de forma interna, consulte
la Guía de distribución ad hoc.
Resumen
Este artículo le da una breve introducción a los mecanismos de distribución que están disponibles para las
aplicaciones de Xamarin.iOS. Introduce la iTunes App Store, la implementación interna y ad hoc, y proporciona
vínculos a información más detallada.
Vínculos relacionados
Distribución a través del App Store
Configuración de una aplicación en iTunes Connect
Publicación en App Store
Distribución interna
Distribución ad hoc
Archivo iTunesMetadata.plist
Compatibilidad con IPA
Solución de problemas
Publicar una aplicación
11/07/2019 • 6 minutes to read • Edit Online
Después de crear una gran aplicación, la gente querrá usarla. En este artículo se describen los pasos implicados en
la distribución pública de una aplicación creada con Xamarin.Android a través de canales como el correo
electrónico, un servidor web privado, Google Play o la Tienda Apps de Amazon para Android.
Información general
El paso final en el desarrollo de una aplicación de Xamarin.Android es publicar la aplicación. La publicación es el
proceso de compilación de una aplicación de Xamarin.Android para que esté lista para que los usuarios la instalen
en sus dispositivos, e implica dos tareas esenciales:
Preparar la publicación: se crea una versión de lanzamiento de la aplicación que se puede implementar en
dispositivos Android (consulte Preparar una aplicación para su lanzamiento para más información sobre la
preparación de lanzamiento).
Distribución: la versión de lanzamiento de una aplicación estará disponible a través de uno o varios
canales de distribución.
El siguiente diagrama ilustra los pasos de publicación de una aplicación de Xamarin.Android:
Como puede observarse en el diagrama anterior, la preparación es la misma independientemente del método de
distribución que se utilice. Hay varias formas de poner una aplicación de Android a disposición de los usuarios:
A través de un sitio web: una aplicación Xamarin.Android puede estar disponible para su descarga en un sitio
web, desde el que los usuarios pueden instalarla haciendo clic en un vínculo.
Por correo electrónico: los usuarios pueden instalar una aplicación Xamarin.Android desde su correo
electrónico. La aplicación se instalará cuando se abra el archivo adjunto con un dispositivo Android.
A través de una tienda: existen varias tiendas de aplicaciones para la distribución, como Google Play o la
Tienda Apps de Amazon para Android.
Utilizar una tienda establecida es la manera más común para publicar una aplicación, ya que proporciona la mayor
cobertura de mercado y el máximo control sobre la distribución. Sin embargo, publicar una aplicación a través de
una tienda requiere un esfuerzo adicional.
Varios canales pueden distribuir una aplicación de Xamarin.Android simultáneamente. Por ejemplo, una aplicación
puede publicarse en Google Play, la Tienda Apps de Amazon para Android y también se puede descargar desde un
servidor web.
Los otros dos métodos de distribución (descarga o correo electrónico) son más útiles para un subconjunto de
usuarios, como un entorno empresarial o una aplicación que solo está destinada a un conjunto de usuarios
pequeño o controlado. La distribución a través de un servidor y de correo electrónico también son modelos de
publicación más sencillos, que requieren menos preparación para publicar una aplicación.
El programa de distribución de aplicaciones de Amazon Mobile permite a los desarrolladores de aplicaciones
móviles distribuir y vender sus aplicaciones en Amazon. Los usuarios pueden descubrir y comprar aplicaciones en
sus dispositivos Android mediante la aplicación Tienda Apps de Amazon. A continuación aparece una captura de
pantalla de la Tienda Apps de Amazon en un dispositivo Android:
Google Play es, posiblemente, la tienda más completa y popular para aplicaciones Android. Google Play permite a
los usuarios detectar, descargar, evaluar y pagar por aplicaciones haciendo clic en un solo icono en su dispositivo o
su equipo. Google Play también proporciona herramientas para ayudar en el análisis de ventas y las tendencias del
mercado y controlar qué dispositivos y usuarios pueden descargar una aplicación. A continuación aparece una
captura de pantalla de Google Play en un dispositivo Android:
En esta sección se muestra cómo cargar la aplicación en una tienda, como Google Play, junto con el material
promocional adecuado. Se describen los archivos de expansión del APK y se ofrece información general
conceptual sobre qué son y cómo funcionan. También se describen los servicios de Licencias de Google. Por
último, se presentan medios alternativos de distribución, incluido el uso de un servidor web HTTP, la distribución
por correo electrónico simple y Amazon Appstore para Android.
Vínculos relacionados
HelloWorldPublishing (ejemplo)
Creación de proceso
Vinculación
Obtener una clave de API de Google Maps
Firma de aplicaciones
Publicación en Google Play
Licencias de aplicaciones de Google
Android.Play.ExpansionLibrary
Portal de distribución de aplicaciones móviles
Preguntas más frecuentes sobre la distribución de aplicaciones móviles de Amazon
Publicación de aplicaciones Xamarin.Mac en el Mac
App Store
11/07/2019 • 3 minutes to read • Edit Online
Información general
Las aplicaciones de Xamarin.Mac pueden distribuirse de dos maneras diferentes:
Developer ID: las aplicaciones firmadas con un Developer ID se distribuyen fuera del App Store, pero
Gatekeeper las reconoce y les da permiso para que se instalen.
Mac App Store: las aplicaciones deben tener un paquete de instalación, y la aplicación y el programa de
instalación deben estar firmados para enviarse al Mac App Store.
En este documento se explica cómo utilizar Visual Studio para Mac y Xcode para configurar una cuenta de
desarrollador de Apple y configurar un proyecto de Xamarin.Mac para cada tipo de implementación.
NOTE
Las selecciones realizadas aquí afectarán al modo en que algunas pantallas aparecen al configurar una cuenta de
desarrollador. Las descripciones y las capturas de pantalla de este documento se realizan desde la perspectiva de una cuenta
de desarrollador personal. En una empresa, algunas opciones solo estarán disponibles para los usuarios del Administrador
del equipo.
Certificados e identificadores
En esta guía se describe el proceso de creación de los certificados y los identificadores necesarios para publicar
una aplicación Xamarin.Mac.
Crear un perfil de aprovisionamiento
En esta guía se describe el proceso de creación de los perfiles de aprovisionamiento necesarios para publicar una
aplicación Xamarin.Mac.
Configuración de aplicaciones de Mac
En esta guía se describe el proceso de configuración de una aplicación Xamarin.Mac para su publicación.
Firmar con Developer ID
En esta guía se explican los pasos para firmar una aplicación Xamarin.Mac con Developer ID para su publicación.
Paquete para el Mac App Store
En esta guía se describe el proceso de creación de una aplicación Xamarin.Mac para su publicación en el Mac App
Store.
Cargar en el Mac App Store
En esta guía se describe el proceso de carga de una aplicación Xamarin.Mac para su publicación en el Mac App
Store.
Vínculos relacionados
Instalación
Ejemplo de Hello, Mac
Identificador del desarrollador y equipo selector
Rendimiento de Xamarin.Forms
11/07/2019 • 20 minutes to read • Edit Online
Existen muchas técnicas para aumentar el rendimiento de aplicaciones de Xamarin.Forms. En conjunto, estas
técnicas pueden reducir considerablemente la cantidad de trabajo que está realizando una CPU y la cantidad de
memoria consumida por una aplicación. En este artículo se describen y se explican estas técnicas.
Información general
El mal rendimiento de una aplicación se manifiesta de muchas formas. Puede hacer que parezca que una
aplicación deja de responder, puede ocasionar un desplazamiento lento y puede reducir la duración de la batería.
La optimización del rendimiento conlleva mucho más que la mera implementación de código eficaz. También debe
tenerse en cuenta la experiencia de rendimiento de la aplicación del usuario. Por ejemplo, asegurarse de que las
operaciones se ejecuten sin evitar que el usuario realice otras actividades puede ayudar a mejorar su experiencia.
Existen varias técnicas para aumentar el rendimiento, y la percepción de rendimiento, de una aplicación de
Xamarin.Forms. Son los siguientes:
Habilitar el compilador XAML
Elegir el diseño correcto
Habilitar la compresión de diseño
Usar representadores rápidos
Reducir enlaces innecesarios
Optimizar el rendimiento de diseño
Optimizar el rendimiento de ListView
Optimizar los recursos de imagen
Reducir el tamaño del árbol visual
Reducir el tamaño del diccionario de recursos de aplicación
Usar el patrón de representador personalizado
NOTE
Antes de leer este artículo, debería leer Rendimiento multiplataforma, donde se explican técnicas no específicas de una
plataforma para mejorar el uso de memoria y el rendimiento de las aplicaciones compiladas con la plataforma Xamarin.
<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>
<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>
Además, no intente reproducir el aspecto de un diseño específico mediante combinaciones de otros diseños, dado
que como resultado se realizarían cálculos de diseño innecesarios. Por ejemplo, no intente reproducir un diseño
Grid mediante una combinación de instancias StackLayout . El ejemplo de código siguiente muestra un ejemplo
de esta práctica incorrecta:
<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>
Es una pérdida de tiempo porque se realizan cálculos de diseño innecesarios. En su lugar, el diseño deseado puede
lograrse mejor mediante un Grid , como se muestra en el ejemplo de código siguiente:
<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>
Al descargar una imagen para mostrar con el método ImageSource.FromUri , guarde en la memoria caché la
imagen descargada asegurándose de que la propiedad UriImageSource.CachingEnabled está establecida en true .
Para más información, vea Trabajar con imágenes.
Para más información, vea Optimizar los recursos de imagen.
La segunda técnica es quitar los elementos innecesarios. Por ejemplo, en el ejemplo de código siguiente se
muestra un diseño de página que muestra una serie 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>
Se puede mantener el mismo diseño de página con un número reducido de elementos, como se muestra en el
ejemplo de código siguiente:
<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>
Pero el código de XAML que es específico de una página no debería incluirse en el diccionario de recursos de la
aplicación, dado que los recursos se analizarán en el inicio de la aplicación en lugar de cuando los solicite una
página. Si una página que no es la página de inicio usa un recurso, se debe colocar en el diccionario de recursos
para esa página, para así reducir el código de XAML que se analiza cuando se inicia la aplicación. El siguiente
ejemplo de código muestra el recurso HeadingLabelStyle , que solo se usa en una página, por lo que se define en
el diccionario de recursos de la 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 más información sobre los dominios de aplicación, vea Working with Styles .
if (e.OldElement != null) {
// Unsubscribe from event handlers and cleanup any resources
}
if (e.NewElement != null) {
if (Control == null) {
// Instantiate the native control
}
// Configure the control and subscribe to event handlers
}
}
Solo se debe crear una instancia de un nuevo control nativo una vez, cuando la propiedad Control es null .
Además, solo se debe crear, configurar el control y suscribir los controladores de eventos cuando se adjunta el
presentador personalizado a un nuevo elemento de Xamarin.Forms. De forma similar, solo se debe cancelar la
suscripción de los controladores de eventos que se han suscrito cuando cambia el elemento al que está asociado
el presentador. Adoptar este enfoque facilita crear un presentador personalizado de rendimiento eficaz que no
sufra pérdidas de memoria.
IMPORTANT
El método SetNativeControl solo se debe llamar si e.NewElement no es null .
Para más información sobre presentadores personalizados, vea Personalización de controles en cada plataforma.
Resumen
En este artículo se han descrito y explicado técnicas para aumentar el rendimiento de las aplicaciones de
Xamarin.Forms. En conjunto, estas técnicas pueden reducir considerablemente la cantidad de trabajo que está
realizando una CPU y la cantidad de memoria consumida por una aplicación.
Vínculos relacionados
Rendimiento multiplataforma
Rendimiento de ListView
Representadores rápidos
Compresión de diseño
XamlCompilation
XamlCompilationOptions
Conceptos avanzados y funcionamiento interno
11/07/2019 • 2 minutes to read • Edit Online
Resolución de dependencias
En este artículo se explica cómo insertar un método de resolución de dependencia en Xamarin.Forms para que el
contenedor de inserción de dependencia de la aplicación tiene control sobre la creación y duración de los
representadores personalizados, los efectos, y DependencyService implementaciones.
Representadores rápidos
Este artículo presentan a los representadores rápidos, que reducen la inflación y los costos de representación de un
control de Xamarin.Forms en Android mediante la reducción de la jerarquía de control nativo resultante.
.NET Standard
En este artículo se explica cómo convertir una aplicación de Xamarin.Forms para usar .NET Standard 2.0.
Resolución de dependencias en Xamarin.Forms
11/07/2019 • 19 minutes to read • Edit Online
descargar el ejemplo
En este artículo se explica cómo insertar un método de resolución de dependencia en Xamarin.Forms para que el
contenedor de inserción de dependencia de la aplicación tiene control sobre la creación y duración de los
representadores personalizados, efectos y las implementaciones de DependencyService. Los ejemplos de código
en este artículo se toman de la resolución de dependencia mediante contenedores ejemplo.
En el contexto de una aplicación de Xamarin.Forms que usa el patrón Model-View -ViewModel (MVVM ), un
contenedor de inserción de dependencia puede utilizarse para registrar y resolver los modelos de vista y para
registrar servicios e insertarlas en modelos de vista. Durante la creación del modelo de vista, el contenedor
inserta las dependencias que son necesarias. Si no se han creado esas dependencias, el contenedor crea y
resuelve primero las dependencias. Para obtener más información sobre la inserción de dependencias, incluidos
ejemplos de inyección de dependencias en los modelos de vista, consulte inserción de dependencias.
Control sobre la creación y duración de los tipos de proyectos de la plataforma tradicionalmente se realiza
mediante Xamarin.Forms, que usa el Activator.CreateInstance método para crear instancias de los
representadores personalizados, los efectos, y DependencyService implementaciones. Lamentablemente, esto
limita el control del desarrollador sobre la creación y duración de estos tipos y la capacidad de insertar
dependencias en ellos. Este comportamiento puede modificarse mediante la inserción de un método de
resolución de dependencia en Xamarin.Forms que controla cómo se crearán los tipos: contenedor de inserción de
dependencia de la aplicación, o Xamarin.Forms. Sin embargo, tenga en cuenta que no hay ningún requisito para
insertar un método de resolución de dependencia en Xamarin.Forms. Xamarin.Forms continuará crear y
administrar la duración de los tipos de proyectos de la plataforma, si no se ha insertado un método de resolución
de dependencia.
NOTE
Aunque en este artículo se centra en la inyección de un método de resolución de dependencia en Xamarin.Forms que
resuelve los tipos registrados mediante un contenedor de inserción de dependencia, también es posible insertar un método
de resolución de dependencia que usa los métodos de fábrica para resolver tipos registrados. Para obtener más
información, consulte el resolución de dependencia mediante métodos de generador ejemplo.
public App()
{
...
DependencyResolver.ResolveUsing(type => container.IsRegistered(type) ? container.Resolve(type) :
null);
...
}
...
}
En este ejemplo, el método de resolución de dependencia se establece en una expresión lambda que usa el
contenedor de inserción de dependencia de Autofac para resolver los tipos que se han registrado con el
contenedor. En caso contrario, null se devolverán, lo que dará como resultado en Xamarin.Forms al intentar
resolver el tipo.
NOTE
La API de un contenedor de inserción de dependencia es el contenedor específica. Los ejemplos de código en este artículo
usan Autofac como un contenedor de inserción de dependencia, que proporciona el IContainer y ContainerBuilder
tipos. Contenedores de inserción de dependencia alternativo podrían usarse por igual, pero usaría distintas API que se
presentan aquí.
Tenga en cuenta que no hay ningún requisito para establecer el método de resolución de dependencia durante el
inicio de la aplicación. Se puede establecer en cualquier momento. La única restricción es que necesita saber
sobre el método de resolución de dependencia en el momento en que la aplicación intenta consumir tipos
almacenados en el contenedor de inserción de dependencia Xamarin.Forms. Por lo tanto, si hay servicios en el
contenedor de inserción de dependencias que requiera la aplicación durante el inicio, el método de resolución de
dependencia deberá establecerse al principio de ciclo de vida de la aplicación. De forma similar, si el contenedor
de inserción de dependencia administra la creación y duración de una determinada Effect , deberá conocer el
método de resolución de dependencia antes de intentar crear una vista de Xamarin.Forms que usa Effect .
WARNING
Al registrar y resolver los tipos con un contenedor de inserción de dependencia, estos tienen un costo por uso del
contenedor de la reflexión para la creación de cada tipo, especialmente si se está reconstruyendo dependencias para cada
navegación de páginas en la aplicación de rendimiento. Si hay muchas o pocas dependencias, puede aumentar
significativamente el costo de la creación.
Registro de tipos
Los tipos deben registrarse en el contenedor de inserción de dependencia antes de que pueda resolver a través
del método de resolución de dependencia. El ejemplo de código siguiente muestra los métodos de registro que
expone la aplicación de ejemplo en el App (clase), para el contenedor Autofac:
using Autofac;
using Autofac.Core;
...
public static void RegisterType<TInterface, T>() where TInterface : class where T : class, TInterface
{
builder.RegisterType<T>().As<TInterface>();
}
Cuando una aplicación utiliza un método de resolución de dependencia para resolver los tipos de un contenedor,
los registros de tipo normalmente se realizan desde proyectos de la plataforma. Esto permite que los proyectos
de plataforma registrar los tipos de representadores personalizados, los efectos, y DependencyService
implementaciones.
Después de registro del tipo desde un proyecto de la plataforma, el IContainer objeto debe compilarse, que se
logra mediante una llamada a la BuildContainer método. Este método invoca de Autofac Build método en el
ContainerBuilder instancia, que crea un nuevo contenedor de inyección de dependencia que contiene los
registros que se han realizado.
En las secciones siguientes, un Logger clase que implementa el ILogger interfaz se inyecta en constructores de
clase. El Logger clase registro simple implementa funcionalidad utilizando el Debug.WriteLine método y se usa
para demostrar cómo los servicios se pueden insertar en los representadores personalizados, los efectos, y
DependencyService implementaciones.
<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>
El VideoPlayer vista se implementa en cada plataforma mediante una VideoPlayerRenderer (clase), que
proporciona la funcionalidad para reproducir el vídeo. Para obtener más información sobre estas clases de
representador personalizado, consulte implementa un Reproductor de vídeo.
En iOS y la plataforma Universal de Windows (UWP ), el VideoPlayerRenderer clases tienen el siguiente
constructor, que requiere un ILogger argumento:
En todas las plataformas, realizar el registro de tipo con el contenedor de inserción de dependencia mediante el
RegisterTypes método, que se invoca antes de la plataforma de carga de la aplicación con el
LoadApplication(new App()) método. El ejemplo siguiente se muestra el RegisterTypes método en la plataforma
de iOS:
void RegisterTypes()
{
App.RegisterType<ILogger, Logger>();
App.RegisterType<FormsVideoLibrary.iOS.VideoPlayerRenderer>();
App.BuildContainer();
}
En este ejemplo, el tipo concreto está registrado a través de una asignación con el tipo de interfaz y el
Logger
VideoPlayerRenderer tipo se registrado directamente sin una asignación de interfaz. Cuando el usuario navega a
la página que contiene el VideoPlayer vista, se invocará el método de resolución de dependencia para resolver el
VideoPlayerRenderer tipo desde el contenedor de inserción de dependencia, que también se resolver e insertar el
Logger escriba en el VideoPlayerRenderer constructor.
Efectos de registro
La aplicación de ejemplo incluye una página que usa un toque seguimiento efecto arrastrar BoxView instancias
alrededor de la página. El Effect se agrega a la BoxView con el código siguiente:
El TouchEffect clase es un RoutingEffect que se implementa en cada plataforma mediante una TouchEffect
clase que tiene un PlatformEffect . La plataforma TouchEffect clase proporciona la funcionalidad para arrastrar
el BoxView alrededor de la página. Para obtener más información sobre estas clases efecto, consulte invocar
eventos de efectos.
En todas las plataformas, la TouchEffect clase tiene el siguiente constructor, que requiere un ILogger
argumento:
En todas las plataformas, realizar el registro de tipo con el contenedor de inserción de dependencia mediante el
RegisterTypes método, que se invoca antes de la plataforma de carga de la aplicación con el
LoadApplication(new App()) método. El ejemplo siguiente se muestra el RegisterTypes método en la plataforma
Android:
void RegisterTypes()
{
App.RegisterType<ILogger, Logger>();
App.RegisterType<TouchTracking.Droid.TouchEffect>();
App.BuildContainer();
}
En este ejemplo, el Logger tipo concreto está registrado a través de una asignación con el tipo de interfaz y el
TouchEffect tipo se registrado directamente sin una asignación de interfaz. Cuando el usuario navega a la página
que contiene un BoxView instancia que tiene el TouchEffect conectadas a ella, se invocará el método de
resolución de dependencia para resolver la plataforma TouchEffect tipo a partir de la dependencia contenedor
de inserción, que también se resolver e insertar el Logger escriba en el TouchEffect constructor.
Registrar las implementaciones de DependencyService
La aplicación de ejemplo incluye una página que usa DependencyService implementaciones en cada plataforma
para permitir al usuario elegir una foto de la biblioteca de imágenes del dispositivo. El IPhotoPicker interfaz
define la funcionalidad que se implementa mediante el DependencyService implementaciones y se muestra en el
ejemplo siguiente:
En cada proyecto de la plataforma, el PhotoPicker la clase implementa la IPhotoPicker interfaz mediante las API
de plataforma. Para obtener más información acerca de estos servicios de dependencia, consulte seleccionar una
foto de la biblioteca de imágenes.
En iOS y UWP, la PhotoPicker clases tienen el siguiente constructor, que requiere un ILogger argumento:
En todas las plataformas, realizar el registro de tipo con el contenedor de inserción de dependencia mediante el
RegisterTypes método, que se invoca antes de la plataforma de carga de la aplicación con el
LoadApplication(new App()) método. El ejemplo siguiente se muestra el RegisterTypes método en UWP:
void RegisterTypes()
{
DIContainerDemo.App.RegisterType<ILogger, Logger>();
DIContainerDemo.App.RegisterType<IPhotoPicker, Services.UWP.PhotoPicker>();
DIContainerDemo.App.BuildContainer();
}
En este ejemplo, el Logger tipo concreto está registrado a través de una asignación con el tipo de interfaz y el
PhotoPicker tipo también se registra a través de una asignación de interfaz.
El PhotoPicker constructor en la plataforma Android es un poco más complicado, ya que requiere un Context
argumento además el ILogger argumento:
void RegisterTypes()
{
App.RegisterType<ILogger, Logger>();
App.RegisterTypeWithParameters<IPhotoPicker, Services.Droid.PhotoPicker>(typeof(Android.Content.Context),
this, typeof(ILogger), "logger");
App.BuildContainer();
}
NOTE
El Resolve<T> método se debe usar al resolver un tipo de contenedor de inserción de dependencia de la aplicación a
través de la DependencyService .
Vínculos relacionados
Resolución de dependencia mediante contenedores (ejemplo)
Inserción de dependencias
Implementación de un reproductor de vídeo
Invocación de eventos de efectos
Seleccionar una foto de la biblioteca de imágenes
Representadores rápidos de Xamarin.Forms
11/07/2019 • 3 minutes to read • Edit Online
Tradicionalmente, la mayoría de los representadores de control original en Android se compone de dos vistas:
Control nativo, como un Button o TextView .
Un contenedor ViewGroup que controla algunas de las otras tareas, administración de gestos y el trabajo de
diseño.
Sin embargo, este enfoque tiene una implicación del rendimiento que dos vistas se crean para cada control
lógico, lo que resulta en un árbol visual más compleja que requiere más memoria y más capacidad de
procesamiento para representar en la pantalla.
Los representadores rápidos reducen la inflación y los costos de representación de un control de Xamarin.Forms
en una sola vista. Por lo tanto, en lugar de crear dos vistas y agregarlos al árbol de la vista, se crea uno solo. Esto
mejora el rendimiento porque crea menos objetos, lo que significa que a su vez un árbol de vista menos
complejo, y menos uso de memoria (que también tiene como resultado menos pausas de la colección de
elementos no utilizados).
Representadores rápidos están disponibles para los siguientes controles de Xamarin.Forms en Android:
Button
Image
Label
Frame
NOTE
Los representadores personalizados pueden crearse para representadores rápidos utilizando el mismo enfoque que se usan
para los representadores heredados. Para obtener más información, consulte Custom Renderers (Representadores
personalizados).
Forms.SetFlags("UseLegacyRenderers");
2. Uso de los representadores personalizados que tienen como destino a los representadores heredados. Los
representadores personalizados existentes seguirán funcionando con los representadores heredados.
3. Especificar otro View.Visual , tales como Material , que usa distintos representadores. Para obtener más
información acerca de Material Visual, consulte Xamarin.Forms Material Visual.
Vínculos relacionados
Representadores personalizados
2.0 compatibilidad con .NET standard en
Xamarin.Forms
11/07/2019 • 2 minutes to read • Edit Online
En este artículo se explica cómo convertir una aplicación de Xamarin.Forms para usar .NET Standard 2.0.
Estándar de .NET es una especificación de API de .NET que va a estar disponible en todas las implementaciones.
NET. Resulta más fácil compartir código entre aplicaciones de escritorio, aplicaciones móviles, juegos y servicios
de nube aunando las API idénticas a las diferentes plataformas. Para obtener información acerca de las
plataformas compatibles con el estándar. NET, vea soporte de implementación de .NET.
Bibliotecas de .NET standard son el reemplazo de las bibliotecas de clases portables (PCL ). Sin embargo, una
biblioteca que tenga como destino .NET Standard sigue siendo una PCL y se conoce como una PCL basadas en
.NET Standard. Algunos perfiles de PCL se asignan a las versiones de .NET Standard, y para los perfiles que tienen
una asignación, los tipos de dos biblioteca podrán hacen referencia entre sí. Para obtener más información,
consulte compatibilidad con PCL.
2.4 de Xamarin.Forms permite que las aplicaciones de Xamarin.Forms para el destino .NET Standard 2.0
reemplazando la PCL con una biblioteca .NET Standard 2.0. Esto puede lograrse como sigue:
Asegúrese de .NET Core 2.0 está instalado.
Actualización de la solución de Xamarin.Forms para usar Xamarin.Forms 2.4 o superior.
Agregar una biblioteca .NET Standard a la solución, que tiene como destino .NET Standard 2.0.
Eliminar la clase que se agrega a la biblioteca .NET Standard.
Agregue el paquete de NuGet Xamarin.Forms 2,4 (o superior) a la biblioteca .NET Standard.
En los proyectos de plataforma, agregue una referencia a la biblioteca estándar de .NET y quite la referencia al
proyecto PCL que contiene la lógica de interfaz de usuario de Xamarin.Forms.
Copie los archivos desde el proyecto PCL en la biblioteca .NET Standard.
Quitar el proyecto PCL que contiene la lógica de interfaz de usuario de Xamarin.Forms.
Vínculos relacionados
.NET Standard
Opciones de uso compartido de código
Solución de problemas
11/07/2019 • 3 minutes to read • Edit Online
Esta guía usa la plantilla de biblioteca de Xamarin.Forms .NET Standard como ejemplo, pero también funcionará el
mismo método general para la plantilla de proyecto compartido de Xamarin.Forms. Esta guía está escrita con el
ejemplo de actualización de Xamarin.Forms 1.5.1.6471 a 2.1.0.6529, pero los mismos pasos son posibles
establecer otras versiones como el valor predeterminado en su lugar.
1. Copie la plantilla original .zip desde:
5. Volver a comprimir la carpeta de plantillas completas. Asegúrese de que coincida con la estructura del
archivo original de la .zip archivo. El Xamarin.Forms.PCL.vstemplate archivo debe estar en la parte superior
de la .zip archivo, no dentro de las carpetas.
6. Cree un subdirectorio "Mobile Apps" en la carpeta de plantillas de Visual Studio por usuario:
7. Copie la nueva carpeta de plantillas de comprimir copia de seguridad en el nuevo directorio "Mobile Apps".
8. Descargue el paquete de NuGet que coincida con la versión del paso 3. Por ejemplo,
http://nuget.org/api/v2/package/Xamarin.Forms/2.1.0.6529 (Vea también
https://stackoverflow.com/questions/8597375/how -to-get-the-url-of-a-nupkg-file ) y cópiela en la
subcarpeta correspondiente de la carpeta de extensiones de Xamarin Visual Studio:
C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\Extensions\Xamarin\Xamarin\[Xamarin
Version]\Packages
¿Por qué no funciona el diseñador XAML de Visual
Studio para los archivos XAML de Xamarin.Forms?
11/07/2019 • 2 minutes to read • Edit Online
Xamarin.Forms no admite actualmente los diseñadores visuales para los archivos XAML. Por este motivo, al
intentar abrir un archivo XAML de Forms en Visual Studio Diseñador de IU XAML o Diseñador de IU XAML con
codificación, se produce el siguiente mensaje de error:
"No se puede abrir el archivo con el editor seleccionado. Elija otro editor."
Esta limitación se describe en el Introducción sección de la conceptos básicos de XAML de Xamarin.Forms guía:
"No hay todavía un diseñador visual para generar XAML en las aplicaciones de Xamarin.Forms, por lo que
todo XAML debe ser escrito a mano."
Sin embargo, se pueden mostrar la vista previa de XAML de Xamarin.Forms seleccionando el View > Other
Windows > controlador de vista previa de Xamarin.Forms opción de menú.
Error de compilación de Android: tarea
LinkAssemblies el error inesperado
11/07/2019 • 3 minutes to read • Edit Online
Es posible que vea un mensaje de error The "LinkAssemblies" task failed unexpectedly al compilar un proyecto de
Xamarin.Android que usa formularios. Esto sucede cuando el vinculador está activo (normalmente en un versión
compilación para reducir el tamaño del paquete de aplicación); y se produce debido a los destinos de Android no
se actualizan a la última versión de framework. (Obtener más información: Xamarin.Forms para Android
requisitos)
La solución a este problema consiste en asegurarse de que dispone de las versiones de Android SDK más reciente
compatibles y establezca el .NET Framework de destino a la última plataforma instalada. También se
recomienda que establezca el versión Android de destino a la última plataforma instalada y el versión Android
mínima en API 19 o superior. Esto se considera la configuración admitida.
Este error puede aparecer en el panel de errores de Visual Studio para Mac o en la ventana de salida de la
compilación de Visual Studio; en los proyectos mediante xamarin.Forms.Maps para Android.
Normalmente, esto se resuelve al aumentar el tamaño del montón de Java para el proyecto de Xamarin.Android.
Siga estos pasos para aumentar el tamaño del montón:
descargar el ejemplo
El libro Creating Mobile Apps with Xamarin.Forms por Charles Petzold es una guía para
obtener información sobre cómo escribir aplicaciones de Xamarin.Forms. El único requisito
previo es el conocimiento de la C# lenguaje de programación. El libro ofrece una amplia
exploración en la interfaz de usuario de Xamarin.Forms y también cubre la animación, MVVM,
desencadenadores, comportamientos, los diseños personalizados, los representadores
personalizados y mucho más.
El libro se publicó en la primavera de 2016 y no se ha actualizado desde entonces. Hay mucho en el libro que
valioso permanece, pero algunos de los material está obsoleto, y algunos temas ya no son completamente
correcto o completo.
Muestras
Los ejemplos están disponibles en github e incluyen proyectos de iOS, Android y la Plataforma universal de
Windows (UWP ). (Xamarin.Forms ya no es compatible con Windows 10 Mobile, pero las aplicaciones de
Xamarin.Forms se ejecutarán en el escritorio de Windows 10).
NOTE
Notas en cada página indican que diverge Xamarin.Forms desde el material presentado en el libro.
Muestras
En el xamarin-forms-book-samples repositorio de GitHub, el código original de libro rama contiene
ejemplos de programa coherentes con el libro. El maestro rama contiene proyectos que se han actualizado para
quitar la API en desuso y reflejar las API mejoradas. Además, los proyectos de Android de la maestro rama se
han actualizado para Android Material Design a través de AppCompat y generalmente se mostrará el texto negro
sobre un fondo blanco.
Vínculos relacionados
Blog de Microsoft Press
Código de ejemplo del libro
Patrones de aplicación empresarial utilizando el libro
electrónico de Xamarin.Forms
11/07/2019 • 9 minutes to read • Edit Online
Guía de arquitectura para el desarrollo de Xamarin.Forms adaptables, fáciles de mantener y probar las
aplicaciones empresariales
Este libro electrónico proporciona instrucciones sobre cómo implementar el patrón Model-View -ViewModel
(MVVM ), la inserción de dependencias, navegación, validación y la administración de configuración, manteniendo
el acoplamiento flexible. Además, también hay una guía sobre cómo realizar la autenticación y autorización con
IdentityServer, acceso a datos de microservicios en contenedores y las pruebas unitarias.
Prefacio
En este capítulo se explica el propósito y el ámbito de la guía, y a quién está destinada.
Introducción
Los desarrolladores de aplicaciones empresariales enfrentan a varios desafíos que pueden modificar la arquitectura
de la aplicación durante el desarrollo. Por lo tanto, es importante compilar una aplicación para que se pueda
modificar o extender con el tiempo. Diseño de la capacidad de dichos adaptación puede ser difícil, pero
normalmente implica dividir una aplicación en componentes discretos y con acoplamiento flexible que pueden
integrarse fácilmente entre sí en una aplicación.
MVVM
El patrón Modelo-Vista-Modelo de vista (MVVM ) ayuda a separar la lógica de negocios y presentación de una
aplicación de su interfaz de usuario. Mantener una separación clara entre la lógica de aplicación y la interfaz de
usuario ayuda a abordar numerosos problemas de desarrollo y puede hacer que probar una aplicación, mantenerla
y desarrollarla sea más fácil. También puede mejorar enormemente las oportunidades de reutilización de código y
permite a los desarrolladores y diseñadores de interfaz de usuario colaborar con mayor facilidad al desarrollar sus
respectivos elementos de una aplicación.
Inserción de dependencias
Inserción de dependencias permite la separación de tipos concretos desde el código que dependa de estos tipos.
Normalmente usa un contenedor que contiene una lista de registros y las asignaciones entre tipos e interfaces
abstractos y los tipos concretos que implementan o amplían estos tipos.
Contenedores de inserción de dependencia reducen el acoplamiento entre objetos por lo que proporciona una
funcionalidad para crear instancias de clase y administra su duración en función de la configuración del contenedor.
Durante la creación de objetos, el contenedor inserta las dependencias que requiere el objeto en él. Si aún no se
han creado esas dependencias, el contenedor crea y resuelve primero sus dependencias.
Navegación
Xamarin.Forms incluye compatibilidad con la navegación de página, que normalmente da como resultado de la
interacción del usuario con la interfaz de usuario o de la aplicación, como resultado de los cambios de estado
controlado por la lógica interna. Sin embargo, navegación puede ser difícil de implementar en las aplicaciones que
usan el patrón MVVM.
Este capítulo presenta un NavigationService (clase), que se usa para realizar la navegación de model first de vista
de modelos de vista. Colocar en la vista lógica de navegación clases de modelo significa que la lógica puede
realizarse a través de pruebas automatizadas. Además, el modelo de vista, a continuación, puede implementar la
lógica para controlar el desplazamiento para garantizar que se apliquen determinadas reglas empresariales.
Validación
Cualquier aplicación que acepte entradas de los usuarios debe asegurarse de que la entrada sea válida. Sin
validación, un usuario puede proporcionar datos que hagan que la aplicación produzca un error. La validación
aplica reglas de negocio e impide que un atacante inserte datos malintencionados.
En el contexto de Model-View -ViewModel (MVVM ) de patrón, un modelo de vista o modelo a menudo se
requerirá para realizar la validación de datos y señalar los errores de validación a la vista para que el usuario puede
corregirlos.
Administración de configuraciones
La configuración permite la separación de datos que configuran el comportamiento de una aplicación desde el
código, lo que permite cambiar el comportamiento sin volver a compilar la aplicación. La configuración de la
aplicación se compone de datos que una aplicación crea y administra, y la configuración de usuario es la
configuración personalizable de una aplicación que afecta al comportamiento de la aplicación y no es necesario
volver a ajustarla a menudo.
Microservicios en contenedores
Los Microservicios ofrecen un enfoque al desarrollo de aplicaciones e implementación que se adapte a los
requisitos de agilidad, escalabilidad y confiabilidad de aplicaciones modernas en la nube. Una de las principales
ventajas de los microservicios es que pueden ser escaladas horizontalmente de forma independiente, lo que
significa que se puede escalar un área funcional específica que requiere más procesamiento de energía o ancho de
banda para admitir la demanda, sin escalado innecesariamente áreas de la aplicación que no está experimentando
una mayor demanda.
Autenticación y autorización
Existen muchos enfoques para integrar la autenticación y autorización en una aplicación de Xamarin.Forms que se
comunica con una aplicación web ASP.NET MVC. En este caso, la autenticación y autorización se realizan con un
microservicio en contenedor de identidad que usa 4 IdentityServer. IdentityServer es un marco de código abierto
de OAuth 2.0 y OpenID Connect para ASP.NET Core que se integra con ASP.NET Core Identity para realizar la
autenticación de token de portador.
Pruebas unitarias
Probar los modelos y los modelos de vista de las aplicaciones MVVM es idéntica a las pruebas de otras clases, y se
pueden usar las mismas herramientas y técnicas. Sin embargo, hay algunos patrones típicos de modelo y las clases
de modelo de vista, que pueden beneficiarse de las técnicas de pruebas de unidad específica.
Comentarios
Este proyecto tiene un sitio de la Comunidad, en el que puede publicar preguntas y proporcionar comentarios. El
sitio de la Comunidad se encuentra en GitHub. Como alternativa, se pueden enviar comentarios sobre el libro
electrónico a dotnet-architecture-ebooks-feedback@service.microsoft.com .
Vínculos relacionados
Descargar libro electrónico (PDF de 2Mb)
eShopOnContainers (GitHub) (ejemplo)
Gráficos de SkiaSharp en Xamarin.Forms
11/07/2019 • 5 minutes to read • Edit Online
descargar el ejemplo
Uso SkiaSharp para gráficos 2D en las aplicaciones de Xamarin.Forms
SkiaSharp es un sistema de gráficos 2D para .NET y C# funciona con el motor de gráficos de Skia de código
abierto que se usa habitualmente en productos de Google. Puede usar SkiaSharp en sus aplicaciones de
Xamarin.Forms para dibujar texto, mapas de bits y gráficos vectoriales en 2D. Consulte la plano 2D guía para
obtener información general sobre la biblioteca de SkiaSharp y algunos otros tutoriales.
En esta guía se da por supuesto que está familiarizado con la programación de Xamarin.Forms.
IMPORTANT
El SkiaSharp.Views.Forms espacio de nombres también contiene un SKGLView clase que derive de View pero usa
OpenGL para representar gráficos. Para fines de simplicidad, esta guía restringe a sí mismo a SKCanvasView , pero al usar
SKGLView en su lugar, es bastante similar.
Transformaciones de SkiaSharp
Las transformaciones permiten que los objetos gráficos uniformemente traducido, escalar, girar, o sesgar.En este
artículo también muestra cómo puede utilizar una matriz de transformación de 3 por 3 estándar para crear
transformaciones no afines y aplicar transformaciones a rutas de acceso.
Efectos de SkiaSharp
Los efectos son propiedades que cambian la visualización de gráficos, incluidos los degradados lineales y
circulares normal, disposición en mosaico de mapa de bits, blend modos de desenfoque y otros usuarios.
Vínculos relacionados
API de SkiaSharp
SkiaSharpFormsDemos (ejemplo)
SkiaSharp con Xamarin.Forms seminario Web (vídeo)