Documentos de Académico
Documentos de Profesional
Documentos de Cultura
09 Manual de Silverlight
09 Manual de Silverlight
¿Qué es Silverlight?
Silverlight permite crear aplicaciones de vanguardia con las siguientes características:
Es una tecnología multiplataforma que se ejecuta en varios exploradores. Se ejecuta en todos los
exploradores web conocidos, como Microsoft Internet Explorer, Mozilla Firefox, Apple Safari y
Google Chrome, así como en Microsoft Windows y Apple Mac OS X.
Es una descarga pequeña que se instala en pocos segundos.
Transmite los contenidos de audio y vídeo por secuencias. Ajusta el contenido de vídeo a todo tipo
de calidades, desde dispositivos móviles hasta exploradores de escritorio y modos de vídeo HDTV
de 720p.
Incluye gráficos atractivos que los usuarios pueden manipular (arrastrar, girar y acercar o alejar)
directamente en el explorador.
Lee datos y actualiza la pantalla, pero no interrumpe al usuario al actualizar la página completa.
La aplicación se puede ejecutar en el explorador web o se puede configurar de modo que los
usuarios puedan ejecutarla en su equipo (ejecución fuera del explorador).
Aplicación de Silverlight con gráficos enriquecidos e interacción con el usuario
Los desarrolladores web y diseñadores de gráficos pueden crear aplicaciones de Silverlight de diversas
maneras. Se puede utilizar el marcado de Silverlight para crear elementos multimedia y gráficos y
manipularlos con lenguajes dinámicos y código administrado. Silverlight también permite utilizar
herramientas de calidad profesional, como Visual Studio para la codificación y Microsoft Expression Blend
para la esquematización y el diseño gráfico.
Controles
Control RichTextBox
El control RichTextBox permite mostrar, escribir y modificar texto enriquecido. Es posible aplicar formato de
caracteres o de párrafos al texto, mostrar hipervínculos y agregar imágenes incorporadas.
Control Viewbox
El control Viewbox es un decorador de contenido que toma un elemento secundario y lo ajusta o lo escala
de acuerdo con el tamaño de Viewbox.
Control WebBrowser
El control WebBrowser proporciona una superficie para mostrar contenido HTML cuando la aplicación se
ejecuta fuera del explorador.
Control WebBrowserBrush
El control WebBrowserBrush se puede usar para mostrar el contenido HTML de un control WebBrowser. Por
ejemplo, se puede utilizar un control WebBrowserBrush para dibujar el relleno (Fill) de una forma, como
Rectangle, o el contenido de la geometría de una forma Path.
Multimedia
Cámara web y micrófono
Ahora, es posible capturar la entrada de origen del dispositivo de audio o de vídeo del usuario. El método
CaptureImageAsync habilita un escenario de captura de pantalla simple y el método VideoBrush.SetSource
habilita un escenario de reproducción de vídeo simple. En escenarios más avanzados, se puede obtener
acceso a los datos de audio o vídeo sin formato para procesarlos en formatos de archivo. Para las capturas
de cámara web y de micrófono, se usa una metáfora de receptor para establecer una clase de agente de
escucha y, para obtener una captura, se requiere el permiso del usuario del cliente para obtener acceso al
dispositivo de captura.
DRM para escenarios sin conexión
Hay varias características nuevas integradas en la administración de derechos digitales (DRM) de Silverlight
que se pueden utilizar para implementar escenarios sin conexión, como compras, descargas, alquileres y
suscripciones.
Varias transformaciones
Ahora, se puede utilizar la clase CompositeTransform para aplicar varias transformaciones al mismo objeto,
como sesgos y giros. Esta clase aplica varias transformaciones en un orden de preferencia y, en general, se
presta mejor para la aplicación de varias transformaciones a un objeto que la clase TransformGroup.
Redes
Multidifusión
El espacio de nombres System.Net.Sockets ha agregado compatibilidad con los clientes de multidifusión
UDP. De este modo, los clientes de red podrán aprovechar las aplicaciones de multidifusión que usen más
eficazmente los recursos de la red.
Recuperar la directiva de seguridad de sockets a través de HTTP
En el caso de una solicitud de conexión mediante System.Net.Sockets, una aplicación puede optar por
recuperar el archivo de directivas de los sockets a través del protocolo HTTP en el puerto TCP 80 en lugar
del protocolo TCP personalizado en el puerto 943. Esto permite a los servidores HTTP que ya ejecutan
servicios HTTP autorizar las conexiones mediante sockets de las aplicaciones de Silverlight sin tener que
implementar un nuevo servicio TCP en el servidor ni abrir un puerto a través de un firewall para el puerto
943. El archivo de directivas de los sockets se recupera a través de HTTP usando como host la dirección IP
resuelta que es el destino de la conexión de socket. Esto da lugar a una directiva autoritativa en el nivel de
equipo para el destino que es necesaria para los recursos del equipo, como los sockets. En cambio, el
archivo de directivas que usan las clases HTTP y WebClient en el espacio de nombres System.Net se
recupera del dominio de host que es el destino de la solicitud HTTP. El protocolo HTTP permite aislar los
recursos según el dominio a través del encabezado Host.
Directiva de seguridad flexible para aplicaciones de confianza
El espacio de nombres System.Net.Sockets incluye compatibilidad con las restricciones de directivas de
seguridad flexibles que se aplican a las aplicaciones de confianza de ejecución fuera del explorador que se
comunican mediante System.Net.Sockets.
Procesamiento de HTTP de cliente
Se han agregado varias características que se pueden usar cuando se opta por el procesamiento de HTTP de
cliente para las llamadas de conexión de red:
El encabezado Referer se envía con todas las solicitudes
Compatibilidad con la autenticación básica y NTLM
Compatibilidad con el almacenamiento en caché
Capacidad para habilitar o deshabilitar el almacenamiento en búfer de secuencias de las solicitudes
de lectura y escritura
El límite de conexiones simultáneas aumenta de 2 a 6
Impresión
Ahora, es posible imprimir la interfaz de usuario de una aplicación de Silverlight mediante la clase
PrintDocument. PrintDocument permite mostrar al usuario un cuadro de diálogo de impresión e imprimir la
aplicación o un elemento UIElement de la aplicación.
Interfaz de usuario
Arrastrar y colocar
Silverlight 4 incluye varias API para admitir operaciones de arrastrar y colocar. Se puede seleccionar una lista
de archivos en aplicaciones fuera del área de contenido de Silverlight, por ejemplo, Mis documentos en
Microsoft Windows. A continuación, se puede arrastrar la lista de archivos seleccionada al área de contenido
de Silverlight, controlar los eventos de colocación en un elemento de destino concreto y, a continuación,
procesar la lista de archivos mediante la información especificada por FileInfo, incluido el acceso al
contenido de los archivos a través de secuencias. Para habilitarlo, hay que agregar el evento Drop así como
los eventos y propiedades relacionados a la clase UIElement base. Las clases de soporte, como
DragEventArgs, también van incluidas.
Acceso al Portapapeles
Silverlight 4 incluye varias API para admitir el acceso al objeto Clipboard. Se puede obtener o establecer la
información de texto Unicode en un objeto Clipboard compartido. Observe que ese acceso requiere el
permiso del usuario y se limita a los datos de texto Unicode. Hay restricciones adicionales, las cuales se
describen en el tema referente a Clipboard.
Eventos que se producen al hacer clic con el botón secundario del mouse
Silverlight 4 agrega los eventos MouseRightButtonDown y MouseRightButtonUp a la clase UIElement base.
Ahora, las aplicaciones pueden controlar los eventos que se producen al hacer clic con el botón secundario
del mouse y cambiar el comportamiento. De forma predeterminada, cuando el usuario hace clic con el
botón secundario en una aplicación de Silverlight, se abre el cuadro de diálogo de configuración de
Silverlight.
Comandos
En Silverlight 4, ButtonBase e Hyperlink admiten las propiedades Command y CommandParameter. La
propiedad Command puede hacer referencia a una implementación de ICommand que procede del origen
de datos de un modelo de vista, a través de {Binding}. El sistema de entrada de Silverlight interpretará el
comando en tiempo de ejecución.
Estilos implícitos
Ahora, Style puede establecerse implícitamente. Los estilos implícitos permiten aplicar un estilo concreto a
todos los elementos de un tipo determinado.
Dirección de flujo de derecha a izquierda
Ahora, es posible establecer la dirección del contenido y del diseño de cada control de modo que fluya de
la derecha a la izquierda. Esto permite desarrollar aplicaciones de Silverlight en idiomas como el hebreo y el
árabe. La dirección de flujo se establece mediante la propiedad FlowDirection.
Compatibilidad con pantalla completa
Ahora, Silverlight permite a las aplicaciones permanecer en modo de pantalla completa cuando está activa
otra aplicación.
Cambios en la API de elementos base
Además de las características anteriores, los siguientes cambios realizados en DependencyObject, UIElement
y FrameworkElement pueden ser interesantes para los escenarios de la interfaz de usuario:
Ahora, la propiedad FrameworkElement.Cursor puede establecerse con las API del sistema de
propiedades.
FrameworkElement tiene un evento Unloaded.
Los eventos de texto para los editores de métodos de entrada se admiten en el nivel de UIElement
de modo que se pueda aprovechar el enrutamiento.
Las llamadas al método SetValue son más coherentes con el comportamiento equivalente de WPF,
sobre todo en el caso de animaciones en ejecución.
XAML
Silverlight 4 incluye un nuevo analizador de XAML como parte del runtime de Silverlight. El nuevo
analizador de XAML en Silverlight proporciona:
Mayor compatibilidad con el lenguaje XAML escrito originalmente para WPF.
Mayor compatibilidad con el lenguaje XAML definido en la especificación [MS XAML].
Permite a las herramientas y otros consumidores de XAML integrar de manera más predecible la
experiencia en tiempo de diseño del lenguaje XAML en Silverlight.
Para optimizar la compatibilidad con las aplicaciones de Silverlight 3, el runtime de Silverlight 4 incluye el
analizador de XAML de Silverlight 3. El analizador de XAML de Silverlight 3 se utiliza para cargar el XAML de
aplicaciones que tienen específicamente Silverlight 3 como destino. El nuevo analizador carga el XAML de
las aplicaciones cuyo destino es Silverlight 4. Los dos analizadores existen en paralelo.
Hay algunas diferencias entre el XAML de Silverlight y el XAML de WPF.
Data
Enlace de datos
Ahora, el enlace de datos de Silverlight admite las siguientes características:
Enlace a instancias de DependencyObject.
Enlace a indizadores de String.
Capacidad para especificar las opciones de formato de String a través de la propiedad
StringFormat.
Capacidad para especificar los valores de presentación predeterminados a través de las
propiedades TargetNullValue y FallbackValue.
Capacidad para agrupar los elementos de colección a través de la propiedad GroupDescriptions de
la clase CollectionViewSource.
Compatibilidad con la interfaz ICollectionViewFactory, que permite a las colecciones de entidades
de datos proporcionar implementaciones personalizadas de ICollectionView a las clases DataGrid y
CollectionViewSource.
Compatibilidad con una validación compleja de varias propiedades de objetos enlazados que
implementan la interfaz IDataErrorInfo o INotifyDataErrorInfo. Esto incluye compatibilidad con estas
interfaces por parte del motor de enlaces y los controles de la interfaz de usuario, como DataGrid.
Una nueva clase DataServiceCollection(Of T) proporciona enlaces simplificados para los datos devueltos por
Servicios de datos de WCF. Esta clase hereda de la clase ObservableCollection(Of T) para actualizar
automáticamente los datos enlazados cuando se producen cambios en los datos de los controles enlazados.
Servicios de datos de WCF
Se ha agregado la siguiente funcionalidad al cliente de Servicios de datos de WCF en esta versión de
Silverlight:
Una nueva clase DataServiceCollection(Of T) proporciona enlaces simplificados de los datos de los
servicios de datos a los controles de Silverlight. Esta clase hereda de la clase
ObservableCollection(Of T) para actualizar automáticamente los datos enlazados cuando se
producen cambios en los datos de los controles enlazados.
Ahora, el cliente de Servicios de datos de WCF en Silverlight admite la ejecución fuera del
explorador y la ejecución entre dominios.
El cliente de Servicios de datos de WCF admite la siguiente nueva funcionalidad de Open Data Protocol
(OData) en esta versión de Silverlight:
Un servicio OData puede devolver únicamente el número total de los recursos representados por
un URI o incluir esta información referente al recuento de filas junto con los datos de los recursos
en una sola respuesta. El cliente de Servicios de datos de WCF para Silverlight se ha actualizado de
modo que se pueda obtener acceso a esta información referente al recuento de filas que va
incluida en la respuesta a una consulta de la aplicación.
Un servicio de datos se puede configurar de modo que los recursos solicitados se devuelvan como
un conjunto de respuestas paginadas. El cliente de Servicios de datos de WCF para Silverlight se ha
actualizado de modo que permita administrar esas respuestas paginadas.
Ahora, los resultados de consulta devueltos por un servicio OData pueden proyectarse en tipos
definidos arbitrariamente. El cliente de Servicios de datos de WCF para Silverlight se ha actualizado
de modo que se admita la proyección mediante la cláusula select (Select en Visual Basic) en una
consulta LINQ.
El cliente de Servicios de datos de WCF para Silverlight se ha actualizado de modo que sea posible
obtener y establecer las propiedades binarias como una secuencia de un servicio OData compatible
con los recursos multimedia.
Modelo de aplicaciones
Servicios RIA de WCF
Los servicios RIA de WCF simplifican el desarrollo de soluciones de n niveles para aplicaciones de Internet
enriquecidas (RIA), como las aplicaciones de Silverlight. Uno de los problemas comunes al desarrollar
soluciones RIA de n niveles es la coordinación de la lógica de aplicación entre el nivel intermedio y el nivel
de presentación. Los servicios RIA resuelven este problema ya que proporcionan componentes de marco de
trabajo, herramientas y servicios que hacen que la lógica de aplicación en el servidor esté disponible para el
cliente de RIA sin tener que duplicar manualmente esa lógica de programación. Los servicios RIA funcionan
con Silverlight 4 pero están disponibles como una instalación independiente.
Extensibilidad de la navegación
Es posible extender la navegación de Silverlight para admitir la resolución arbitraria de los identificadores
URI. Por ejemplo, se pueden implementar extensiones de navegación para la redirección de los
identificadores URI, la generación de páginas dinámicas y la descarga a petición de páginas del servidor.
Las clases NavigationService y Frame también proporcionan un método Refresh. Este método resulta útil en
el caso de usar extensiones de navegación que pueden proporcionar contenido diferente para el mismo
identificador URI según las interacciones con el usuario en una página determinada. Por ejemplo, esto
habilita algunos escenarios de navegación con páginas que requieren la autenticación del usuario.
Dynamic Language Runtime
Dynamic Language Runtime (DLR) es un nuevo entorno en tiempo de ejecución que agrega a CLR un
conjunto de servicios para lenguajes dinámicos. Para admitir DLR, se ha agregado el nuevo espacio de
nombres System.Dynamic a .NET Framework y se han extendido los árboles de expresión con nuevos tipos
que representan el flujo de control, como LoopExpression y TryExpression.
Principal
Clases de colección
La nueva interfaz ISet(Of T) permite la abstracción de los conjuntos. Los conjuntos son colecciones que
tienen elementos únicos y operaciones específicas. La clase HashSet(Of T), que ahora está disponible para
las aplicaciones basadas en Silverlight, implementa la interfaz ISet(Of T).
Tuplas
Silverlight 4 proporciona la clase Tuple para crear objetos de tupla que contienen datos estructurados.
También proporciona clases de tupla genéricas que tienen de uno a siete parámetros de tipo para
representar singletons, pares, triples, cuádruplos, etc. Para admitir objetos de tupla con nueve o más
componentes, hay una clase de tupla genérica que tiene siete parámetros de tipo y un octavo parámetro de
cualquier tipo de tupla.
Analizar y dar formato a los intervalos de tiempo
Para admitir un formato que tiene en cuenta la referencia cultural, ahora la estructura TimeSpan implementa
la interfaz IFormattable e incluye nuevas sobrecargas de los métodos ToString, Parse, TryParse, ParseExact y
TryParsExact. Sus métodos de formato y de análisis también admiten cadenas de formato estándar y
personalizado.
Otras características básicas
En la lista siguiente, se describen las nuevas capacidades y mejoras que se han agregado a Silverlight.
Algunas de ellas están basadas en sugerencias de los clientes.
El nuevo método String.IsNullOrWhiteSpace indica si una cadena es nula, está vacía o consta solo
de caracteres de espacio en blanco. Se han agregado nuevas sobrecargas a los métodos String.Join
y String.Concat, que concatenan los miembros de colecciones
System.Collections.Generic.IEnumerable(Of T).
El método String.Concat permite concatenar todos los elementos de una colección enumerable sin
convertir primero los elementos en cadenas.
El método StringBuilder.Clear permite borrar con mayor facilidad una instancia de StringBuilder.
El nuevo método Enum.HasFlag determina si uno o más campos o marcas de bits están
establecidos en un valor de enumeración. El método Enum.TryParse devuelve un valor booleano
que indica si una cadena o un valor entero se pudo analizar correctamente.
Las aplicaciones de confianza pueden utilizar las nuevas sobrecargas del método Path.Combine que
permiten combinar rutas de acceso a archivos.
Los nuevos métodos de enumeración de archivos pueden mejorar el rendimiento de las
aplicaciones de confianza que obtienen acceso a directorios o que iteran por las líneas de archivos
de gran tamaño. Solo se puede obtener acceso a los directorios y archivos ubicados en Mis
documentos.
Ahora puede habilitar la inicialización diferida para cualquier tipo personalizado ajustando el tipo
dentro de una clase System.Lazy(Of T).
La nueva sobrecarga del método Monitor.Enter(Object, Boolean) toma una referencia booleana y la
establece de forma atómica en true solo si se entra correctamente en el monitor.
Ahora, la estructura System.Guid contiene los métodos TryParse y TryParseExact.
Silverlight Designer
En Visual Studio 2010, se han realizado varias mejoras del diseñador para ayudar a crear aplicaciones de
Silverlight. En Visual Studio 2008, la compatibilidad del diseñador con los proyectos de Silverlight era
limitada. Ahora, en Visual Studio 2010, se pueden realizar tareas, como seleccionar y colocar elementos con
el mouse en la superficie de diseño así como establecer propiedades en la ventana Propiedades.
Requisitos previos
Puede ejecutar todos los ejemplos de este tema sin necesidad de instalar nada, salvo el motor en tiempo de
ejecución de Silverlight 4. Sin embargo, si desea compilar o modificar los ejemplos, necesitará Silverlight
Tools y un proyecto de trabajo de Silverlight.
En este tema se usa la API administrada para Silverlight. También puede desarrollar aplicaciones basadas en
Silverlight utilizando la API de JavaScript para Silverlight.
XAML
XAML es un lenguaje de marcado declarativo que puede usar para definir los elementos de la interfaz de
usuario de la aplicación basada en Silverlight. Al crear un nuevo proyecto de Visual Studio, se crea
automáticamente un archivo Page.xaml. En el archivo de XAML, puede crear objetos y definir sus
propiedades mediante etiquetas y atributos XML.
A continuación se muestra una instrucción XAML simple que crea un rectángulo rojo.
Puede crear todas las interfaces de usuario en XAML, usar la superficie de diseño de Visual Studio o puede
usar Microsoft Expression Blend para diseñar la aplicación. Expression Blend es una herramienta de
diseñador con una superficie de diseño WYSIWYG que sirve para crear aplicaciones basadas en Silverlight.
Expression Blend genera un archivo de XAML que es posible modificar directamente. También es posible
enlazar eventos y escribir código subyacente con Expression Blend.
Diseño
Al crear una aplicación basada en Silverlight, una de las primeras decisiones que tendrá que tomar será
cómo organizar la interfaz de usuario. Silverlight proporciona 3 paneles de diseño al usuario. El panel
predeterminado es Grid, que es el panel de diseño más flexible y eficaz.
Contenedor Descripción
Canvas Coloque los elementos secundarios en posiciones absolutas en el espacio x,y.
Coloque los elementos secundarios en posiciones relativas entre sí en pilas horizontales o
StackPanel
verticales.
Grid Coloque los elementos secundarios en filas y columnas.
En el ejemplo siguiente, se coloca un elemento Rectangle en la celda 1,1 de una cuadrícula. La cuadrícula
usa un índice de base cero, de modo que el rectángulo se muestra en la celda inferior derecha.
<Grid ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Rectangle Fill="Red" Width="150" Height="100" Grid.Column="1" Grid.Row="1"/>
</Grid>
Controles
Los controles de Silverlight permiten hospedar contenido u otros controles y pueden diseñarse de modo
que muestren los cambios de estado del usuario. Los controles varían en funcionalidad de elementos que
permiten la interacción del usuario, como Button o TextBox, a elementos que admiten un diseño complejo
de la información, como DataGrid.
Silverlight incluye plantillas predeterminadas para cada control que afectan al aspecto del control. No
obstante, es posible crear plantillas personalizadas para cambiar el aspecto y el comportamiento visual de
todos los controles.
En el ejemplo siguiente se toma el ejemplo anterior y se agrega un botón a la celda 0,0 de la cuadrícula.
<Grid ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Button Height="25" Width="100" Grid.Column="0" Grid.Row="0"/>
<Rectangle Fill="Red" Width="150" Height="100" Grid.Column="1" Grid.Row="1"/>
</Grid>
Lenguajes dinámicos
Silverlight Tools para Visual Studio incluye Dynamic Language Runtime (DLR), que permite a los usuarios de
lenguajes dinámicos, como Python y Ruby, escribir aplicaciones basadas en Silverlight. Los lenguajes
dinámicos se empaquetan como código fuente, no se compilan en ensamblados, y el código puede
generarse y compilarse en tiempo de ejecución. Resultan apropiados para un estilo de desarrollo flexible e
interactivo. Silverlight incluye tres lenguajes dinámicos: IronPython, IronRuby y JScript administrado.
Gráficos
Silverlight proporciona muchas opciones para agregar características visuales interesantes a la aplicación.
Puede usar dibujos, formas, rutas y geometrías complejas. Las áreas definidas por geometrías pueden
rellenarse con efectos, como imágenes, degradados de color o clips de vídeo, mediante el uso de pinceles.
Puede transformar gráficos y otros objetos en la pantalla (por ejemplo, girarlos o inclinarlos). Incluso puede
aplicar efectos 3D.
Puede agregar imágenes y efectos de imagen a la aplicación. Silverlight también incluye Deep Zoom, que
permite hacer zoom y panorámicas con facilidad de imágenes de gran detalle.
En el ejemplo siguiente el rectángulo se rellena con un pincel de degradado lineal.
<Rectangle x:Name="rect1" Width="150" Height="100" Grid.Column="1" Grid.Row="1">
<Rectangle.Fill>
<LinearGradientBrush>
<GradientStop Offset="0" Color="LightBlue"/>
<GradientStop Offset="0.4" Color="Blue"/>
<GradientStop Offset="0.8" Color="Purple"/>
<GradientStop Offset="1.0" Color="Lavender"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
Multimedia y animación
Además de gráficos estáticos, puede agregar animaciones, audio y vídeo a la aplicación para hacerla más
dinámica e interactiva.
En el ejemplo siguiente se aumenta y se reduce el tamaño del rectángulo del ejemplo anterior hasta que se
hace clic en el botón Detener.
<Grid ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.Resources>
<Storyboard x:Name="AnimateRectangle">
<DoubleAnimation Storyboard.TargetName="rect1"
Storyboard.TargetProperty="Height"
From="0" To="100" AutoReverse="True" Duration="0:0:02"
RepeatBehavior="Forever"/>
<DoubleAnimation Storyboard.TargetName="rect1"
Storyboard.TargetProperty="Width"
From="0" To="100" AutoReverse="True" Duration="0:0:04"
RepeatBehavior="Forever"/>
</Storyboard>
</Grid.Resources>
<Button Height="25" Width="100"
Grid.Column="0" Grid.Row="0"
Content="Stop"
Click="Button_Click"/>
<Rectangle x:Name="rect1" Width="150" Height="100" Grid.Column="1" Grid.Row="1" Loaded="OnLoaded">
<Rectangle.Fill>
<LinearGradientBrush>
<GradientStop Offset="0" Color="LightBlue"/>
<GradientStop Offset="0.4" Color="Blue"/>
<GradientStop Offset="0.8" Color="Purple"/>
<GradientStop Offset="1.0" Color="Lavender"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Button Height="25" Width="100"
Grid.Column="0" Grid.Row="1"
Content="Start"
Click="Button_Click_1"/>
</Grid>
Data
Muchas aplicaciones basadas en Silverlight trabajan con datos. Puede mostrar conjuntos de datos utilizando
controles como DataGrid y ListBox. Para rellenar la interfaz de usuario, puede usar Enlace de datos. Si enlaza
la interfaz de usuario al objeto de datos, las actualizaciones del objeto se propagarán automáticamente a la
interfaz de usuario.
Los datos incluidos en la aplicación pueden proceder de varios orígenes, como una fuente RSS, pero suelen
estar en formato XML. Silverlight incluye XmlReader y LINQ para analizar los datos XML. LINQ resulta más
adecuado cuando se analizan fragmentos de datos más pequeños.
Redes
Silverlight proporciona varias características para comunicarse en la nube. La clase WebClient controla la
descarga de contenido en el cliente. También puede usar WebClient para enviar y recibir mensajes XML sin
formato. Las aplicaciones basadas en Silverlight también pueden obtener acceso a servicios Web, como
Windows Communication Foundation (WCF), SOAP y ASP.NET AJAX.
Nota:
Silverlight admite dos modelos de programación: la API de JavaScript para Silverlight y la API administrada
para Silverlight. La API administrada se basa en un subconjunto de .NET Framework. Muchas de las
características que se mencionan en este artículo son únicamente compatibles con la API administrada.
Plataforma de Silverlight
La plataforma de Silverlight en su conjunto se compone de dos partes principales, además de un
componente de instalador y actualización, tal y como se describe en la siguiente tabla.
Componente Descripción
Componentes y servicios orientados a la interfaz de usuario y la interacción con el
usuario, incluidos los datos proporcionados por el usuario, controles de interfaz de
Marco de trabajo
usuario ligeros para su uso en las aplicaciones web, reproducción de elementos
de presentación
multimedia, administración de derechos digitales, enlaces de datos; y características de
básico
presentación, incluidos gráficos vectoriales, texto, animaciones e imágenes. También
incluye el lenguaje XAML para especificar el diseño.
Subconjunto de .NET Framework que contiene componentes y bibliotecas, que incluyen
integración de datos, controles de Windows extensibles, funciones de red, bibliotecas de
clases base, recolección de elementos no utilizados y CLR (Common Language Runtime).
En la ilustración siguiente se muestran estos componentes de la arquitectura de Silverlight, junto con los
componentes y servicios relacionados.
Arquitectura de Silverlight
Característica Descripción
Administra datos de entrada procedentes de distintos dispositivos de
Entrada
hardware, como los de dibujo, el teclado y el mouse, y otros.
Representación de la interfaz
Representa gráficos vectoriales y de mapa de bits, animaciones y texto.
de usuario
Los programadores pueden interactuar con este marco de trabajo de presentación utilizando XAML para
especificar los detalles de presentación. XAML constituye el punto primario de interacción entre .NET
Framework y la capa de la presentación. Los programadores pueden manipular la capa de presentación
mediante programación con código administrado.
Característica Descripción
Admite las características de LINQ (Language-Integrated Query) y de LINQ to XML,
que facilitan el proceso de integrar datos procedentes de orígenes dispares y
Data
trabajar con ellos. También admite el uso de las clases de serialización y XML para
administrar los datos.
Un conjunto de bibliotecas de .NET Framework que proporcionan las funciones de
Biblioteca de clases
programación esenciales, como la administración de cadenas, expresiones
base
regulares, entrada y salida, reflexión, colecciones y globalización.
Proporciona características para simplificar el acceso a los servicios y datos
Windows remotos. Esto incluye un objeto de explorador, un objeto de solicitud y respuesta
Communication HTTP, compatibilidad con solicitudes HTTP entre dominios, compatibilidad con
Foundation (WCF) fuentes de distribución RSS/Atom así como compatibilidad con los servicios JSON,
POX y SOAP.
CLR (Common Proporciona administración de memoria, recolección de elementos no utilizados,
Language Runtime) comprobación de seguridad de tipos y control de excepciones.
Controles de WPF Proporciona un conjunto enriquecido de controles, como son Button, Calendar,
(Windows Presentation CheckBox, DataGrid, DatePicker, HyperlinkButton, ListBox, RadioButton y
Foundation) ScrollViewer.
Admite la compilación y ejecución dinámicas de lenguajes de scripting como
DLR (Dynamic JavaScript y IronPython para programar aplicaciones basadas en Silverlight. Incluye
Language Runtime) un modelo conectable que aporta compatibilidad con otros lenguajes para su uso
con Silverlight.
.NET Framework para Silverlight es un subconjunto de la plataforma .NET Framework completa. Proporciona
los fundamentos del desarrollo robusto y orientado a objetos para tipos de aplicaciones (como las de
Internet) que tradicionalmente no contaban con este tipo de recursos.
Los desarrolladores pueden interactuar con la capa de .NET Framework para Silverlight escribiendo código
administrado en C# y Visual Basic. Los desarrolladores de .NET Framework también pueden tener acceso a
la capa de presentación creando sus aplicaciones en Visual Studio o Microsoft Expression Blend.
Característica Descripción
La mayoría de las aplicaciones de Silverlight 3 funcionarán con Silverlight 4 sin ningún cambio.
Cuando se requieren cambios importantes, Silverlight intentará mantener la compatibilidad con el
comportamiento anterior y con el comportamiento nuevo mediante un modo quirks.
No obstante, es posible que algunos cambios realizados en los componentes de Silverlight generen un error
en las aplicaciones basadas en Silverlight anteriores (tiempo de compilación, tiempo de carga de XAML o
posiblemente tiempo de diseño) o hagan que dichas aplicaciones tengan un comportamiento distinto.
En este tema, se describen los cambios realizados en Silverlight 4 con respecto a Silverlight 3. No se
describen las nuevas características ni mejoras de Silverlight 4
Este tema contiene las siguientes secciones:
Cambios en el analizador de XAML En esta sección, se describen los cambios realizados en el
analizador de XAML de Silverlight 4.
Cambios importantes desde Silverlight 3 En esta sección, se describen los cambios que podrían
interrumpir las aplicaciones escritas para Silverlight 3 que los usuarios ejecutan en el runtime de
Silverlight 4, incluso cuando el manifiesto de aplicación tiene como destino Silverlight 3.
Comportamiento en modo quirks En esta sección, se describen las diferencias de
comportamiento del runtime o de su API que son específicas de la versión. Estas diferencias de
comportamiento se basan en la versión del runtime que la aplicación tiene como destino. En
muchas ocasiones, los cambios representan correcciones de errores que se han introducido en
Silverlight 4, pero el comportamiento de Silverlight 3 sigue siendo accesible como un modo quirks
específico, que se utiliza únicamente cuando la aplicación tiene como destino un runtime de
Silverlight 3. Esto es así por si la lógica de la aplicación se basa en el comportamiento de
Silverlight 3.
Cambios importantes en la actualización En esta sección, se describen los cambios que se aplican
cuando se recompila una aplicación de Silverlight 3 y el destino previsto es Silverlight 4.
Cambios importantes desde la versión Beta de Silverlight 4 En esta sección, se describen los
cambios que se aplican únicamente a las aplicaciones compiladas específicamente para la versión
Beta de Silverlight 4, que es la última versión pública del runtime de Silverlight. No hay modo
quirks para el comportamiento de la versión Beta de Silverlight 4.
del mouse para que se vuelva a ejecutar la prueba de posicionamiento y para que los controles puedan
cambiar su estado si es necesario.
Ahora, al cambiar las propiedades DisplayMemberPath e ItemTemplate de
ItemControl, se vuelven a crear todos los contenedores
En Silverlight 3, establecer las propiedades DisplayMemberPath e ItemTemplate de una plantilla de
elementos, como en el siguiente código, no tenía ningún efecto una vez finalizada la medición de ListBox.
<ListBox x:Name="lb" ItemTemplate="{StaticResource lbItem}">
lb.ItemTemplate = lbItemTemplate;
lb.DisplayMemberPath = itemDisplayPath;
En Silverlight 4, este código invalidará todos los contenedores realizados y los volverá a crear incluso
después de su medición.
Orígenes de BitmapImage compartidos
Cuando dos controles BitmapImage comparten el mismo origen de BitmapImage y no tienen establecido un
valor explícito de Width/Height (es decir, usan un tamaño natural), el segundo control Image no representa
su BitmapImage en Silverlight 3. Este comportamiento se ha corregido en Silverlight 4 y, ahora, ambos
controles Image deberán representar correctamente su contenido.
IronPython 2.0.2 y versiones anteriores
Silverlight 4 no funciona con versiones anteriores de IronPython; es necesario actualizar a la versión
IronPython 2.0.3 o posterior, que se puede descargar desde http://ironpython.codeplex.com/.
Microsoft.Jscript.Compiler.dll / Microsoft.Jscript.Runtime.dll
Silverlight 4 no funciona con Microsoft.Jscript.Compiler.dll / Microsoft.Jscript.Runtime.dll, que también se
conocen como "DLR Jscript" y a veces como "Jscript administrado". La última versión experimental de DLR
Jscript se publicó como parte de la versión Alfa de Dynamic Languages SDK 0.4.0. Esta característica se ha
eliminado porque no era totalmente funcional. Vea http://dlr.codeplex.com/Thread/View.aspx?
ThreadId=58121 para obtener información detallada. (DLR JScript no debe confundirse con la API de
JavaScript basada en explorador para Silverlight que es más común y sigue funcionando.)
DRM y clientes con SO en particiones FAT32
En Silverlight 3, DRM funciona correctamente en los sistemas de cliente donde el sistema operativo está
instalado en una unidad o partición FAT32. (Esta situación se da para un número reducido de sistemas
operativos Windows XP que no usan deliberadamente los valores predeterminados de la instalación o
conversión del SO.)
En Silverlight 4, las características de DRM ya no funcionan en los sistemas de cliente donde el sistema
operativo está instalado en una unidad o partición FAT32.
Para solucionarlo, se recomienda realizar una conversión a NTFS.
RuntimeVersion refleja la versión de compilación de Silverlight que había en el equipo del desarrollador
cuando se compiló la aplicación.
Si se compila la aplicación con las herramientas de Silverlight 4 y se elige específicamente Silverlight 3 como
destino, se podrá invocar el modo quirks como si se hubiera compilado la aplicación con las herramientas
de Silverlight 3.
Control correcto de los espacios en blanco con etiquetas Span y contenedores
El objeto TextBlock en Silverlight 3 (y RichTextArea en la versión Beta de Silverlight 4) tenía un error en la
composición de <Span> o <Run> porque el espacio en blanco en el XAML (normalmente para dar formato)
se utilizaba en realidad como contenido. A veces, esto requería limitar las líneas nuevas en el origen de
XAML y daba lugar a un XAML poco legible para el usuario. Este comportamiento está en modo quirks para
Silverlight 3, como parte del comportamiento más exhaustivo del analizador de XAML que se describe en
Diferencias en el procesamiento de XAML entre Silverlight 3 y Silverlight 4.
Los contenedores de texto en Silverlight 4 aceptan contenido de texto y crean ejecuciones implícitas en el
modelo de objetos para cualquier contenido de texto de "innertext". Esto es necesario para generar un
espacio en blanco entre los elementos de texto separados por CRLF. Por ejemplo:
<Run>Some</Run>
<Run>Text</Run>
Se transforma en:
<Run>Some</Run><Run> </Run><Run>Text</Run>
Las condiciones para recortar los espacios en blanco iniciales y finales se han ampliado en Silverlight 4.
Anteriormente, se recortaban los espacios en blanco iniciales para los elementos Run implícitos, a menos
que el elemento Run fuese precedido por un elemento Run explícito. En Silverlight 4, se recortan los
espacios en blanco iniciales a menos que el elemento Run implícito vaya precedido por un elemento de
texto explícito que NO sea un elemento Run (por ejemplo, Span, InlineUIContainer, Hyperlink) o un
elemento Run explícito.
Ahora, el método Clear del control Panel llama a InvalidateMeasure
En Silverlight 4, cuando se invoca el método Clear de una colección de elementos Panel, se llama al método
InvalidateMeasure. De este modo, se activará un efecto sobre el diseño en el paso siguiente. En Silverlight 3,
una llamada a Clear seguirá sin tener ningún efecto sobre el diseño de Panel.
Ahora, VirtualizingStackPanel.MouseWheelUp y VirtualizingStackPanel.Morse
WheelDown producen un desplazamiento de tres líneas
En las aplicaciones compiladas de Silverlight 3, los métodos MouseWheelDown y MouseWheelUp seguirán
produciendo un desplazamiento de una línea. Sin embargo, en las aplicaciones de Silverlight 4, estos
métodos producen un desplazamiento de tres líneas.
Ahora, ImageBrush.ImageSource devuelve el objeto ImageSource en lugar de
UriSource
En las aplicaciones de Silverlight 3, ImageBrush.ImageSource devuelve el valor de UriSource de su
ImageSource (una cadena). Esto coincide con el comportamiento original de JavaScript en Silverlight 1.0.
En Silverlight 4, se devuelve el objeto ImageSource real, que puede ser un objeto WriteableBitmap o
BitmapImage.
Ahora, cambiar el valor base durante una animación funciona según lo previsto
En Silverlight 3, si se llamaba al método SetValue en una propiedad durante una animación activa, el
resultado se aplicaba solamente a ese paso. El método SetValue cambiaba correctamente ese valor pero, en
el siguiente paso de la animación activa, la animación sobrescribía el valor establecido. En muchas
ocasiones, parecía que no había cambiado nada visualmente (el cambio al nuevo valor se realizaba tan
rápidamente que el usuario no lo percibía). La llamada al método SetValue no cambiaba el valor base de la
animación (resultado de GetAnimationBaseValue). Cuando se detenía la animación, el valor base se
restablecía en el valor que la propiedad tenía antes del inicio de la animación y omitía el método SetValue.
En Silverlight 4, si el valor de una propiedad cambia durante una animación activa, la llamada al método
SetValue modificará el valor base de la animación. Cuando se detiene la animación, esta utilizará el nuevo
valor base. Esto se corresponde con el comportamiento en WPF. (Observe que las animaciones HoldEnd no
se ven necesariamente afectadas por este cambio.)
ReadLocalValue devuelve el valor local durante una animación
En Silverlight 3, cuando se anima una propiedad y la animación se está ejecutando, una llamada al método
ReadLocalValue devuelve el valor animado.
En Silverlight 4, una llamada al método ReadLocalValue devolverá el valor local. Esto se corresponde con el
comportamiento en WPF. Si desea obtener el valor animado, llame al método GetValue.
No se invocan los establecedores duplicados en un estilo cuando todos hacen
referencia a la misma propiedad adjunta
En Silverlight 3, era posible utilizar varios objetos StyleSetter para establecer dos veces la misma propiedad
adjunta. En algunos escenarios se utilizaba esta característica.
En Silverlight 4, este comportamiento ya no está habilitado. No es un error de sintaxis establecer dos veces
la misma propiedad adjunta en Setters. Sin embargo, el subsistema de estilos de Silverlight invocará
solamente el ÚLTIMO objeto Setter que haga referencia a la propiedad adjunta; los demás establecedores
no serán operativos. Esto se corresponde con el comportamiento en WPF.
Zoom del explorador y Content.Resized
En Silverlight 4, si una aplicación enlaza el evento Resized, se aplicará automáticamente un zoom a la vista
del área de contenido de Silverlight cuando cambie el nivel de zoom del explorador. Si una aplicación de
Silverlight 4 desea deshabilitar el zoom automático del explorador, deberá establecer explícitamente el valor
de la propiedad EnableAutoZoom en false.
En Silverlight 3, se suponía que las aplicaciones que realizaban escuchas de Resized se encargaban ellas
mismas del zoom del explorador y deshabilitaban el zoom automático del explorador. Por consiguiente, en
modo quirks, no hay ningún comportamiento de zoom asociado al evento Resized cuando la aplicación
tiene Silverlight 3 como destino.
Cambios en la API de MEF
A continuación, se describen los cambios específicos que se han realizado en la API de Managed Extension
Framework (MEF) y que están presentes en los componentes de MEF de Silverlight (ensamblado
System.ComponentModel.Composition y ensamblados relacionados).
PartCreator<T> pasa a denominarse ExportFactory<T> y se ha movido a System.
ComponentModel.Composition.Initialization.dll
PartInitializer pasa a denominarse CompositionInitializer
CompositionHost.InitializeContainer pasa a denominarse CompositionHost.Initialize
PackageCatalog se ha reemplazado por DeploymentCatalog
Comparaciones de cadenas y CultureInfo
Algunas API de comparación de cadenas de las clases String y Char usan una lógica diferente para el modo
en que obtienen el objeto CultureInfo en vigor, según si la aplicación se ejecuta en Silverlight 3 o en
Silverlight 4. Esto se aplica únicamente a los casos en los que una sobrecarga no pasa ningún objeto
CultureInfo concreto. El comportamiento está en modo quirks, por lo que las aplicaciones de Silverlight 3 no
tienen que corregirlo. En la tabla siguiente se indican las diferencias entre las API.
Silverlight 4
Al presionar la tecla FLECHA ARRIBA en Silverlight 4, se activa el control TabItem anterior (es decir, el
situado encima del control TabItem activo en modo de diseño vertical cuando el valor de TabStripPlacement
es Left o Right). Al presionar la tecla FLECHA ABAJO, se activa el control TabItem siguiente (es decir, el
situado debajo del control TabItem activo en modo de diseño vertical). Este es el comportamiento
actualizado si se hace referencia o se distribuye el ensamblado System.Windows.Controls.dll de Silverlight 4.
Ahora, los controles tienen compatibilidad integrada con MouseWheel
En Silverlight 4, los siguientes controles tienen compatibilidad integrada con los eventos MouseWheel:
ListBox
TextBox
ComboBox
ScrollViewer
Calendar
DatePicker
DataGrid
En Silverlight 3, no hay compatibilidad integrada con MouseWheel.
Si se actualizan aplicaciones de Silverlight 3 a Silverlight 4, es posible quitar cualquier control específico
anterior de los eventos de la rueda del mouse en el nivel de la aplicación o quizás en el DOM HTML. Esto
podría aplicarse a cualquiera de los siguientes controles: ListBox, TextBox, ComboBox y ScrollViewer.
Nota:
Hay también controles compatibles con MouseWheel que no figuran aquí porque no existían en
Silverlight 3. Un ejemplo de ello es RichTextBox. Compruebe en las páginas de referencia de cada control si
hay reemplazos de OnMouseWheel u otras observaciones referentes al control del evento MouseWheel.
DESPUÉS
public class DomainAcquirer
{
public void CancelAsync();
public event EventHandler<DomainJoinCompletedEventArgs> DomainJoinCompleted;
public event EventHandler<DomainLeaveCompletedEventArgs> DomainLeaveCompleted;
}
public class LicenseAcquirer
{
public void CancelAsync();
public string ChallengeCustomData;
}
public class MediaLicense
{
public Nullable<DateTimeOffset> ExpirationDate;
}
public enum ContentKeyType
{
Aes128Bit,
Cocktail
}
ha cambiado a:
public event EventHandler<NotifyEventArgs> ScriptNotify;
ha cambiado a:
public Visibility Visibility { get; }
public event EventHandler Closed;
Ha cambiado a:
namespace System.Runtime.InteropServices.Automation
{
public sealed class AutomationEvent
public sealed class AutomationEventArgs : EventArgs
De este modo, se establece MyProperty en un objeto Binding con la ruta de acceso MyItem.
Después del cambio:
<local:MyDependencyObject MyProperty="{Binding MyItem}" />
De este modo, se adjunta un objeto BindingExpression a la propiedad MyProperty que escucha la ruta de
acceso MyItem (es similar a una llamada al método SetBinding). Las aplicaciones de Silverlight 4 que deseen
establecer el comportamiento de un objeto Binding deberán convertir la propiedad de destino en una
propiedad de CLR en lugar de una DependencyProperty. Esto es coherente con el comportamiento de
FrameworkElement.
Ahora, HtmlBrush se denomina WebBrowserBrush
Es necesario cambiar a WebBrowserBrush todas las referencias a HtmlBrush. El espacio de nombres de CLR y
la ubicación del ensamblado siguen siendo los mismos.
Se ha cambiado el nombre de los estados visuales de ListBoxItem
Se ha cambiado el nombre de dos de los estados visuales de ListBoxItem.
El estado visual Loaded en la versión Beta de Silverlight 4 se denomina ahora AfterLoaded.
El estado visual Unloaded en la versión Beta de Silverlight 4 se denomina ahora BeforeUnloaded.
Este cambio afectará al usuario si ha escrito plantillas para los controles de elementos que incluyan estos
estados visuales. Es necesario cambiar las plantillas de modo que incluyan los nuevos nombres de estado. Es
posible que este cambio también afecte al usuario si ha escrito lógica de VisualStateManager que utilice los
nombres de estado definidos por ItemsControl.
Los nuevos nombres de estado se reflejan en los atributos de CLR del tipo ListBoxItem. Estos estados no
existían en el control ListBoxItem de Silverlight 3.
No se admiten enlaces en un establecedor de estilo
En la versión Beta de Silverlight 4, se permitían sintácticamente los enlaces en un establecedor de estilo
(valor de Setter.Property) (aunque no funcionaban según lo esperado en comparación con usos
equivalentes en WPF).
En Silverlight 4, se han bloqueado sintácticamente los enlaces en un establecedor de estilo. Este fue también
el caso en Silverlight 3.
Administración de la memoria
El recolector de elementos no utilizados de Common Language Runtime administra la asignación y
liberación de la memoria de una aplicación. Esto significa que los programadores no tienen que escribir
código para realizar tareas de administración de memoria al programar aplicaciones administradas. La
administración automática de la memoria puede eliminar problemas frecuentes, como olvidar liberar un
objeto y causar una pérdida de memoria, o intentar tener acceso a la memoria de un objeto que ya se ha
liberado.
Cuando se inicializa un nuevo proceso, el motor en tiempo de ejecución reserva una región contigua de
espacio de direcciones para el proceso. Este espacio de direcciones reservado se denomina montón
administrado. El montón administrado mantiene un puntero a la dirección a la que se asignará el siguiente
objeto del montón. Inicialmente, este puntero se establece en la dirección base del montón administrado.
Todos los tipos de referencia se asignan en el montón administrado. Cuando una aplicación crea el primer
tipo de referencia, se le asigna memoria en la dirección base del montón administrado. Cuando la aplicación
crea el siguiente objeto, el recolector de elementos no utilizados le asigna memoria en el espacio de
direcciones que sigue inmediatamente al primer objeto. Siempre que haya espacio de direcciones
disponible, el recolector de elementos no utilizados continúa asignando espacio a los objetos nuevos de
este modo.
La asignación de memoria desde el montón administrado es más rápida que la asignación de memoria no
administrada. Como el tiempo de ejecución asigna memoria a los objetos agregando un valor a un puntero,
este método es casi tan rápido como la asignación de memoria desde la pila. Además, puesto que los
nuevos objetos que se asignan consecutivamente se almacenan uno junto a otro en el montón
administrado, la aplicación puede tener un acceso muy rápido a los objetos.
Además de asignar memoria, el motor de optimización del recolector de elementos no utilizados determina
cuál es el mejor momento para realizar una recolección, según las asignaciones que se estén realizando.
Cuando el recolector de elementos no utilizados lleva a cabo una recolección, libera la memoria de los
objetos que ya no usa la aplicación.
En Silverlight se presenta la característica Deep Zoom, que permite ampliar y reducir imágenes o
colecciones de imágenes de alta-resolución.
Nota:
Los controles del Kit de herramientas de Silverlight se actualizan periódicamente.
Control Silverlight o WPF Disponible para Silverlight
AccessText WPF No está disponible
AdornedElementPlaceholder WPF No está disponible
AdornerDecorator WPF No está disponible
AutoCompleteBox Silverlight SDK de Silverlight
Border Ambos Motor en tiempo de ejecución
BulletChrome WPF No está disponible
BulletDecorator WPF No está disponible
Button Ambos Motor en tiempo de ejecución
ButtonChrome WPF No está disponible
Calendar Ambos SDK de Silverlight
Canvas Ambos Motor en tiempo de ejecución
CheckBox Ambos Motor en tiempo de ejecución
ClassicBorderDecorator WPF No está disponible
ComboBox Ambos Motor en tiempo de ejecución
ComboBoxItem Ambos Motor en tiempo de ejecución
ContentControl Ambos Motor en tiempo de ejecución
ContentPresenter Ambos Motor en tiempo de ejecución
ContextMenu WPF No está disponible
Control Ambos SDK de Silverlight
DataPager Silverlight SDK de Silverlight
DataGrid Ambos SDK de Silverlight
DatePicker Ambos SDK de Silverlight
Decorator WPF No está disponible
DescriptionViewer Silverlight SDK de Silverlight
DockPanel Ambos Kit de herramientas de Silverlight
DocumentPageView WPF No está disponible
DocumentReference WPF No está disponible
DocumentViewer WPF No está disponible
Ellipse Ambos Motor en tiempo de ejecución
Expander Ambos Kit de herramientas de Silverlight
FixedPage WPF No está disponible
FlowDocumentPageViewer WPF No está disponible
FlowDocumentReader WPF No está disponible
FlowDocumentScrollViewer WPF No está disponible
Frame Ambos SDK de Silverlight
FrameworkElement Ambos Motor en tiempo de ejecución
Glyphs Ambos Motor en tiempo de ejecución
Grid Ambos Motor en tiempo de ejecución
GridSplitter Ambos SDK de Silverlight
GridViewColumnHeader WPF No está disponible
GridViewHeaderRowPresenter WPF No está disponible
Diferencias funcionales
Modo de ventanas
Nota:
Si está controlando la entrada de teclado (como con los eventos KeyUp y KeyDown) y casos de proceso con
teclas modificadoras, debe tener en cuenta que se podría presionar la tecla Control en Macintosh para
generar el equivalente al clic con botón secundario.
Para el control de teclado general, hay dos conjuntos de teclas. Hay un conjunto de teclas que es un común
entre todas las plataformas compatibles y otro conjunto que varía según la plataforma. Una tecla de
plataforma se notifica como un PlatformKeyCode. Las teclas modificadoras (se obtienen a través de la
propiedad Keyboard.Modifiers) pueden variar según la plataforma.
Silverlight 4 permite arrastrar una lista de archivos desde fuera del complemento Silverlight a un elemento
de destino en el área de contenido de Silverlight. Esta característica se expone a través de eventos de
entrada, como el evento Drop de la clase UIElement. Debido a las limitaciones en el modelo de entrada de
Safari para los complementos hospedados, solo puede habilitar esta característica en Safari mediante una
solución alternativa o correcciones de compatibilidad (shim) de scripting HTML. No puede habilitar esta
característica en Firefox.
Aplicaciones con ejecución fuera del explorador
Las aplicaciones con ejecución fuera del explorador se ejecutan de manera idéntica en Windows y en
Macintosh, pero necesitan pasos de desinstalación diferentes. En Windows, los usuarios desinstalan una
aplicación mediante Programas y características en el Panel de control. O bien, pueden hacer clic con el
botón secundario en la aplicación y seleccionar la opción de desinstalación. En Macintosh, los usuarios
desinstalan una aplicación arrastrándola hacia la papelera.
Las aplicaciones de confianza pueden integrarse con funcionalidad nativa que difiere dependiendo del
sistema operativo host. Por ejemplo, en Windows, las aplicaciones de confianza pueden interoperar con las
API de Automatización a través de la clase AutomationFactory.
Depuración
Puede depurar aplicaciones basadas en Silverlight en equipos Macintosh estableciendo una sesión de
depuración remota desde un equipo que está ejecutando Windows con Visual Studio instalado.
Característica de .NET
Comportamiento de Windows Comportamiento de Macintosh
Framework
Convierte Char a minúsculas usando En Mac OS v10.4 y en versiones
Char.ToLower(Char, CultureInfo) las convenciones de la referencia anteriores, convierte Char a
cultural especificada. minúsculas usando las convenciones
2. Introducción a Silverlight
En los temas de esta sección se ofrece información detallada para comenzar a desarrollar aplicaciones
basadas en Silverlight. Se incluye información sobre herramientas de desarrollo, el modo de crear un
proyecto básico en Visual Studio y vínculos a ejemplos de código fuente.
Nota:
De forma predeterminada, Visual Studio 2010 incluye compatibilidad con Silverlight 3.
Al instalar Silverlight 4 Tools para Visual Studio 2010, aparecerá la opción para elegir Silverlight 4
como destino. En la siguiente ilustración se muestra la opción Silverlight 4 en el cuadro de diálogo
Nueva aplicación de Silverlight.
Al crear un nuevo proyecto de Silverlight, verá un gran número de las herramientas y ventanas con
las que ya se ha familiarizado en Visual Studio.
SDK de Silverlight 4
El Kit de desarrollo de software (SDK) de Silverlight 4 incluye varios componentes que ayudan a crear
aplicaciones de Silverlight. El SDK de Silverlight 4 se incluye en la instalación de Silverlight 4 Tools, pero
también lo puede instalar por separado. De forma predeterminada, el SDK de Silverlight 4 se instala en la
carpeta %ProgramFiles%\Microsoft SDKs\Silverlight. El SDK de Silverlight 4 contiene los elementos
siguientes.
Licencia de usuario. El documento de licencia incluye las condiciones del SDK de Silverlight 4.
Bibliotecas de Silverlight. El SDK de Silverlight 4 incluye bibliotecas de cliente y servidor. Las
bibliotecas de Silverlight no forman parte del complemento Silverlight. Las bibliotecas de cliente
incluyen las extensiones y los controles de usuario de Silverlight. Las bibliotecas de servidor
incluyen los controles de servidor de Silverlight. Para conocer las condiciones de uso, consulte la
licencia de usuario del SDK de Silverlight 4.
Herramientas. Incluye ensamblados de referencia, componentes de compilación y herramientas
para compilar y empaquetar aplicaciones de Silverlight.
Herramienta Descripción
Expression Blend es una herramienta para diseñadores (y programadores) que
permite crear gráficos, diseñar animaciones y generar experiencias de usuario.
Expression Blend Expression Blend utiliza XAML y el mismo sistema de proyectos que Visual Studio.
Esto permite que diseñadores y programadores compartan los mismos archivos y
colaboren.
Deep Zoom Composer es una herramienta que permite preparar imágenes de alta
resolución para usarlas con la característica Deep Zoom. La nueva tecnología Deep
Deep Zoom Zoom de Silverlight permite al usuario acercar y alejar las imágenes de manera fluida.
Composer Deep Zoom Composer permite al usuario crear archivos de composición Deep Zoom
que controlan la experiencia de aplicar el zoom y, luego, exportar los archivos
necesarios para su implementación con Silverlight.
Silverlight.js es un archivo auxiliar de JavaScript que se proporciona en el SDK de
Silverlight. Puede llamar a las funciones definidas en este archivo para inicializar
Silverlight.js instancias del complemento Silverlight en una página web. Silverlight.js también
contiene las funciones de utilidad para determinar la versión instalada del cliente del
complemento.
Este archivo de aplicación auxiliar de JavaScript opcional incluye la función
Silverlight.supported
Silverlight.supportedUserAgent, que determina si el explorador del usuario admite
UserAgent.js
Silverlight.
Silverlight Designer para Visual Studio 2010 proporciona compatibilidad con el diseño visual para crear
aplicaciones de Silverlight y de Windows Presentation Foundation (WPF). Para construir las interfaces de
usuario de las aplicaciones, arrastre los controles del Cuadro de herramientas y establezca las propiedades
en la ventana Propiedades. También puede editar directamente XAML en la vista XAML. En la ilustración
siguiente se muestran Silverlight Designer y algunas de sus ventanas auxiliares.
Silverlight Designer
La primera vez que se inicia Silverlight Designer, las ventanas Cuadro de herramientas, Orígenes de datos y
Esquema del documento se contraen en el lado izquierdo de Visual Studio. Si se muestran y anclan las
pestañas a la izquierda, se ve la vista anterior, lo cual resulta útil para usar la superficie de diseño.
Vista de diseño
La vista de diseño proporciona una superficie de diseño visual para compilar los controles de Silverlight y
para el diseño de las aplicaciones. Muestra una presentación del XAML que hay actualmente en la vista
XAML. Cuando se cambian los controles en la superficie de diseño, la vista XAML se actualiza para reflejar
los cambios. La vista de diseño proporciona muchas características para organizar los controles de la página
de la aplicación de Silverlight. En la siguiente ilustración se muestran algunas de las características de la vista
Diseño.
Vista de diseño
Zoom
El control Zoom permite controlar el tamaño de la superficie de diseño. Puede hacer zoom desde 10% hasta
20x.
Panorámica
Cuando se aplica el zoom a la superficie de diseño y aparece una barra de desplazamiento horizontal o
vertical, puede aplicar la panorámica para ver las partes de la superficie de diseño que están fuera de la
pantalla. Mantenga presionada la barra espaciadora y, a continuación, arrastre la superficie de diseño para
aplicar la panorámica.
Ajustar a la vista
El botón Ajustar a la vista permite ajustar el tamaño de la superficie de diseño a la pantalla disponible en la
vista de diseño. Esto resulta útil si ha hecho zoom para acercarse o alejarse mucho.
Raíles de la cuadrícula
Los raíles de la cuadrícula se usan para administrar las filas y columnas en un control Grid. Puede crear y
eliminar columnas y filas, y puede ajustar el alto y el ancho relativos.
Líneas de la cuadrícula
Las líneas de la cuadrícula se usan para controlar el ancho y alto de las columnas y filas de un objeto Grid.
Para agregar una nueva columna o fila, haga clic en los raíles situados encima y a la izquierda de Grid.
Indicadores de línea de cuadrícula
Un indicador de línea de cuadrícula aparece como un triángulo en el raíl de la cuadrícula. Al arrastrar un
indicador de línea de cuadrícula o la propia línea de cuadrícula, el ancho o el alto de las columnas o filas
adyacentes se actualiza al mover el mouse.
Icono de desplazamiento
Un icono de desplazamiento aparece en la parte superior izquierda de un control de panel seleccionado y
permite mover el panel. Haga clic en el icono de desplazamiento y arrastre el control hacia la posición
deseada en la superficie de diseño.
Asas de ajuste de tamaño
Las asas de ajuste de tamaño aparecen en los controles seleccionados y permiten cambiar el tamaño del
control. Cuando se cambia el tamaño de un control, normalmente aparecen valores de ancho y alto para
ayudar a ajustar el tamaño del control con exactitud.
Líneas del margen
Los márgenes representan la cantidad de espacio fijo comprendido entre el borde de un control y el borde
de su contenedor. Establezca los márgenes de un control haciendo clic en las líneas del margen.
Códigos auxiliares de margen
Un código auxiliar de margen aparece en un control seleccionado cuando su margen se establece en 0.
Haga clic en el código auxiliar de margen para establecer una distancia del margen respecto del borde
correspondiente del contenedor.
Líneas de ajuste
Las guías de alineación ayudan a alinear los controles entre sí. Si están habilitadas, al arrastrar un control en
relación con otros controles, las guías de alineación aparecen cuando los bordes y el texto de algunos
controles están alineados horizontal o verticalmente.
Barra de información
La barra de información aparece en la parte superior de la vista de diseño y muestra información sobre
cómo presentar los problemas en dicha vista. En algunos casos, puede hacer clic en la barra de información
para obtener información adicional sobre el problema.
Barra de tamaño
Al mover el puntero del mouse sobre un raíl de la cuadrícula para un control Grid que tiene dos o más
columnas o filas, aparece la barra de tamaño fuera del raíl. La barra de tamaño permite establecer las
opciones de tamaño fijo, proporcional y automático para las filas y las columnas de Grid.
Etiqueta de tamaño de raíz
La etiqueta de tamaño de raíz aparece en la parte inferior derecha de la ventana en la vista de diseño
cuando la ventana está seleccionada. Dicha etiqueta permite alternar el tamaño raíz de la ventana entre
automático y fijo.
Vista XAML
El lenguaje XAML proporciona un vocabulario declarativo, basado en XML, para especificar la interfaz de
usuario de una aplicación. Silverlight Designer proporciona una vista XAML y una vista de diseño
sincronizada del marcado XAML que presenta la aplicación. La vista XAML incluye IntelliSense, formato
automático, resaltado de sintaxis y navegación por etiquetas. En la siguiente ilustración, se muestra la vista
XAML.
Vista XAML
Propiedades (Ventana)
La ventana Propiedades permite establecer los valores de las propiedades en los controles en la vista de
diseño. En la siguiente ilustración se muestra un ejemplo de la ventana Propiedades.
Ventana Propiedades
La parte superior de la ventana Propiedades tiene varias opciones. Para cambiar el nombre del control
seleccionado actualmente, coloque el cursor en el cuadro Nombre y escriba el nombre. En la esquina
superior derecha se muestra una vista previa en miniatura del control seleccionado actualmente. Para
enumerar las propiedades por categoría o alfabéticamente, haga clic en el botón Por categorías o
Alfabético. Para ordenar las propiedades por origen, haga clic en el botón Ordenar por origen de
propiedad. Para ver la lista de eventos de un control, haga clic en el botón Eventos. Para buscar una
propiedad, empiece a escribir el nombre de esta en el cuadro Buscar. La ventana Propiedades muestra las
propiedades que coinciden con su búsqueda cuando escribe.
A la derecha del nombre de la propiedad, en la primera columna, aparece un marcador de propiedad. El
marcador de propiedad indica si se ha aplicado a la propiedad un recurso o enlace de datos. Al hacer clic en
el marcador de propiedad, puede abrir el generador de enlace de datos o el selector de recursos.
Generador de enlace de datos
El generador de enlace de datos permite crear enlaces de datos sin necesidad de escribir código XAML.
Puede crear enlaces a los recursos, contextos de datos y propiedades de los elementos. También puede
aplicar convertidores de valores. En la ilustración siguiente, se muestra el generador de enlaces de datos.
Generador de enlace de datos
Selector de recursos
El selector de recursos permite buscar recursos y asignarlos a las propiedades en la ventana Propiedades.
También puede extraer los valores codificados de forma rígida a los recursos para promover la reutilización.
En la ilustración siguiente, se muestra el selector de recursos.
Selector de recursos
Editor de pinceles
El editor de pinceles permite crear muchos tipos distintos de pinceles en la ventana Propiedades. En la
ilustración siguiente, se muestra el editor de pinceles.
Editor de pinceles
Una vez establecida una conexión de datos, puede arrastrar las tablas de datos a la superficie de diseño y se
generarán automáticamente lógica de negocios y enlaces de datos. Se puede enlazar a un objeto, conjunto
de datos de ADO.NET, Entity Data Model o servicio.
Descripción Tema
Crear una nueva biblioteca de clases o aplicación de
Cómo: Crear un nuevo proyecto de Silverlight
Silverlight con Visual Studio.
Utilizar controles en una página. Introducción a los controles
Crear controladores de eventos para controles. Introducción a los controles
Manipular el diseño de las aplicaciones de Silverlight. Alineación en Silverlight Designer
Enlazar datos con el diseñador. Enlace de datos en Silverlight Designer
Extensibilidad de WPF Designer
Crear una experiencia en tiempo de diseño para los
controles de Silverlight. Ejemplos de la extensibilidad de WPF Designer y
Silverlight Designer
Crear aplicaciones y controles de WPF. WPF Designer
5. Especifique un nombre y una ubicación para la aplicación y, a continuación, haga clic en Aceptar.
Aparecerá el cuadro de diálogo Nueva aplicación de Silverlight, tal y como se muestra en la
siguiente ilustración.
Si activa la casilla Hospedar la aplicación de Silverlight en un nuevo sitio web en el cuadro de diálogo
Nueva aplicación de Silverlight, se crea y se agrega a la solución de Silverlight un sitio web ASP.NET. El
sitio web contiene los archivos siguientes:
Silverlight.js
Un archivo auxiliar de JavaScript que contiene funciones para inicializar instancias de complemento
Silverlight y funciones para determinar la versión instalada del cliente del complemento.
Archivo HTML
Un archivo HTML que se utiliza para configurar y crear instancias del complemento Silverlight, que
descarga y ejecuta la aplicación de Silverlight. El nombre de este archivo es una concatenación del
nombre del proyecto de aplicación de Silverlight y el texto "TestPage.html".
Archivo .aspx
Archivo .aspx que es la página web de inicio predeterminada. El nombre de este archivo es una
concatenación del nombre del proyecto de aplicación de Silverlight y el texto "TestPage.aspx".
Web.config
Archivo de configuración del sitio web
Class1.cs o Class1.vb
El archivo de código para una clase única denominada Class1.
Nota:
Para excluir el ensamblado al que se hace referencia en el paquete de la aplicación, seleccione la referencia
de ensamblado y, a continuación, en la ventana Propiedades, establezca Copia local en Falso. Esto es útil
cuando se desear recuperar el ensamblado a petición.
Para utilizar el ensamblado en XAML, tiene que especificar una asignación del espacio de nombres XML.
Para agregar una asignación de espacio de nombres XML
1. Abra MainPage.xaml.
2. En la etiqueta de apertura <UserControl>, agregue el marcado para declarar un espacio de
nombres. Por ejemplo, agregaría el siguiente marcado para utilizar DataGrid.
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
3. Para utilizar el elemento en XAML, prefije el nombre con el nombre especificado en la asignación
del espacio de nombres XML. Por ejemplo, en XAML, el elemento DataGrid se parecería a lo
siguiente:
<sdk:DataGrid></sdk:DataGrid>
Requisitos previos
Necesita los componentes siguientes para completar este tutorial:
Visual Studio 2010.
Silverlight 4 Tools para Visual Studio 2010.
Esta propiedad especifica que se agreguen líneas para identificar las filas y columnas de Grid. Esta
característica de depuración resulta de gran utilidad a la hora de crear los diseños de Grid.
4. Dentro del elemento Grid, agregue el siguiente código XAML para definir tres filas y dos columnas.
<Grid x:Name="LayoutRoot" Background="Beige" ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="220"/>
<RowDefinition Height="40"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75" />
<ColumnDefinition Width="325"/>
</Grid.ColumnDefinitions>
</Grid>
En la vista de diseño, ve que aparecen líneas que identifican las filas y columnas.
5. Presione F5 o haga clic en el botón de barra de herramientas Iniciar depuración para ejecutar la
aplicación.
El explorador se abrirá y verá líneas de puntos que indican el Grid que definió, como se muestra en
la siguiente ilustración.
Agregar controles
Silverlight incluye varios controles para ayudarle a mostrar los datos y obtener los datos introducidos por el
usuario. En esta sección se describe cómo agregar controles TextBlock, TextBox, StackPanel, Calendar y
Button al diseño de Grid.
Para agregar controles
1. Abra la ventana Cuadro de herramientas, si aún no está abierta.
4. Detrás del control TextBlock denominado Name, agregue otro control de tipo TextBlock con
Text="Date:".
5. Detrás del control TextBlock denominado Date, agregue otro control de tipo TextBlock con
Text="Message:".
En la vista de diseño, puede ver que los elementos TextBlock se superponen entre sí en la primera
celda. Para colocar los controles TextBlock en celdas Grid, debe especificar las propiedades
Grid.Row y Grid.Column.
6. En la etiqueta de apertura del control TextBlock Name, agregue las propiedades siguientes.
Grid.Row="0" Grid.Column="0"
8. En la etiqueta de apertura del control de tipo TextBlock denominado Message, agregue las
propiedades siguientes.
Grid.Row="2" Grid.Column="0"
En la vista de diseño, los elementos TextBlock se colocan ahora en las celdas adecuadas.
10. En el cuadro de herramientas, arrastre un control TextBox Message justo detrás del mensaje
TextBlock en la vista XAML.
11. En la etiqueta de apertura, defina las propiedades siguientes.
<TextBox Text="Your Name" Grid.Row="0" Grid.Column="1"></TextBox>
Observe que TextBox rellena toda la celda Grid. Rellena la celda porque las propiedades
VerticalAlignment y HorizontalAlignment están establecidas en "Stretch" (ajustada) de forma
predeterminada.
14. Debajo del control TextBox denominado Your Name, arrastre un control StackPanel desde el
cuadro de herramientas hasta la vista XAML.
StackPanel es un control útil para apilar los elementos vertical u horizontalmente. En la celda de la
cuadrícula de Grid situada bajo el control Name de tipo TextBox, apilará dos controles
verticalmente.
15. En la etiqueta de apertura del control de tipo StackPanel, agregue las propiedades siguientes.
<StackPanel Grid.Column="1" Grid.Row="1" Orientation="Vertical">
</StackPanel>
16. En el cuadro de herramientas, arrastre un control Calendar al interior del elemento StackPanel en la
vista XAML.
Al agregar el control Calendar, observará que el nombre de la etiqueta es algo diferente del de los
demás controles. Lleva el prefijo "sdk:". El control Calendar no forma parte de los controles básicos
de Silverlight y se implementa en un ensamblado diferente. El control Calendar forma parte del SDK
de Silverlight. Para usar los controles del SDK de Silverlight, debe agregar un espacio de nombres
XML y una referencia al ensamblado. Al arrastrar un control del SDK de Silverlight hasta la vista
XAML o de diseño, se agrega automáticamente un espacio de nombres XML al principio del archivo
MainPage.xaml, en la etiqueta <UserControl>. Tal y como se puede ver en el siguiente marcado, el
espacio de nombres sdk utiliza un identificador URI concreto, lo cual se describe en Prefijos y
asignaciones para las bibliotecas de Silverlight.
<UserControl xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
18. En el cuadro de herramientas, arrastre un control Button justo detrás del control Calendar, pero
dentro del elemento StackPanel en la vista XAML.
Puesto que la propiedad Orientation del control StackPanel está establecida en Vertical, el control
de tipo Button aparecerá bajo el control Calendar.
19. En la etiqueta de apertura del control Button, establezca las propiedades Width, Height,
HorizontalAlignment y Content.
<Button Width="75" Height="25" HorizontalAlignment="Left" Content="OK"></Button>
Un control Button no incluye ninguna propiedad Text, pero sí que incluye una propiedad Content.
El control Button tiene una propiedad Content porque realmente pueden agregarse otros
elementos como contenido de Button, tales como imágenes u otros controles.
20. En el menú Archivo, haga clic en Guardar todo.
Llegados a este punto, podemos decir que se han agregado todos los controles. El código XAML
será similar al siguiente.
<UserControl
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
x:Class="HelloSilverlight.MainPage"
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"
mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="300">
<Grid x:Name="LayoutRoot" Background="Beige" ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="220"/>
<RowDefinition Height="40"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75" />
<ColumnDefinition Width="325"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Name:" Grid.Row="0" Grid.Column="0"></TextBlock>
<TextBlock Text="Date:" Grid.Row="1" Grid.Column="0"></TextBlock>
<TextBlock Text="Message:" Grid.Row="2" Grid.Column="0"
Grid.ColumnSpan="2"></TextBlock>
<TextBox Text="Your Name" Grid.Row="0" Grid.Column="1"
Width="150" HorizontalAlignment="Left"></TextBox>
<StackPanel Grid.Column="1" Grid.Row="1" Orientation="Vertical">
<sdk:Calendar SelectionMode="SingleDate"
HorizontalAlignment="Left"></sdk:Calendar>
<Button Width="75" Height="25"
HorizontalAlignment="Left" Content="OK"></Button>
</StackPanel>
</Grid>
</UserControl>
Agregar código
Los archivos de código subyacente permiten agregar lógica a los elementos definidos mediante XAML. Para
obtener acceso a los controles y a otros elementos mediante programación, es necesario asignar un nombre
a los elementos. En esta sección se describe cómo asignar un nombre a los elementos en XAML, cómo
agregar un controlador de eventos y cómo agregar lógica al archivo de código subyacente.
Para agregar código
1. En la vista XAML, busque el control Message de tipo TextBlock .
2. En la etiqueta de apertura del control Message de tipo TextBlock, agregue la siguiente propiedad
Name message1.
x:Name="message1"
4. En la etiqueta de apertura del control OK de tipo Button, escriba Click y, a continuación, presione
TAB.
Deberá aparecer una ventana de IntelliSense, tal y como se muestra en la ilustración siguiente.
El ajuste de tamaño Auto indica que el tamaño viene determinado por el contenido. El ajuste de
tamaño Star (*) indica que el tamaño es una proporción ponderada del espacio restante.
2. En el elemento Grid.ColumnDefinitions, cambie los valores de Width por los siguientes.
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*"/>
3. Agregue la siguiente propiedad Margin a los controles de tipo TextBlock Name, Date y Message.
El siguiente código indica que se agregue un margen de 10 píxeles a izquierda y derecha, y un
margen de 5 píxeles arriba y abajo.
Margin="10,5,10,5"
5. Agregue la siguiente propiedad FontSize al control Message de tipo TextBlock para aumentar el
tamaño de la fuente.
FontSize="20"
Si se utiliza Expression Blend, los gráficos se crearán visualmente en el diseñador. Si se utiliza Visual Studio,
los gráficos se crearán mediante código XAML. Una vez creados los gráficos que componen la apariencia
del reloj, se agregarán animaciones y lógica para que el reloj funcione.
Requisitos previos
Necesita los componentes siguientes para completar este tutorial:
Expression Blend 4 (opcional).
Visual Studio 2010.
Silverlight 4.
Estos gráficos se crean con elementos simples organizados en un control Grid. Todos los gráficos circulares,
incluidos los gráficos de la cara de reloj, el borde exterior, el bisel y la sombra, se crean con elementos
Ellipse, mientras que las manecillas del reloj se crean con elementos Rectangle.
Para crear un nuevo proyecto de aplicación de Silverlight en Expression Blend
1. Inicie Expression Blend. Si aparece el formulario de inicio, haga clic en Cerrar.
2. En el menú Archivo, haga clic en Nuevo proyecto.
Aparecerá el cuadro de diálogo Nuevo proyecto.
3. En el recuadro Tipos de proyecto, seleccione Silverlight.
4. En la lista de proyectos, seleccione Aplicación de Silverlight.
2. En la mesa de trabajo, dibuje una elipse de unos 330 píxeles de ancho y de alto. Mientras dibuja,
presione la tecla MAYÚS para mantener el ancho y el alto iguales.
3. Si necesita cambiar la posición de la elipse, en el panel Herramientas, haga clic en la herramienta
Selección y cambie la elipse de posición.
5. En el panel Propiedades, en Pinceles, haga clic en Relleno y, a continuación, haga clic en Pincel
de color sólido.
6. En el Editor de colores, establezca el color en negro.
Ahora, la elipse tiene un relleno de color negro semitransparente que proporcionará el efecto de
sombra.
8. En el menú Archivo, haga clic en Guardar todo.
A continuación, va a crear el borde exterior del reloj. Dado que el borde exterior tiene el mismo tamaño que
la elipse de sombra, podrá crearlo copiando simplemente la elipse de sombra.
Para crear el borde exterior del reloj
1. En el panel Herramientas, haga clic en la herramienta Selección.
2. En la mesa de trabajo, haga clic en la elipse de sombra para asegurarse de que está seleccionada.
3. En el menú Edición, seleccione Copiar o presione CTRL+C.
4. En el menú Edición, seleccione Pegar o presione CTRL+V.
Aparecerá una nueva elipse denominada shadowEllipse_Copy justo encima de la elipse de sombra.
5. En el panel Propiedades, establezca el nombre en outerRimEllipse.
A continuación, va a cambiar la dirección del degradado lineal para que fluya de la parte superior
izquierda a la parte inferior derecha (en lugar de fluir de izquierda a derecha sobre la elipse).
11. En el panel Herramientas, haga clic en la herramienta Degradado.
A continuación, va a crear el bisel del reloj. La elipse que va a usar para crear el bisel es similar a
outerRimEllipse, pero algo más pequeña.
Para crear el bisel del reloj
1. Seleccione la elipse outerRimEllipse.
2. Cree una copia de outerRimEllipse y péguela.
3. En el panel Propiedades, establezca el nombre de la copia de outerRimEllipse en bevelEllipse.
4. En el panel Propiedades, en Diseño, establezca el valor de Ancho y de Alto en 290.
A continuación, va a rellenar bevelEllipse con un degradado lineal. Dado que bevelEllipse es una
copia de outerRimEllipse, ya tendrá aplicado un degradado.
5. En el panel Propiedades, en Pinceles, haga clic en el punto de degradado izquierdo y establezca
su color en #FF2F2F32.
6. Haga clic en el punto de degradado derecho y establezca su color en #FFE4E5F4.
7. Arrastre el punto de degradado derecho hacia la derecha hasta que sea del 100%.
Este degradado fluye en la misma dirección que el degradado aplicado a outerRimEllipse. Sin
embargo, el degradado de bevelEllipse pasa de oscuro en la parte superior izquierda a claro en la
parte inferior derecha, que es lo contrario de lo que ocurre con el degradado aplicado a
outerRimEllipse. En la ilustración siguiente, se muestra el degradado.
A continuación, creará la cara del reloj. La elipse que va a usar para crear la cara es similar a bevelEllipse,
pero algo más pequeña.
Para crear la cara del reloj
1. Seleccione la elipse bevelEllipse.
2. Cree una copia de bevelEllipse y péguela.
3. En el panel Propiedades, establezca el nombre de la copia de bevelEllipse en faceEllipse.
4. En el panel Propiedades, en Diseño, establezca el valor de Ancho y de Alto en 270.
5. En el panel Propiedades, en Pinceles, haga clic en Relleno, haga clic en Pincel de color sólido y, a
continuación, establezca el color en negro.
Observe que, al agregar esta elipse, el bisel se vuelve visible.
9. En el menú Objeto, haga clic en Alinear y, a continuación, haga clic en Centros horizontales.
La elipse centerEllipse está alineada horizontalmente.
10. En el menú Objeto, haga clic en Alinear y, a continuación, haga clic en Centros verticales.
La elipse centerEllipse está alineada verticalmente.
1. En el panel Herramientas, haga clic con el botón secundario en la herramienta Elipse y haga clic
en la herramienta Rectángulo.
2. En la cara del reloj, dibuje un rectángulo grande y estrecho que represente la posición de las 12 en
punto.
3. En el panel Propiedades, establezca el nombre en secondHand.
4. En el panel Propiedades, en Pinceles, haga clic en Relleno, haga clic en Pincel de color sólido y, a
continuación, establezca el color en rojo.
5. En el panel Propiedades, en Diseño, establezca el valor de Ancho en 5 y el valor de Alto en 80.
6. En el panel Objetos y escala de tiempo, seleccione secondHand, presione la tecla CTRL y, a
continuación, seleccione faceEllipse.
7. En el menú Objeto, haga clic en Alinear y, a continuación, haga clic en Centros horizontales.
8. En el panel Herramientas, haga clic en la herramienta Selección.
9. En el panel Objetos y escala de tiempo, haga clic en secondHand para seleccionar el rectángulo
secondHand.
10. En la esquina inferior izquierda de la mesa de trabajo, haga clic en la flecha Zoom para acercar el
rectángulo secondHand.
En el paso siguiente, va a cambiar el punto central del rectángulo al centro de la cara del reloj. Más
adelante, animará las manecillas del reloj alrededor del centro del reloj.
11. Arrastre el punto central del rectángulo secondHand hasta el centro de la cara del reloj.
12. Cree un segundo rectángulo que represente el minutero con las siguientes propiedades.
o Nombre = minuteHand
o Relleno, Pincel de color sólido, verde
o Ancho = 9, Alto = 80
o Alinear centros horizontalmente
o Punto central establecido en el centro de la cara del reloj
13. Cree un tercer rectángulo que represente el horario con las siguientes propiedades.
o Nombre = hourHand
o Relleno, Pincel de color sólido, verde
o Ancho = 11, Alto = 60
o Alinear centros horizontalmente
o Punto central establecido en el centro de la cara del reloj
Cuando termine, las manecillas del reloj estarán una encima de la otra.
En la siguiente sección, va a agregar animaciones para que las manecillas giren alrededor del reloj.
Esto lo hará animando la propiedad Angle del elemento RotateTransform que se aplica a la
manecilla del reloj. Dado que la animación deberá tener como destino la transformación
RotateTransform correcta, tendrá que asignar un nombre a los elementos RotateTransform
aplicados a cada una de las manecillas del reloj. No se puede cambiar el nombre de los elementos
RotateTransform en la interfaz de usuario de Expression Blend, por lo que habrá que hacerlo en
código XAML.
14. En la esquina superior derecha de la mesa de trabajo, haga clic en la pestaña Vista XAML o Vista
en dos paneles.
Ahora podrá ver el marcado XAML de todos los objetos que ha creado en el diseñador. Las
manecillas del reloj se crean con elementos Rectangle.
15. Busque el rectángulo secondHand en el código XAML.
16. Modifique el rectángulo secondHand agregando un elemento Rectangle.RenderTransform y un
elemento RotateTransform denominado secondHandTransform, tal y como se muestra en el
siguiente código XAML.
<!-- Second Hand -->
<Rectangle x:Name="secondHand" ...>
<Rectangle.RenderTransform>
<RotateTransform x:Name="secondHandTransform"/>
</Rectangle.RenderTransform>
</Rectangle>
19. En la esquina superior derecha, haga clic en la pestaña Vista de diseño para mostrar la vista de
diseño.
20. Guarde el proyecto.
Una vez llegado a este punto, ya ha creado todos los gráficos del reloj. A continuación, va a aplicar
animaciones a las transformaciones de giro de las manecillas del reloj. Estas animaciones de giro harán que
las manecillas del reloj giren alrededor del centro del reloj (tal y como se espera que hagan las manecillas
del reloj). Controlando el tiempo de las animaciones, puede hacer que las manecillas giren alrededor del
reloj en sincronización con la hora actual del equipo.
Para agregar animaciones a las manecillas del reloj
1. Muestre el panel Proyectos.
2. Asegúrese de que esté seleccionado MainPage.xaml.
3. Haga clic en la pestaña Vista XAML o Vista en dos paneles para mostrar el código XAML.
4. Después del elemento inicial UserControl, escriba el código siguiente para agregar animaciones a
las manecillas del reloj.
<UserControl.Resources>
<Storyboard x:Name="clockStoryboard">
<!-- This animation targets the hour hand transform -->
<DoubleAnimation x:Name="hourAnimation"
Storyboard.TargetName="hourHandTransform"
Storyboard.TargetProperty="Angle"
Este marcado define un objeto Storyboard que contiene las animaciones que animan las manecillas
del reloj. Todas estas animaciones hacen referencia a la propiedad Angle de la correspondiente
transformación de la manecilla del reloj. La propiedad Duration de cada animación se establece
dependiendo de la velocidad deseada de la animación. Por ejemplo, para la transformación del
horario, la duración de la animación se establece en 12 horas, que es el tiempo que tarda la
manecilla de la hora en recorrer el reloj completamente. RepeatBehavior para todas las animaciones
se establece en "Forever". Por consiguiente, cuando la animación se completa (la manecilla da una
vuelta completa al reloj), vuelve a empezar de nuevo y se repite indefinidamente.
Para iniciar el objeto Storyboard, va a usar el evento Loaded para llamar al método Begin del objeto
Storyboard.
5. Busque el elemento Grid y agregue el siguiente atributo Loaded.
De este modo, se especifica que se debe llamar al controlador de eventos SetAndStartClock cuando
se carga la aplicación.
<Grid x:Name="LayoutRoot" Background="White" Loaded="SetAndStartClock">
8. Guarde el proyecto.
9. Haga clic en el menú Proyecto y, a continuación, haga clic en Ejecutar proyecto para compilar y
ejecutar la aplicación. (También puede presionar F5 para ejecutar la aplicación.)
Se abrirá el explorador web y el reloj comenzará a funcionar. Observe que el segundero se está
moviendo alrededor del reloj. Las otras manecillas también se están moviendo, pero lo están
haciendo tan despacio que no es perceptible.
Aunque las manecillas del reloj se están moviendo a la velocidad esperada, el reloj no está ajustado en la
hora actual. Para ajustar el reloj, deberá agregar cierta lógica.
Para establecer el reloj en la hora actual
1. Cierre el explorador y abra MainPage.xaml.vb o MainPage.xaml.cs.
2. En lugar del procedimiento de SetAndStartClock, escriba el código que figura a continuación.
Con este código, se establecen las manecillas del reloj en la hora actual.
Private Sub SetAndStartClock(ByVal sender As Object, ByVal e As EventArgs)
' The current date and time.
Dim currentDate As Date = DateTime.Now
' Find the appropriate angle (in degrees) for the hour hand
' based on the current time.
Dim hourangle As Double = (((CType(currentDate.Hour, Single) / 12) * 360) + (currentDate.Minute / 2))
3. Ejecute la aplicación.
Ahora, las manecillas del reloj deben señalar la hora actual.
Estos gráficos se crean con elementos simples organizados en un control Grid. Todos los gráficos circulares,
incluidos los gráficos de la cara de reloj, el borde exterior, el bisel y la sombra, se crean con elementos
Ellipse, mientras que las manecillas del reloj se crean con elementos Rectangle.
Para crear un nuevo proyecto de aplicación de Silverlight en Visual Studio 2008
1. Inicie Visual Studio.
2. Cree un nuevo proyecto de aplicación de Silverlight denominado SilverlightClock en Visual Basic o
Visual C#.
3. En el cuadro de diálogo Nueva aplicación de Silverlight, desactive la casilla Hospedar la
aplicación de Silverlight en un nuevo sitio web y, en la lista Versión de Silverlight, seleccione
Silverlight 4.
Los gráficos del reloj se componen de capas de formas superpuestas, que crean la apariencia general de un
reloj. Para crear el reloj, deberá construirlo capa por capa, comenzando por la capa inferior, que es la
sombra del reloj.
Para crear la sombra del reloj
1. Abra MainPage.xaml.
2. Reemplace el XAML existente por el siguiente XAML para crear la sombra del reloj.
<UserControl x:Class="SilverlightClock.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
Observe que el relleno se establece en negro y la opacidad se establece en 0,3 (30%). Esto hace que
el relleno de la elipse sea semitransparente, como una sombra. El ancho, el alto y el margen son
arbitrarios. Estas propiedades simplemente especifican el tamaño y la posición del círculo dentro
del control Grid.
Nota:
El lenguaje de procedimientos utilizado (por ejemplo, Visual Basic, C# o JavaScript) no afecta a la
mayor parte del marcado XAML en las aplicaciones de Silverlight.
La elipse de sombra está colocada ligeramente hacia la parte inferior derecha de modo que solo se
ve un fragmento de esa elipse. Esto produce un efecto de sombra. Además, observe que se ha
aplicado un degradado lineal a la elipse del borde exterior. Este degradado lineal sirve para crear
un efecto de luz procedente de la parte superior izquierda de la elipse.
A continuación, agregará el bisel del reloj.
Esta elipse tiene un tamaño ligeramente inferior que la elipse utilizada para crear el borde exterior y
se encuentra directamente sobre la elipse del borde exterior. Además, esta elipse también tiene
aplicado un degradado lineal, pero este degradado pasa de oscuro en la parte superior izquierda a
claro en la parte inferior derecha.
A continuación, creará la cara del reloj.
Para crear la cara del reloj
En MainPage.xaml, después de la elipse del bisel, agregue el siguiente código XAML para crear la
cara del reloj.
<!-- Face -->
<Ellipse Fill="#FF000000" Height="270" Margin="65,65,65,65"
Stroke="#FF000000" Width="270" />
La cara del reloj es simplemente una elipse rellena de negro, de tamaño ligeramente inferior al de
la elipse del bisel y colocada directamente sobre las demás elipses. Observe también que, al
agregar esta elipse, el bisel se vuelve visible.
En el código anterior, el minutero, el horario y el segundero comparten los mismos valores para las
propiedades que determinan la posición (por ejemplo, Margin). No obstante, las manecillas difieren
entre sí en lo que se refiere al tamaño y/o color (por ejemplo, el horario es el más grueso porque
tiene el valor StrokeThickness más elevado).
Observe que todas las manecillas tienen aplicada una transformación RotateTransform. Esta
transformación permite girar el ángulo de la manecilla. En la sección siguiente, animará el ángulo
de esta transformación, que hará que las manecillas del reloj se muevan para mostrar la hora. Cada
uno de los elementos RotateTransform tiene un nombre (por ejemplo,
x:Name="hourHandTransform"). De este modo, puede asociar una animación a la transformación.
Además, tenga en cuenta que todas las manecillas tienen un valor RenderTransformOrigin. Esta
propiedad se usa para especificar el punto del lienzo con respecto al que todas las
transformaciones son relativas. Puesto que va a girar las manecillas alrededor del centro del reloj, el
valor de la propiedad RenderTransform para todas las manecillas se proporciona como centro de la
cara del reloj.
Una vez llegado a este punto, ya ha creado todos los gráficos del reloj. A continuación, va a aplicar
animaciones a las transformaciones de giro de las manecillas del reloj. Estas animaciones de giro harán que
las manecillas del reloj giren alrededor del centro del reloj (tal y como se espera que hagan las manecillas
del reloj). Controlando el tiempo de las animaciones, puede hacer que las manecillas giren alrededor del
reloj en sincronización con la hora actual del equipo.
Para agregar animaciones a las manecillas del reloj
1. En MainPage.xaml, después del elemento inicial UserControl, escriba el código siguiente para
agregar animaciones a las manecillas del reloj.
<UserControl.Resources>
<Storyboard x:Name="clockStoryboard">
<!--This animation targets the hour hand transform-->
<DoubleAnimation x:Name="hourAnimation"
Storyboard.TargetName="hourHandTransform"
Storyboard.TargetProperty="Angle"
Este marcado define un objeto Storyboard que contiene las animaciones que animan las manecillas
del reloj. Todas estas animaciones de Storyboard hacen referencia a la propiedad Angle de la
transformación de la manecilla del reloj correspondiente. La propiedad Duration de cada animación
se establece dependiendo de la velocidad deseada de la animación. Por ejemplo, para la
transformación del horario, la duración de la animación se establece en 12 horas, que es el tiempo
que tarda la manecilla de la hora en recorrer el reloj completamente. RepeatBehavior para todas las
animaciones se establece en "Forever". Por consiguiente, cuando la animación se completa (la
manecilla da una vuelta completa al reloj), vuelve a empezar de nuevo y se repite indefinidamente.
Para iniciar el objeto Storyboard, use el evento Loaded a fin de llamar al método Begin del objeto
Storyboard.
2. En el elemento Grid, agregue el siguiente atributo Loaded.
De este modo, se especifica que se debe llamar al controlador de eventos SetAndStartClock cuando
se carga la aplicación.
<Grid x:Name="LayoutRoot" Loaded="SetAndStartClock">
5. Guarde el proyecto.
6. En el menú Depurar, haga clic en Iniciar depuración o presione F5 para ejecutar la aplicación.
Se abrirá el explorador web y el reloj comenzará a funcionar. Observe que el segundero se está
moviendo alrededor del reloj. Las otras manecillas también se están moviendo, pero lo están
haciendo tan despacio que no es perceptible.
Aunque las manecillas del reloj se están moviendo a la velocidad esperada, el reloj no está ajustado en la
hora actual. Para ajustar el reloj, deberá agregar cierta lógica.
Para establecer el reloj en la hora actual
1. Cierre el explorador y abra MainPage.xaml.vb o MainPage.xaml.cs.
2. En lugar del procedimiento de SetAndStartClock, escriba el código que figura a continuación.
Con este código, se establecen las manecillas del reloj en la hora actual.
Private Sub SetAndStartClock(ByVal sender As Object, ByVal e As EventArgs)
' The current date and time.
Dim currentDate As Date = DateTime.Now
' Find the appropriate angle (in degrees) for the hour hand
' based on the current time.
Dim hourangle As Double = (((CType(currentDate.Hour, Single) / 12) * 360) + (currentDate.Minute / 2))
' The same as for the minute angle.
3. Ejecute la aplicación.
Ahora, las manecillas del reloj deben señalar la hora actual.
Conclusión
En este tutorial, ha aprendido a hacer lo siguiente en Silverlight:
Diseñar gráficos vectoriales superpuestos que simulan el aspecto de un reloj real.
Usar degradados para crear sombreado y profundidad.
Usar animaciones para agregar funcionalidad al reloj.
Usar código para ajustar la hora correcta del reloj.
Obtenga información sobre cómo utilizar Expression Blend y Visual Studio para crear aplicaciones
de Silverlight.
Requisitos previos
Se necesitan los siguientes componentes para compilar el Editor de texto de Silverlight:
Silverlight 4.
Silverlight 4 Tools para Visual Studio 2010.
Visual Studio 2010.
Barra de herramientas
La barra de herramientas se hospeda en un control Grid denominado ToolBarGrid. El control ToolBarGrid
tiene dos filas y siete columnas. La primera fila no tiene ningún elemento secundario y se utiliza para
agregar relleno a la segunda fila. En la segunda fila se hospedan los botones de la barra de herramientas.
Cada columna hospeda una sección de la barra de herramientas, por ejemplo, Portapapeles, Fuente, etc.
Considere una sección de la barra de herramientas como ejemplo. La segunda columna del control
ToolBarGrid (Grid.Column = 1) hospeda la sección Fuente de la barra de herramientas. Esta sección consta
de siete controles. En la siguiente tabla, se muestran los elementos de la sección Fuente y el control que se
utiliza para crear cada elemento.
La posición de los controles ComboBox usados para crear el nombre de fuente y el tamaño de fuente se
define estableciendo un valor de margen adecuado. La posición de los controles Button y del control
ComboBox para el color de fuente se determina utilizando un diseño de StackPanel con orientación
horizontal. La posición del control TextBlock para el título de la sección se define con un valor de margen
adecuado. En el siguiente XAML, se muestra la sección Fuente de la barra de herramientas.
<!--Fonts Toolbar Section-->
<ComboBox x:Name="cmbFonts" ...
<ComboBoxItem Content="Arial" ...
<ComboBoxItem Content="Arial Black" ...
...
</ComboBox>
<ComboBox x:Name="cmbFontSizes" …
<ComboBoxItem Content="8" Tag="8"/>
<ComboBoxItem Content="9" Tag="9"/>
...
</ComboBox>
<StackPanel Grid.Column="1" Grid.Row="1" ...
<!--Buttons-->
<Button x:Name="btnBold" ...
<Button x:Name="btnItalic" ...
<Button x:Name="btnUnderline" ...
<ComboBox x:Name="cmbFontColors" ...
<ComboBoxItem Tag="FFFF0000">
<ComboBoxItem Tag="FF008000">
...
</ComboBox>
</StackPanel>
Editor
El editor se hospeda en un control Grid denominado RTBGrid. En la siguiente tabla, se muestran los
elementos secundarios de RTBGrid.
Elemento
Nombre Descripción
secundario
Rectangle Se utiliza como borde alrededor del control RichTextBox.
RichTextBox rtb Se utiliza para escribir y modificar contenido enriquecido.
Canvas highlightCanvas Se utiliza al hacer clic en el botón Resaltar de la barra de herramientas.
Se utiliza para que se muestre el código XAML al hacer clic en el botón
XAML de la barra de herramientas. Este control TextBox está oculto de
TextBox xamlTB
forma predeterminada y se muestra únicamente cuando se hace clic en el
botón XAML de la barra de herramientas.
Portapapeles
Es posible cortar, copiar o pegar un texto seleccionado en el editor mediante los botones Cortar, Copiar o
Pegar situados en la sección Portapapeles de la barra de herramientas. Esto se implementa mediante el
nuevo objeto Clipboard de Silverlight 4, tal y como se muestra en el siguiente código.
//Cut the selected text
private void btnCut_Click(object sender, RoutedEventArgs e)
{
Clipboard.SetText(rtb.Selection.Text);
rtb.Selection.Text = "";
ReturnFocus();
}
//Copy the selected text
private void btnCopy_Click(object sender, RoutedEventArgs e)
{
Clipboard.SetText(rtb.Selection.Text);
ReturnFocus();
}
//paste the text
private void btnPaste_Click(object sender, RoutedEventArgs e)
{
rtb.Selection.Text = Clipboard.GetText();
ReturnFocus();
}
Menú contextual
Asimismo, es posible cortar, copiar y pegar un texto seleccionado mediante un menú contextual. El menú
contextual aparece cuando se hace clic con el botón secundario del mouse en el editor. Los eventos que se
producen al hacer clic con el botón secundario del mouse son una característica nueva de Silverlight 4. En la
siguiente ilustración se muestra el menú contextual.
El menú contextual se implementa mediante el control Popup. La lógica del menú contextual se encuentra
fundamentalmente en los archivos ContextMenu.cs y RTBContextMenu.cs del proyecto.
ContextMenu es una clase abstracta que proporciona la funcionalidad básica para crear, mostrar y cerrar un
menú contextual. Es posible derivar de esta clase base para crear cualquier menú contextual que se desee.
La clase ContextMenu proporciona las siguientes funcionalidades:
Define un método abstracto denominado GetContent.
La clase derivada debe implementar el método GetContent para crear el contenido deseado del
menú contextual. El método GetContent devuelve un objeto FrameworkElement que tiene el
contenido del menú contextual.
_isShowing = true;
_location = location;
ConstructPopup();
_popup.IsOpen = true;
}
Controla el evento MouseLeftButtonUp para las operaciones de cortar, copiar y pegar cuando se
hace clic en los correspondientes botones del menú contextual. En el siguiente código, se muestran
los controladores de eventos para las operaciones de cortar, copiar y pegar.
//handle the cut, copy and paste actions when the appropriate button on the context menu is clicked.
void cut_MouseLeftButtonUp(object sender, RoutedEventArgs e)
{
Clipboard.SetText(rtb.Selection.Text);
rtb.Selection.Text = "";
Close();
}
void copy_MouseLeftButtonUp(object sender, RoutedEventArgs e)
{
Clipboard.SetText(rtb.Selection.Text);
Close();
}
void paste_MouseLeftButtonUp(object sender, RoutedEventArgs e)
{
rtb.Selection.Text = Clipboard.GetText();
Close();
}
Fuente
El ejemplo del editor de texto de Silverlight permite aplicar a un texto seleccionado los formatos de negrita,
cursiva, subrayado, tipo de fuente, tamaño de fuente y color de fuente. Para usar un formato de fuente, se
aplica el método TextSelection.ApplyPropertyValue al texto seleccionado en el control RichTextBox con la
propiedad de dependencia y el valor de propiedad apropiados. En la siguiente tabla, se resumen la
propiedad de dependencia y el valor de propiedad que se pueden usar para aplicar el formato de fuente.
Formato de Propiedad de
Valor de propiedad
fuente dependencia
Se usa la propiedad FontWeights.Bold para aplicar el formato de
negrita al texto seleccionado. Se usa
Negrita FontWeightProperty
la propiedad FontWeights.Normal para quitar el formato de
negrita del texto seleccionado.
Se usa la propiedad FontStyles.Italic para aplicar el formato de
cursiva al texto seleccionado.
Cursiva FontStyleProperty
Se usa la propiedad FontStyles.Normal para quitar el formato de
cursiva del texto seleccionado.
En el siguiente código, se muestra cómo se aplica el formato de fuente en el ejemplo del editor de texto de
Silverlight.
RichNotepadSnippets#Font1, Font2
Insertar
Es posible insertar elementos como imágenes, hipervínculos, cuadrículas de datos y calendarios en el
ejemplo del editor de texto de Silverlight.
El botón Insertar imagen permite insertar una imagen en la ubicación actual del editor. Primero, se crea la
imagen con un objeto Image que apunta a un identificador URI que especifica la ubicación de la imagen. A
continuación, se inserta la imagen en el control RichTextBox mediante un objeto InlineUIContainer. En este
ejemplo, se inserta una imagen denominada desert.jpg que se almacena como un recurso del proyecto. Sin
embargo, es posible insertar cualquier otra imagen pasando el identificador URI adecuado.
En el siguiente código, se muestra cómo se inserta una imagen.
'Insert an image into the RichTextBox
Private Sub btnImage_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
Dim container As InlineUIContainer = New InlineUIContainer
container.Child = MainPage.createImageFromUri(New Uri("/RichNotepad;component/images/Desert.jpg",
UriKind.RelativeOrAbsolute), 200, 150)
rtb.Selection.Insert(container)
'ReturnFocus()
End Sub
Private Shared Function createImageFromUri(ByVal URI As Uri, ByVal width As Double, ByVal height As Double) As Image
Dim img As Image = New Image
img.Stretch = Stretch.Uniform
img.Width = width
img.Height = height
Dim bi As BitmapImage = New BitmapImage(URI)
img.Source = bi
img.Tag = bi.UriSource.ToString
Return img
End Function
El proceso para insertar cualquier otro objeto UIElement en un control RichTextBox es igual que el proceso
que se ha descrito para insertar un control Image. En este ejemplo, se utiliza el mismo proceso para insertar
objetos DataGrid y Calendar.
El botón Insertar hipervínculo permite insertar hipervínculos en el editor. Para insertar un hipervínculo, se
utiliza el elemento Hyperlink. Se usa la propiedad NavigateUri para especificar el identificador. Cuando se
hace clic en el botón Insertar hipervínculo, aparece el cuadro de diálogo Insertar dirección URL, tal y
como se muestra en la siguiente ilustración.
El cuadro de diálogo Insertar dirección URL es un control ChildWindow que permite escribir la Dirección
URL de destino y una Descripción de la dirección URL del hipervínculo. En el siguiente código, se muestra
cómo se implementa la inserción del hipervínculo.
//Insert a hyperlink
private void btnHyperlink_Click(object sender, RoutedEventArgs e)
{
InsertURL cw = new InsertURL(rtb.Selection.Text);
cw.HasCloseButton = false;
if (cw.txtURLDesc.Text.Length > 0)
hyperlink.Inlines.Add(cw.txtURLDesc.Text);
else
hyperlink.Inlines.Add(cw.txtURL.Text);
rtb.Selection.Insert(hyperlink);
ReturnFocus();
}
};
cw.Show();
}
Cuando se hace clic en el botón Aceptar o Cancelar del cuadro de diálogo Insertar dirección URL, se
valida el valor de Dirección URL de destino. Esta validación se realiza en el controlador de eventos Closing.
La validación se realiza en el evento Closing en lugar del evento Closed porque, de este modo, se mantiene
abierto el cuadro de diálogo si se produce un error de validación. Si el identificador URI es válido, se crea un
nuevo objeto Hyperlink y se inserta en la selección actual del control RichTextBox.
Imprimir
Es posible imprimir el contenido del editor mediante el botón Imprimir. La impresión es una nueva
característica de Silverlight 4. Cuando se hace clic en el botón Imprimir, se muestra el cuadro de diálogo
Vista previa de impresión. Este cuadro de diálogo Vista previa de impresión es un objeto ChildWindow
que tiene una imagen del contenido que se va a imprimir. En la ilustración siguiente, se muestra el cuadro
de diálogo Vista previa de impresión.
Esta imagen se crea con un objeto WriteableBitmap que toma el objeto RichTextBox como parámetro. A
continuación se muestran el código XAML para crear el cuadro de diálogo Vista previa de impresión y el
código para crear la imagen WriteableBitmap.
<!-- NOTE:
By convention, the sdk prefix indicates a URI-based XAML namespace declaration
for Silverlight SDK client libraries. This namespace declaration is valid for
Silverlight 4 only. In Silverlight 3, you must use individual XAML namespace
declarations for each CLR assembly and namespace combination outside the scope
of the default Silverlight XAML namespace. For more information, see the help
topic "Prefixes and Mappings for Silverlight Libraries".
Cuando se hace clic en el botón Aceptar del cuadro de diálogo Vista previa de impresión, su contenido se
imprime mediante el objeto PrintDocument, tal y como se muestra en el siguiente código.
//Print the document
private void btnPrint_Click(object sender, RoutedEventArgs e)
{
PrintPreview cw = new PrintPreview();
cw.ShowPreview(rtb);
cw.HasCloseButton = false;
//Hook up a handler to the Closed event before displaying the PrintPreview window by calling the Show() method.
cw.Closed += (t, a) =>
{
if (cw.DialogResult.Value)
{
PrintDocument theDoc = new PrintDocument();
theDoc.PrintPage += (s, args) =>
{
args.PageVisual = rtb;
args.HasMorePages = false;
};
theDoc.EndPrint += (s, args) =>
{
MessageBox.Show("The document printed successfully", "Text Editor", MessageBoxButton.OK);
};
theDoc.Print("Silverlight 4 Text Editor");
ReturnFocus();
}
};
cw.Show();
}
Display
El ejemplo del editor de texto de Silverlight admite el diseño de derecha a izquierda, que es una nueva
característica de Silverlight 4. Se incluye por motivos de compatibilidad con idiomas como el árabe y el
hebreo. En la siguiente ilustración, se muestra el ejemplo del editor de texto de Silverlight en el diseño de
derecha a izquierda.
El botón de alternancia Dirección del texto sirve para pasar del diseño de izquierda a derecha al diseño de
derecha a izquierda, y viceversa. En el siguiente código, se muestra cómo se usa el objeto FlowDirection
para este propósito.
//Set the flow direction
public void btnRTL_Checked(object sender, RoutedEventArgs e)
{
//Set the button image based on the state of the toggle button.
if(btnRTL.IsChecked.Value)
btnRTL.Content = MainPage.createImageFromUri(new Uri("/RichNotepad;component/images/rtl.png",
UriKind.RelativeOrAbsolute), 30, 32);
else
btnRTL.Content = MainPage.createImageFromUri(new Uri("/RichNotepad;component/images/ltr.png",
UriKind.RelativeOrAbsolute), 30, 32);
ApplicationBorder.FlowDirection = (ApplicationBorder.FlowDirection == System.Windows.FlowDirection.LeftToRight) ?
System.Windows.FlowDirection.RightToLeft : System.Windows.FlowDirection.LeftToRight;
ReturnFocus();
}
El botón de alternancia Modo de edición o vista para pasar del modo de edición al estado de solo lectura
del editor, y viceversa. De forma predeterminada, el editor está en modo de edición. En el siguiente código,
se muestra cómo se implementa el modo de edición o de solo lectura.
//Make the RichTextBox read-only
public void btnRO_Checked(object sender, RoutedEventArgs e)
{
rtb.IsReadOnly = !rtb.IsReadOnly;
//Set the button image based on the state of the toggle button.
if (rtb.IsReadOnly)
btnRO.Content = MainPage.createImageFromUri(new Uri("/RichNotepad;component/images/view.png",
UriKind.RelativeOrAbsolute), 29, 32);
else
btnRO.Content = MainPage.createImageFromUri(new Uri("/RichNotepad;component/images/edit.png",
UriKind.RelativeOrAbsolute), 29, 32);
ReturnFocus();
}
Para especificar el modo de solo lectura, se establece la propiedad IsReadOnly de RichTextBox en true. Los
elementos de la interfaz de usuario y los hipervínculos de un control RichTextBox están activos únicamente
en modo de solo lectura. Por ejemplo, pueden responder a entradas y recibir el foco únicamente cuando
están en modo de solo lectura.
Resaltar
Cuando se activa el botón de alternancia Resaltar, se resalta toda la línea en la que se encuentra el puntero
del mouse. En la ilustración siguiente, se muestra un ejemplo del resaltado.
Cuando se activa el botón de alternancia del resaltado, el controlador de eventos enumera el contenido del
control RichTextBox y crea un rectángulo que delimita cada línea. Los rectángulos se agregan a una lista. En
los siguientes pasos, se muestra cómo se crea la lista de todos los rectángulos.
1. Obtenga un objeto TextPointer que apunte al comienzo del contenido del control RichTextBox
mediante la propiedad ContentStart.
2. Obtenga el rectángulo delimitador del primer carácter mediante el método GetCharacterRect.
3. Obtenga el rectángulo delimitador de la primera línea. Para ello, se enumera el contenido mediante
el método GetNextInsertionPosition. Obtenga el objeto TextPointer en cada posición. Compruebe si
ha pasado a la línea siguiente; para ello, compare las coordenadas de los puntos Top de los
rectángulos que se han obtenido mediante el comienzo del objeto TextPointer de la línea y el
objeto TextPointer actual. Si pasa a la línea siguiente, cree el rectángulo de la línea actual y
agréguelo a la lista antes de iniciar la misma enumeración para la línea siguiente.
4. Repita el paso anterior hasta que se procesen todas las líneas.
Ya tiene una lista de los rectángulos correspondientes a cada una de las líneas del contenido.
Para determinar qué línea se va a resaltar, el código realiza una prueba de posicionamiento para la posición
actual del mouse con respecto a la lista de rectángulos en el controlador de eventos MouseMove del
control RichTextBox. El código resalta una línea mostrando un rectángulo en el control Canvas denominado
highlightCanvas.
XAML
El botón XAML sirve para mostrar el marcado XAML del contenido del editor. Para ello, se usa la propiedad
RichTextBox.Xaml. En el siguiente código, se ilustra cómo mostrar el XAML mediante la propiedad Xaml.
'Set the xamlTb TextBox with the current XAML of the RichTextBox and make it visible. Any changes to the XAML made
'in xamlTb is also reflected back on the RichTextBox. Note that the Xaml string returned by RichTextBox.Xaml will
'not include any UIElement contained in the current RichTextBox. Hence the UIElements will be lost when you
'set the Xaml back again from the xamlTb to the RichTextBox.
Public Sub btnMarkUp_Checked(ByVal sender As Object, ByVal e As RoutedEventArgs)
If btnMarkUp.IsChecked.Value Then
xamlTb.Visibility = System.Windows.Visibility.Visible
xamlTb.IsTabStop = True
xamlTb.Text = rtb.Xaml
Else
rtb.Xaml = xamlTb.Text
xamlTb.Visibility = System.Windows.Visibility.Collapsed
xamlTb.IsTabStop = False
End If
End Sub
Cuando se hace clic en el botón XAML, el marcado XAML se muestra en un control TextBox denominado
xamlTb. El valor predeterminado de la propiedad Visibility de xamlTb es Collapsed y cambia a Visible
cuando se hace clic en el botón XAML. Si se realizan cambios en el marcado XAML de xamlTb, dichos
cambios se reflejan en el contenido del control RichTextBox. Observe que la cadena XAML devuelta por la
propiedad Xaml no incluye ningún objeto UIElement que se encuentre en el control RichTextBox. Por
consiguiente, se perderán los objetos UIElement cuando se pase de nuevo de la vista XAML al control
RichTextBox.
Archivo
Cuando se hace clic en el botón Nuevo archivo, se borra el contenido existente del control RichTextBox. En
el siguiente código, se muestra el proceso para crear un nuevo archivo.
//Clears the contents of the existing file.
private void btnNew_Click(object sender, RoutedEventArgs e)
{
rtb.Blocks.Clear();
}
Es posible abrir un archivo existente mediante el botón Abrir archivo. En el siguiente código, se muestra el
proceso de abrir un archivo existente.
//Opens an existing file
private void btnOpen_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
Cuando se hace clic en el botón Abrir archivo, se crea un objeto OpenFileDialog que se muestra mediante
el método ShowDialog. Se trata del cuadro de diálogo Abrir archivo estándar de Windows, que se puede
usar para seleccionar el archivo que se desea abrir. El archivo seleccionado se abre como StreamReader y su
contenido se asigna a la propiedad Xaml del control RichTextBox.
Es posible guardar el archivo existente mediante el botón Guardar archivo. Si el control RichTextBox
contiene objetos UIElement, estos no se guardan durante la operación de guardar. No es posible guardar
los objetos UIElement porque la propiedad Xaml del control RichTextBox incluye únicamente contenido de
texto y el marcado asociado. En el siguiente código, se muestra cómo se guarda el contenido actual.
//Saves the existing file
private void btnSave_Click(object sender, RoutedEventArgs e)
{
string ContentToSave = rtb.Xaml;
//Check if the file contains any UIElements
var res = from block in rtb.Blocks
from inline in (block as Paragraph).Inlines
where inline.GetType() == typeof(InlineUIContainer)
select inline;
//If the file contains any UIElements, it will not be saved
if (res.Count() != 0)
{
MessageBox.Show("Saving documents with UIElements is not supported");
return;
}
SaveFileDialog sfd = new SaveFileDialog();
sfd.DefaultExt = ".sav";
sfd.Filter = "Saved Files|*.sav|All Files|*.*";
if (sfd.ShowDialog().Value)
{
using (FileStream fs = (FileStream)sfd.OpenFile())
{
System.Text.UTF8Encoding enc = new System.Text.UTF8Encoding();
byte[] buffer = enc.GetBytes(ContentToSave);
fs.Write(buffer, 0, buffer.Length);
fs.Close();
}
}
}
Primero, el código enumera el contenido del control RichTextBox y comprueba si hay objetos UIElement. Si
el control RichTextBox contiene objetos UIElement, finaliza la operación de guardar y se muestra un cuadro
de mensaje. Si el control RichTextBox solo tiene elementos de texto, se crea un control SaveFileDialog que
se muestra mediante el método ShowDialog. Se trata del cuadro de diálogo Guardar archivo estándar de
Windows, que se puede usar para guardar un archivo. El contenido del control RichTextBox se recupera
como una cadena mediante la propiedad Xaml y, a continuación, se escribe en un objeto FileStream.
Arrastrar y colocar
Es posible abrir archivos de texto y de Office Word en el ejemplo del editor de texto de Silverlight
arrastrándolos hasta el área de contenido. Esta característica se implementa mediante la nueva característica
de arrastrar y colocar de Silverlight 4. En el código siguiente, se muestra el método de control del evento
Drop.
private void rtb_Drop(object sender, System.Windows.DragEventArgs e)
{
VisualStateManager.GoToState(this, "Normal", true);
//the Drop event passes in an array of FileInfo objects for the list of files that were selected and drag-dropped onto the
RichTextBox.
if (e.Data == null)
{
ReturnFocus();
return;
En el controlador de eventos Drop (rtb_Drop), la lista de objetos FileInfo de los archivos colocados en el
control RichTextBox se pasa en el argumento del evento. El controlador de eventos rtb_Drop enumera los
objetos FileInfo y analiza los archivos .txt y .docx. Se omiten los archivos con otras extensiones. Las
funciones ParseTxtFile y ParseDocxFile (que no se muestran en este tema) toman el objeto FileInfo, lo
analizan y agregan su contenido al control RichTextBox.
Requisitos previos
Para compilar el ejemplo Issue Tracker, se requieren los siguientes componentes:
Silverlight 4.
Silverlight 4 Tools para Visual Studio 2010.
Visual Studio 2010.
Kit de herramientas de Silverlight
Servicios RIA de WCF
Kit de herramientas de Servicios RIA de WCF
RichTextBox
Se utiliza para mostrar las tendencias de los Kit de herramientas de
Gráficos
problemas en la página Informes. Silverlight
Se utiliza para personalizar la apariencia de la Kit de herramientas de
Temas
aplicación. Silverlight
Se utiliza para validar los datos
Validación de datos proporcionados por el usuario en los diversos INotifyDataErrorInfo
campos de un problema.
Se utiliza para asociar acciones a los botones
Comandos Guardar y Crear que se utilizan para guardar ICommand
y crear problemas o incidencias.
FileInfo
DragEventArgs
Se utiliza para vincular la aplicación de
Documentación de los
Servicios RIA de WCF Silverlight a la base de datos en la aplicación
servicios RIA de WCF
ASP.NET.
Los temas que se utilizan para personalizar la
Kit de herramientas de
ContextMenu apariencia de la aplicación se muestran en un
Silverlight
menú contextual.
Imprimir
Se utiliza para imprimir los informes sobre las
Impresión
tendencias de los errores.
PrintDocument
Se utiliza para enlazar a datos la propiedad
DataBinding: compatibilidad con SelectedValue de algunos cuadros
SelectedValue
el selector combinados, como el cuadro combinado
Estado.
DataBinding: para especificar los Se utiliza para establecer el valor de
FallbackValue
valores de presentación presentación predeterminado de algunos
predeterminados de un control controles, como el cuadro combinado
TargetNullValue
enlazado a datos Abierto por.
DataBinding: para agrupar los Se utiliza para agrupar las plataformas de un
GroupDescriptions
elementos de una colección problema por tipo de procesador.
Se utiliza para mostrar el texto con formato en
DataBinding: formato de cadena el bloque de texto donde se muestra el StringFormat
identificador del problema.
Para personalizar la apariencia del ejemplo Issue Tracker, se puede usar el menú contextual que aparece
cuando se hace clic con el botón secundario del mouse en cualquier punto del ejemplo. Este
comportamiento se implementa mediante los controles Themes y ContextMenu, que están disponibles en el
Kit de herramientas de Silverlight.
El ejemplo también tiene un indicador de ocupación que aparece cuando el cliente IssueTracker está
comunicando con el servicio IssueTracker.Web. Este comportamiento se implementa mediante el control
BusyIndicator, que también está incluido en el Kit de herramientas de Silverlight.
Aplicación IssueTracker.Web ASP.NET
IssueTracker.Web es una aplicación ASP.NET que hospeda una base de datos denominada
IssueTrackerData.mdf y la lógica de nivel medio que administra la interacción entre la aplicación cliente
IssueTracker y la base de datos.
En la siguiente tabla, se muestran las diversas tablas que se incluyen en esta base de datos.
Para crear un vínculo de servicios RIA entre el servidor y el cliente de Silverlight, se necesita un modelo de
entidad que represente las tablas y las columnas presentes en la base de datos. Un modelo de entidad
representa las tablas y las columnas como tipos de CLR (las tablas se representan como clases; las columnas
y las asociaciones de clave externa se representan como propiedades). En este proyecto, se usa el modelo
de entidad LINQ to SQL, representado por el archivo IssueTrackerData.Dbml.
Una vez elegido el modelo de entidad, se puede crear un vínculo de servicios RIA agregando una clase
LinqToSqlDomainService(Of TContext) al servidor. Para ello, se utiliza el cuadro de diálogoque permite
agregar una nueva clase de servicio de dominio. En este cuadro de diálogo, se pueden seleccionar los tipos
(que representan las tablas) del modelo de entidad que se van a incluir en el servicio de dominio. Hay que
activar la casilla que permitehabilitar la edición para que pueda haber un enlace de datos bidireccional entre
el cliente y el servidor. La clase de servicio de dominio para este proyecto es la clase
IssueTrackerDomainService. Al crear el servicio de dominio, se generan automáticamente los métodos para
consultar, actualizar y eliminar filas en todas las tablas asociadas. Además, hace que los mismos métodos
estén disponibles en el proyecto de cliente de Silverlight como la clase IssueTrackerDomainContext. Se
modifican estos métodos para personalizar el resultado de las consultas.
La página My Issues (Mis problemas) es similar a la página All Issues (Todos los problemas), salvo la
consulta GetMyIssues que se utiliza para rellenar DataGrid. La consulta GetMyIssues filtra los problemas
asignados al usuario actual.
Al seleccionar un problema en el control DataGrid, el control IssueEditor se rellena con los detalles del
problema seleccionado. El problema seleccionado se pasa como DataContext al control IssueEditor, tal y
como se muestra en el siguiente XAML.
<my:IssueEditor Grid.Row="2" DataContext="{Binding Data.CurrentItem, ElementName=issueDomainDataSource}"
x:Name="issueEditor1" />
IssueEditor es un control de usuario que se utiliza para ver y actualizar los detalles de un problema. El
control IssueEditor se utiliza para ver y actualizar los problemas en la página All Issues (Todos los
problemas), ver y actualizar los problemas asignados al usuario en la página My Issues (Mis problemas), y
crear un nuevo problema en la página New Issue (Nuevo problema). El control IssueEditor se compone de
un gran número de controles de Silverlight que están enlazados a varias columnas y las muestran en la tabla
Issues. En las siguientes secciones, se describe cómo se implementan las áreas de título del problema,
estado, usuario al que se asigna el problema y plataforma del control IssueEditor.
Título del problema
El título del problema se muestra en un control TextBox que está enlazado a la columna Title
correspondiente al problema seleccionado en la tabla Issues, tal y como se muestra en el siguiente XAML.
<TextBox Name="textBox4" Grid.Column="1" Text="{Binding Path=Title, Mode=TwoWay, NotifyOnValidationError=True}"
VerticalAlignment="Center" />
Status
El estado del problema se muestra en un control ComboBox. Los elementos del control ComboBox están
enlazados a la tabla Status y la propiedad SelectedValue del control ComboBox está enlazada al estado del
problema seleccionado. En el siguiente XAML, se muestra cómo se implementa.
<ComboBox DisplayMemberPath="Name" ItemsSource="{Binding Status, Source={StaticResource issueTrackerData}}"
Name="comboBox7" SelectedValue="{Binding StatusID, Mode=TwoWay}" SelectedValuePath="StatusID" ...
Plataforma
La información de plataforma contiene opciones de sistema operativo, explorador e idioma que se pueden
asociar a un problema. La información de plataforma se muestra en un control DataGrid que está enlazado
a la tabla Platforms de la base de datos, tal y como se muestra en el siguiente XAML.
<sdk:DataGrid Name="dataGrid3" IsReadOnly="True" ItemsSource="{Binding Source={StaticResource platformViewSource}}"
SelectedItem="{Binding Platform, Mode=TwoWay}" ...
<sdk:DataGrid.Columns>
<sdk:DataGridTemplateColumn Header="Operating System" Width="*" SortMemberPath="OSVersion">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Text="{Binding OS}" />
<TextBlock Text=" " />
<TextBlock Text="{Binding OSVersion}" />
</StackPanel>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
La propiedad Command está enlazada al comando AddIssue, que es del tipo ICommand. La clase AddIssue
implementa la interfaz ICommand, tal y como se muestra en el siguiente código.
private class AddIssueCommand : ICommand
{
...
#region ICommand Members
public bool CanExecute(object parameter)
{
return parameter != null && parameter is Issue && !dc.IsLoading && !dc.IsSubmitting;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
...
dc.Issues.Add(parameter as Issue);
(parameter as IEditableObject).EndEdit();
dc.SubmitChanges();
}
#endregion
}
Se usa el método CanExecute para comprobar si el comando AddIssue puede ejecutarse en este momento.
Mediante este método, se comprueba si hay alguna operación de carga o de envío en curso en el vínculo de
servicios RIA. El método Execute llama al método EndEdit del nuevo problema, agrega el problema a la tabla
Issues y envía los cambios pendientes al vínculo de los servicios RIA.
Para realizar cambios y actualizar un problema existente, haga clic en el botón Save (Guardar) que figura en
las páginas All Issues (Todos los problemas) y My Issues (Mis problemas). El botón Save está asociado a
una propiedad Command denominada SaveChanges, tal y como se muestra en el siguiente XAML.
<Button Content="Save" Command="{Binding SaveChanges, Source={StaticResource issueTrackerData}}"
CommandParameter="{Binding Data.CurrentItem, ElementName=issueDomainDataSource}" ...
La clase SaveChanges implementa la interfaz ICommand, tal y como se muestra en el siguiente código.
Se invoca el método CanExecute para comprobar si el comando SaveChanges puede ejecutarse en este
momento. Con este método, se comprueba si hay que guardar algún cambio y si hay alguna operación de
carga o de envío en curso en el vínculo de servicios RIA. El método Execute invoca el método EndEdit del
problema actual y envía los cambios pendientes al vínculo de servicios RIA.
Si la consulta anterior devuelve problemas, se genera una cadena de error, se agrega dicha cadena a una
lista de errores y se provoca el evento ErrorsChanged. Esto queda reflejado en el ejemplo de código
siguiente.
partial void OnTitleChanged()
{
...
var data = new IssueTrackerDomainContext();
Para que el control TextBox correspondiente al título controle este evento ErrorsChanged, se debe
establecer la propiedad NotifyOnValidationError en true, tal y como se muestra en el siguiente XAML.
<TextBox Text="{Binding Path=Title, Mode=TwoWay, NotifyOnValidationError=True}" ...
El método GetErrors devuelve una lista IEnumerable con los mensajes de error que existen para un campo
determinado. La propiedad HasErrors indica si hay algún error asociado a la clase Issue. En el ejemplo de
código siguiente, se muestra cómo la clase Issue implementa el método GetErrors y la propiedad HasErrors.
public System.Collections.IEnumerable GetErrors(string propertyName)
{
if (errors != null && errors.ContainsKey(propertyName))
return errors[propertyName];
return null;
}
public bool HasErrors
get
{
return (from errorList in errors.Values where (from e in errorList where !(e is string && ((string)e).StartsWith("Warning: "))
select e).Count() > 0 select errorList).Count() > 0;
}
}
Estos modelos de programación son distintos porque no se pueden utilizar al mismo tiempo dentro de una
instancia única del complemento Silverlight. Sin embargo, puede implementar una pantalla de presentación
que utilice la API de JavaScript y, a continuación, pasar a la API administrada cuando la aplicación se ha
cargado.
La API administrada proporciona significativamente más funcionalidad que la API de JavaScript y es el tema
tratado en la mayor parte de la documentación de Silverlight. Las aplicaciones que utilizan la API
administrada tienen acceso a una versión ligera de .NET Framework. La API de JavaScript, sin embargo, solo
tiene acceso al núcleo de presentación de Silverlight y al motor del explorador de JavaScript.
La API administrada
Puede utilizar el marcado XAML para encapsular los diseños de interfaz de usuario en la API administrada y
la API de JavaScript. Con la API administrada, sin embargo, puede factorizar el código de la aplicación en
varios archivos XAML y archivos de código subyacente.
Cuando el complemento Silverlight carga los archivos XAML, crea un árbol de objetos que el código
subyacente puede manipular. El código de la aplicación administrada también puede manipular el Modelo
de objetos de documento HTML (DOM) a través del puente HTML.
La API de JavaScript
La API de JavaScript es el modelo que estuvo disponible en Silverlight versión 1.0 y se mantiene para la
compatibilidad con versiones anteriores y para habilitar escenarios determinados.
En la API de JavaScript, el complemento Silverlight carga una página XAML única, en lugar de un paquete de
aplicación. Este XAML puede incluir referencias URI a recursos del servidor, como imágenes y vídeos. El
complemento Silverlight usa el XAML para crear un árbol de objetos que puede manipular mediante
programación utilizando JavaScript en la página HTML en que se hospeda.
La API de JavaScript no proporciona ningún modelo de aplicaciones capaz de admitir aplicaciones
complejas con navegación interna. Sin embargo, habilita escenarios para los que la API administrada es
demasiado prolija, como las pantallas de presentación. También puede implementar la navegación básica
cargando nuevas páginas de XAML en el complemento Silverlight o cargando las nuevas páginas web en el
explorador.
Estructura de aplicación
El sistema de activación de Silverlight permite especificar los ensamblados y archivos de recursos que se
deben incluir con la aplicación. El sistema de compilación incluye los archivos especificados en un paquete
de aplicación, que es un archivo zip comprimido con la extensión .xap.
Puede reducir el tamaño del paquete de la aplicación mediante el almacenamiento en caché de biblioteca
de aplicaciones. En este caso, los ensamblados configurados para el almacenamiento en caché se
comprimen en archivos zip independientes. Estos ensamblados se denominan ensamblados ExternalPart.
Este paquete incluye un archivo de manifiesto que identifica todos los ensamblados que la aplicación puede
utilizar. Se incluyen:
Los ensamblados del paquete de la aplicación.
Los ensamblados ExternalPart, que se descargan en el inicio y posteriormente se almacenan en
caché.
Los ensamblados que se podrían descargar después del inicio.
Como mínimo, el paquete de la aplicación debe incluir también el ensamblado con la clase de aplicación, de
la que el complemento Silverlight crea instancias. Cuando la aplicación se inicia, puede realizar tareas como
mostrar una interfaz de usuario o recuperar recursos adicionales.
El usuario debe decidir qué ensamblados y archivos de recursos va a implementar en el paquete de la
aplicación, como ensamblados ExternalPart, o cuáles se van a recuperar después del inicio. Uno de los flujos
de trabajo más comunes es incluir todo en el paquete de aplicación y, a continuación, medir los tiempos de
descarga e inicio cuando aumenta el tamaño de la aplicación. Cuando el retraso se incrementa de manera
significativa, se debe considerar la posibilidad de proporcionar una pantalla de presentación, mediante el
almacenamiento en caché de biblioteca de aplicaciones, y recuperar algunos archivos después del inicio.
Servicios de aplicación
La clase Application proporciona servicios en las categorías siguientes:
Eventos Startup y Exit de la aplicación.
Interacción con el complemento Silverlight y la página web del host.
Administración de recursos.
Control de excepciones centralizado.
Todas las aplicaciones basadas en Silverlight deben incluir una clase única derivada de Application.
Normalmente, la clase de aplicación agregará los recursos de aplicación basados en XAML y controlará el
evento Startup para proporcionar una interfaz de usuario. El complemento Silverlight muestra la interfaz de
usuario en su área de cliente tal y como se configura en la página web del host.
Se puede utilizar el evento Startup para inicializar la aplicación y su interfaz de usuario. Por ejemplo, se
puede especificar el estado inicial de la aplicación basándose en los parámetros de configuración del
complemento Silverlight, los parámetros de dirección URL o los valores de usuario recuperados del
almacenamiento aislado.
También se puede utilizar el evento Startup para iniciar la descarga asincrónica de ensamblados y archivos
de recursos adicionales. La clase Application proporciona un método auxiliar para extraer los recursos del
paquete de ensamblados o los archivos zip descargados.
Recursos
Silverlight admite los siguientes tipos de recursos:
Recursos XAML, como estilos y plantillas que varios elementos de la interfaz de usuario pueden
compartir.
Archivos de recursos, como imágenes y vídeos a los que se puede hacer referencia mediante un
identificador URI. Los archivos de recursos se pueden incrustar en los ensamblados, incluir por
separado en el paquete de aplicación o recuperar de la red.
Cadenas de recursos y otros valores incrustados en los ensamblados o proporcionados a través de
ensamblados satélite localizados.
En general, el término archivo de recursos puede hacer referencia a cualquier archivo que complemente el
ensamblado de la aplicación. Pueden ser archivos de datos o ensamblados de biblioteca que contienen
otros tipos de recursos, como cadenas localizadas o archivos XAML.
A algunos archivos de recursos, como las imágenes, se puede hacer referencia mediante un identificador
URI. Este identificador URI puede ser absoluto para recuperar archivos de cualquier ubicación de Internet o
puede ser relativo. Silverlight utiliza un mecanismo de reserva para los identificadores URI relativos de modo
que se puede cambiar la ubicación de implementación de algunos archivos sin tener que cambiar el código.
Algunos tipos de archivo, como archivos zip y ensamblados, se pueden recuperar únicamente desde el sitio
de origen mediante una operación de descarga asincrónica. Se puede utilizar la clase Application para
extraer los recursos de los archivos zip y la clase AssemblyPart para cargar los ensamblados.
Navegación
Silverlight proporciona varias opciones para navegar dentro de la aplicación o a recursos ajenos a la
aplicación.
Para la navegación dentro de la aplicación, se usan los controles Page y Frame. El marco actúa como
contenedor de controles de página, y facilita la navegación a las páginas. Cada página incluye contenido, y
se pueden agregar cuantas páginas sean necesarias para representar el contenido para el usuario. En
cualquier momento, el marco muestra el contenido de una sola página. Para la navegación a recursos
externos, se pueden proporcionar hipervínculos normales en la interfaz de usuario o se puede incluir la
navegación mediante programación a través del DOM HTML.
Pantallas de presentación
Silverlight proporciona compatibilidad con las pantallas de presentación de modo que se puede
personalizar la experiencia predeterminada durante la descarga y el inicio de las aplicaciones administradas.
La pantalla de presentación predeterminada muestra una simple animación giratoria después de un
pequeño retraso.
Si el paquete de aplicación requiere un tiempo de descarga e inicio significativo, quizás desee reemplazar la
pantalla de presentación predeterminada con otra en la que se muestra el progreso de la descarga. La
pantalla de presentación también se puede utilizar para describir la aplicación o proporcionar instrucciones,
créditos o avisos de exención de responsabilidad.
Las pantallas de presentación de Silverlight se implementan mediante la API de JavaScript. De este modo, el
complemento Silverlight puede mostrar inmediatamente la pantalla de presentación, incluso antes de que
se cargue el motor en tiempo de ejecución administrado de Silverlight. La pantalla de presentación se
puede cambiar mediante programación utilizando en la página web del host código JavaScript interpretado
por el explorador.
aplicación para identificar la clase de aplicación de la que se va a crear una instancia. Esta clase se conoce
como el punto de entrada de la aplicación y debe derivarse de la clase Application.
Si se usa el almacenamiento en caché de biblioteca de aplicaciones, el manifiesto también indica qué
ensamblados necesarios son externos al paquete de la aplicación. El complemento recuperará todos esos
archivos. En el caso de las aplicaciones adaptadas, el complemento recuperará también los ensamblados
satélite específicos de la referencia cultural para todos los ensamblados internos y externos necesarios. La
clase Application proporciona un evento Startup que se puede controlar para inicializar la aplicación y su
interfaz de usuario. La clase Application también proporciona otros servicios de aplicación que normalmente
son necesarios. Por ejemplo, se puede utilizar esta clase para extraer los archivos de recursos del paquete de
aplicación o de archivos zip descargados.
El proceso a través del cual se descargan los archivos de inicio de la aplicación y se crea una instancia de la
clase de aplicación se conoce como sistema de activación de Silverlight. El sistema de activación permite
especificar una descarga inicial mínima de uno o más paquetes para optimizar el almacenamiento en caché.
Después de la activación, la aplicación puede recuperar a petición otros ensamblados de biblioteca y
archivos de recursos adicionales.
En este tema se describe la estructura del paquete de aplicación. También explica las opciones para
implementar los archivos en el paquete de aplicación, como elementos necesarios pero externos, o como
archivos a petición.
Paquete de aplicación
Un paquete de aplicación contiene los archivos siguientes:
Un archivo AppManifest.xaml, que identifica los ensamblados empaquetados y el punto de entrada
de la aplicación.
Un ensamblado de aplicación, que incluye la clase de aplicación.
Cero o más ensamblados de biblioteca.
Cero o más archivos de recursos separados, como imágenes o archivos de vídeo.
El archivo AppManifest.xaml lo suele generar el proceso de compilación y utiliza marcado XAML para
declarar un objeto Deployment para la aplicación.
En el archivo AppManifest.xaml, el elemento Deployment incluye los atributos siguientes:
Un atributo RuntimeVersion para identificar la versión requerida de Silverlight.
Los atributos EntryPointAssembly y EntryPointType para identificar el punto de entrada de la
aplicación.
El elemento Deployment también incluye un elemento secundario de la propiedad Deployment.Parts que
tiene un elemento AssemblyPart secundario para cada ensamblado incluido en el paquete de aplicación.
Si se usa el almacenamiento en caché de biblioteca de aplicaciones, el elemento Deployment también
podría incluir un elemento de propiedad Deployment.ExternalParts secundario. Este elemento está presente
si se han agregado referencias a ensamblados de biblioteca configurados para el uso con el
almacenamiento en caché de biblioteca de aplicaciones. El elemento de propiedad
Deployment.ExternalParts tiene un elemento ExtensionPart secundario para cada paquete de biblioteca
externo.
El paquete de aplicación debe incluir un archivo AppManifest.xaml y un ensamblado de aplicación de punto
de entrada. Todos los demás componentes de la aplicación se pueden implementar como archivos
empaquetados, archivos ExternalPart o archivos a petición.
Los archivos empaquetados son archivos que se incluyen en el paquete de aplicación. Normalmente, se
incluyen los archivos principales que la aplicación requiere al iniciarse o que deben estar disponibles de
inmediato para evitar retrasos después del inicio. También se pueden incluir los recursos compartidos, como
imágenes, que se pueden incrustar en ensamblados o proporcionar como archivos independientes en el
paquete de aplicación.
Los archivos ExternalPart son archivos zip que contienen uno o más ensamblados necesarios en el inicio de
la aplicación. Normalmente son ensamblados de biblioteca que tienen menos probabilidades de cambiar
que los archivos principales de la aplicación. Es posible mejorar la eficacia del almacenamiento en caché en
los equipos de los usuarios si estos archivos se factorizan en descargas independientes.
Los archivos a petición son los archivos que se implementan en un servidor, normalmente en la misma
ubicación que el paquete de aplicación. La aplicación puede recuperar estos archivos después de la
activación. Según el tipo y el tamaño de los archivos, hay varias opciones para recuperar los archivos a
petición. Por ejemplo, se pueden utilizar referencias de URI directas para recuperar archivos de imagen, o
bien, se pueden iniciar descargas asincrónicas para recuperar ensamblados de biblioteca o archivos zip. Para
obtener más información, consulte la sección siguiente.
En el diagrama siguiente se resumen la estructura del paquete de aplicación y las opciones de
implementación de los archivos de aplicación.
que se puede mover cualquier archivo al que se haga referencia mediante un identificador URI relativo sin
tener que cambiar el código.
Muchos tipos de archivo no admiten el uso de un identificador URI para hacer referencia a ellos y requieren
un procesamiento especial si se opta por volver a implementarlos como archivos a petición. Por ejemplo, si
se vuelve a implementar un ensamblado de biblioteca, se debe agregar código que lo recupere a petición y
lo cargue en el dominio de aplicación. En este caso, aunque todavía se debe hacer referencia al ensamblado
en el proyecto de aplicación, el valor Copia local se establece en Falso. De esta forma, se evita que en la
compilación se agregue el ensamblado al paquete de aplicación o que se solicite en el inicio como un
ensamblado ExternalPart.
También se puede optar por sacar del paquete de aplicación varios archivos de recursos relacionados para
recuperarlos a petición como una sola descarga. Para ello, es preciso agruparlos en un archivo zip, que se
implementa en el servidor. A continuación, se debe agregar código que recupere el archivo zip a petición y
extraiga su contenido.
Nota:
No se puede usar el almacenamiento en caché de biblioteca de aplicaciones y la compatibilidad
con la ejecución fuera del explorador en la misma aplicación. Las aplicaciones de ejecución fuera
del explorador requieren que todos los ensamblados de inicio residan en el paquete de la
aplicación.
Los elementos name, publickeytoken y version deben coincidir con los metadatos correspondientes
del ensamblado. El elemento relpath indica el nombre de archivo del ensamblado. Por último, el
elemento extension indica el nombre del elemento externo empaquetado a través del atributo
downloadUri.
El valor de atributo downloadUri se usa para rellenar la propiedad ExtensionPart.Source del
manifiesto de aplicación, como se muestra en el fragmento de manifiesto siguiente.
<Deployment.ExternalParts>
<ExtensionPart Source="System.Json.zip" />
</Deployment.ExternalParts>
En el código de ejemplo siguiente se muestra cómo recuperar un ensamblado del servidor del host a
petición y, a continuación, cargarlo en el dominio de aplicación.
En este ejemplo se utiliza la clase WebClient para iniciar una descarga asincrónica del ensamblado en
respuesta a un clic del mouse del usuario. Cuando se completa la descarga, se utiliza la clase AssemblyPart
para cargar el ensamblado.
En este ejemplo se supone que se agregó una referencia al ensamblado en el proyecto de aplicación. El
ensamblado debe tener también en Copia local el valor False para que no se implemente en el paquete de
la aplicación.
Puede emplear esta técnica para cargar ensamblados a los que no se hace referencia en su proyecto de
aplicación. En este caso, sin embargo, debe usar la reflexión para crear instancias de los tipos a partir del
ensamblado cargado.
Ejemplo
En el ejemplo siguiente se carga un ensamblado denominado SilverlightLibrary.dll cuando el usuario hace
clic en un bloque de texto. En este ejemplo se usa un URI relativo para cargar el ensamblado desde la
misma ubicación que el archivo XAP de la aplicación.
<UserControl x:Class="SilverlightApplication.HomePage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid Background="SandyBrown">
<StackPanel x:Name="stackPanel">
<TextBlock>Page from Host Application</TextBlock>
<TextBlock
MouseLeftButtonUp="TextBlock_MouseLeftButtonUp"
Cursor="Hand">
Click Here to Display a UI from the Library Assembly
</TextBlock>
</StackPanel>
</Grid>
</UserControl>
Imports SilverlightLibrary
La API de Silverlight define su conjunto de objetos como árboles de objetos que permiten rellenar el
contenido inicial de una aplicación basada en Silverlight mediante la carga de XAML y el ajuste del árbol de
objetos en tiempo de ejecución. En la API administrada, la interacción con el árbol de objetos de Silverlight
se define con código administrado. Mediante el CLR, el código administrado se compila para convertirlo en
un ensamblado. El ensamblado suele contener, además, el marcado XAML para la aplicación basada en
Silverlight. El código administrado puede admitir el modelo de aplicaciones de Silverlight, y se le puede
llamar en respuesta a eventos de duración de objetos o de eventos iniciados por el usuario. También puede
utilizar el código administrado para escribir clases de soporte, para definir objetos de datos y para muchos
otros escenarios de aplicación. También puede utilizar DLR en lugar del CLR, lo que se explica en Lenguajes
dinámicos en Silverlight.
explorador y, potencialmente, podría existir en el mismo ámbito. En la API administrada, existe una
separación más formal, el código administrado lo utilizan las bibliotecas básicas de Silverlight y su CLR, no el
explorador. Para interactuar con el DOM de la API administrada, puede utilizar una serie de características
que se denominan en ocasiones colectivamente Puente HTML, o puente del DOM HTML. Algunas de estas
formas son:
Interfaces API que exponen al código administrado las partes utilizadas con frecuencia del DOM
(por ejemplo, el objeto Document).
Medios que pueden hacer que los tipos administrados admitan script desde el DOM.
Técnicas de conversión para la generación de tipos administrados desde objetos o valores de
JavaScript cuyas referencias se calculan.
Interfaces API que específicamente expongan la representación de objetos del complemento
Silverlight en el DOM.
Requisitos previos
En este tema se supone que el usuario ha leído Información general sobre XAML y Arquitectura de
Silverlight.
Arboles de objetos
Un árbol de objetos es una conceptualización del modo en que se relacionan entre sí los objetos que se
crean y existen en el contenido de Silverlight en tiempo de ejecución. Las relaciones se basan en el principio
de que los objetos tienen propiedades y, muchas veces, el valor de la propiedad es otro objeto que a su vez
también tiene propiedades. El árbol de objetos tiene bifurcaciones porque algunas de estas propiedades
son propiedades de colección y contienen más de un objeto; también tiene una raíz porque la arquitectura
debe hacer referencia en última instancia a un único objeto que es el punto de conexión de los conceptos
que se encuentran fuera del árbol de objetos (como el host del explorador o el complemento Silverlight que
muestra el contenido).
Aunque realmente hay un único árbol de objetos desde el punto de vista conceptual, la API de Silverlight no
expone al usuario el árbol completo. Gran parte de la estructura del árbol de objetos son realmente detalles
de implementación. En lugar de ello, el usuario dispone de propiedades específicas de objetos que influyen
en los valores secundarios de puntos determinados del árbol y que pueden informar acerca del elemento
primario (en la mayoría de los casos, el eje primario es de solo lectura porque los árboles suelen generarse
de la raíz hacia arriba, ya sea en código o a través del proceso de análisis de XAML). Por ejemplo, un Panel
tiene una propiedad Children que establece los objetos secundarios. FrameworkElement tiene Parent para
notificar el elemento primario. Estas dos API se encuentran en clases base, de modo que están disponibles
en un gran número de objetos de Silverlight.
En Silverlight, un concepto de árbol relacionado es el árbol visual. El árbol visual puede conceptualizarse
como una representación editada o filtrada del árbol de objetos más grande. El filtro que se aplica es que
solo los objetos que tienen una implicación de representación estén presentes en el árbol visual. Por
ejemplo, una clase de una colección no formaría parte del árbol visual sino que, en lugar de ello, el árbol
visual abstrae las colecciones en un concepto de "elementos secundarios". Sin embargo, el árbol visual
también puede incluir objetos que no son inmediatamente visibles si se considera que el marcado XAML de
origen cargado es una aproximación del árbol de objetos. Esto se debe a que el árbol visual también
notifica objetos que son partes compuestas de controles que proceden de una plantilla de control aplicada
o de diccionarios de recursos. El árbol visual se usa internamente para el proceso de representación de
Silverlight, pero tener conocimientos sobre el árbol visual suele ser importante en determinados escenarios,
como a la hora de escribir o reemplazar una plantilla de control o en el análisis de una instancia del control
en tiempo de ejecución, una vez aplicada la plantilla. Para estos escenarios, Silverlight proporciona la API
VisualTreeHelper, que permite examinar el árbol visual de un modo más generalizado de lo que podría
hacerse con las propiedades del elemento primario y de los elementos secundarios específicos del objeto.
El concepto de árbol visual también existe en WPF y, en Silverlight, el concepto de árbol visual es similar.
Una diferencia notable, sin embargo, es que WPF también proporciona una concepción o filtro adicional del
árbol de objetos, que recibe el nombre de árbol lógico. El concepto de árbol lógico es relevante para
determinados comportamientos del sistema de propiedades. Silverlight no expone este árbol lógico a través
de una clase auxiliar. En Silverlight, existen algunos de los comportamientos relevantes de las propiedades
(aunque no todos), pero sin una API auxiliar para obtener acceso a ellos, el concepto de árbol lógico no
resulta útil en Silverlight y, por lo tanto, no se describe en la documentación. Una implicación de
compatibilidad secundaria derivada de la omisión del árbol lógico es que el comportamiento de la
propiedad FrameworkElement.Parent es diferente en Silverlight versión 4 y, realmente, esta notificando el
árbol visual primario.
plantilla suelen usar un TemplateBinding, que permite aplicar la plantilla y establecer valores concretos que
se incluyen en el objeto de plantilla.
Precaución:
En general, Silverlight admite el concepto de cambio de aspecto visual o, de otro modo, redefinición del
estilo o de la plantilla de un control. Concretamente, si es autor de un control y está escribiendo el código
de soporte del control, puede ser peligroso suponer una estructura de árbol determinada. Puesto que la
mayoría de los controles admiten una plantilla que puede establecerse (independientemente de que haya
habilitado puntos de extensión más concretos, como estilos de subpartes), el árbol visual en tiempo de
ejecución podría ser diferente de lo que sería si lo crease con la plantilla predeterminada aplicada.
Usar VisualTreeHelper
VisualTreeHelper es una clase de utilidad que puede resultar útil para recorrer el árbol de objetos. El
concepto de árbol visual se explicó anteriormente en la sección "Árboles de objetos" de este tema.
Dado que puede actuar sobre el árbol visual en tiempo de ejecución y recorrer las partes de plantilla, esta
puede ser una técnica útil para examinar la composición de la plantilla. Si lo desea, puede examinar una
colección de elementos secundarios que podría rellenarse mediante un enlace de datos o donde el código
de la aplicación no conozca totalmente la naturaleza global del árbol de objetos en tiempo de ejecución .
Para hacer esto, tendría que recorrer el árbol a través de GetChild, utilizando GetChildrenCount como
determinante de si el nodo de árbol es un elemento único o una colección de "elementos secundarios" que
debe recorrer en iteración por recuento.
API de JavaScript
Para obtener más información sobre los árboles de objetos utilizando la API de JavaScript, vea API de
JavaScript para Silverlight.
Requisitos generales
Si se compila por marcado una página XAML de una aplicación administrada (acción de
compilación Página, con MSBuild:MarkupCompilePass1 como valor de Herramienta
personalizada), el elemento raíz de la página debe declarar un atributo x:Class. Como reserva,
puede haber únicamente el archivo de código subyacente (un archivo DependentUpon con la
acción de compilación Compilar); vea la nota en la siguiente sección.
Nota:
Si bien no se recomienda, se puede dejar en blanco la derivación en la definición de clase parcial
del código subyacente si el marcado declaró x:Class. Esto se puede hacer únicamente si la página
no tiene controladores de eventos ni ninguna otra lógica basada en código. El resultado compilado
supondrá que la raíz de la página es la clase base de la clase parcial aunque no se especifique
(porque la parte correspondiente al marcado de la clase parcial sí especifica implícitamente la clase
base a través de su etiqueta de elemento raíz).
La clase parcial debe ser pública. Este requisito se debe a que la clase parcial definida a través del
marcado x:Class es pública cuando se compila por marcado, por lo que la clase parcial del código
debe usar el mismo acceso para que se una a la clase parcial del marcado.
Se puede optar por omitir un espacio de nombres, siempre y cuando esto se corresponda con la
forma en que se declaró x:Class.
Los controladores de eventos que se escriban deben ser métodos de instancia definidos por la
clase parcial dentro del espacio de nombres identificado por x:Class. No se puede calificar el
nombre de un controlador de eventos para indicar a un procesador XAML que lo busque en otro
ámbito de clase. Tampoco se puede utilizar un método estático como controlador de eventos.
Los controladores de eventos no necesitan ser públicos; pueden ser privados o internos.
Generalmente, se recomienda escribir controladores de eventos no públicos.
El controlador de eventos debe coincidir con el delegado del evento apropiado. Observe que
algunos eventos utilizan controladores genéricos con datos de evento restringidos. En estos casos,
utilice la restricción de los datos de evento que se indique en la firma de evento.
Los controladores de eventos se pueden compartir para el mismo evento en diferentes objetos. Si
el delegado lo permite, también se puede compartir el mismo controlador para diferentes tipos de
evento. Sin embargo, en este caso, la lógica del controlador de eventos debe utilizar los valores de
sender y/o de OriginalSource para distinguir los orígenes de los eventos.
En el caso concreto del lenguaje Visual Basic, se puede utilizar la palabra clave Handles específica
del lenguaje para asociar los controladores a instancias y eventos en la declaración del controlador,
en lugar de adjuntarlos a los atributos en XAML. Sin embargo, esta técnica tiene algunas
limitaciones porque Handles no admite todas las características específicas del sistema de eventos,
como algunos escenarios de eventos enrutados.
DOM Descripción
Gecko DOM (Mozilla, Firefox, versión 6 y Gecko es el componente de software que controla el análisis de
posteriores de Netscape y otros HTML, el diseño de páginas, el modelo de objetos de documento y
exploradores basados en Mozilla) la representación de la aplicación completa.
El DOM de HTML dinámico (DHTML) ofrece a los autores acceso
directo y programable a los componentes individuales de sus
DHTML DOM (Internet Explorer)
documentos web, desde elementos individuales hasta
contenedores.
Después de crear el complemento Silverlight (normalmente con una etiqueta HTML object, puede recuperar
una referencia a la instancia del complemento en el DOM HTML haciendo referencia a su identificador (ID).
En el ejemplo de JavaScript siguiente se muestra cómo recuperar los identificadores (ID) del complemento
Silverlight utilizando el método document.getElementById.
var plugin_1 = document.getElementById("SLPlugin_1");
En el caso de la API administrada, antes de que se analice el XAML, un compilador de marcado lo compila
en el equipo del programador.
Cuando el XAML se carga y se analiza en tiempo de ejecución en el cliente, el analizador crea un árbol de
objetos a partir del marcado. El árbol de objetos tendrá un objeto UserControl como raíz. De hecho, incluirá
una instancia de una subclase UserControl concreta: la clase Page a la que se hace referencia en el atributo
x:Class del elemento raíz.
Al interactuar con la aplicación basada en Silverlight en tiempo de ejecución, se usa la API administrada de
Silverlight para obtener acceso a la clase Page. También es posible extenderse más allá de la raíz Page del
árbol de objetos inmediato y obtener acceso al objeto Application. Application proporciona acceso a los
distintos aspectos de una aplicación basada en Silverlight que se desea conservar incluso aunque se
reemplace toda la página metafórica de la interfaz de usuario que se muestra en el área de contenido de
Silverlight. Application incluye recursos de nivel de aplicación, acceso al paquete que contiene los
componentes de la aplicación y objetos que se conectan al DOM HTML.
XAML dinámico
Para algunos escenarios de API administradas, se puede cargar XAML dinámico, es decir, un archivo XAML
que se incluye como contenido en un paquete de Silverlight XAP o bien al que se obtiene acceso mediante
una dirección URL. Este XAML no puede declarar x:Class ni utilizar código subyacente. Ejemplos de
escenarios de esta situación son los diccionarios de recursos combinados, los recursos específicos del
usuario o las cadenas de contenido de Load. La relación de este XAML dinámico con el resto del árbol de
objetos depende del escenario exacto y no se describe aquí.
API de JavaScript
En el ejemplo siguiente se crea una jerarquía de marcado que contiene el objeto raíz Canvas. Este ejemplo
está específicamente diseñado para la API de JavaScript y representa un archivo XAML individual
proporcionado por el mismo servidor que la página HTML donde se hospeda Silverlight. En este caso, el
archivo XAML no se empaqueta ni se compila con un compilador de marcado.
<StackPanel
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<Rectangle
Width="200" Height="35"
Fill="PowderBlue" />
<TextBlock
Foreground="Teal" FontFamily="Verdana" FontSize="18"
FontWeight="Bold"
Text="Sample Output" />
</StackPanel>
Este XAML también define una interfaz de usuario básica. De hecho, es visualmente idéntico al ejemplo
anterior. Cuando se analiza este XAML, el analizador crea un árbol de objetos a partir del marcado. Este
árbol de objetos tendrá StackPanel como elemento raíz.
Al interactuar con la aplicación basada en Silverlight en tiempo de ejecución, no se obtiene acceso
inmediato al árbol de objetos completo. Se tiene acceso a la variable que podría haberse creado para hacer
referencia al complemento de Silverlight en el DOM pero, de lo contrario, el acceso al modelo de
programación suele realizarse a través del sender de un controlador de eventos. Este sender es un objeto
que está incluido dentro del árbol de objetos y que es accesible para cualquier API de Silverlight. Pero
sender no suele ser accesible para el DOM HTML; el DOM se detiene en el nivel de la etiqueta object del
host.
La API de JavaScript usa cualquier referencia Name / x:Name en tiempo de ejecución, pero su único uso
inicial es actuar como destinos de las llamadas a FindName. Solo después de haber llamado a FindName
tendrá un objeto real en el árbol de objetos; antes, el nombre de un objeto es simplemente una cadena, y
no un objeto. Por convención, suele usarse un nombre de variable idéntico a la cadena utilizada para Name
y esta convención le resultará de gran utilidad si alguna vez tiene que migrar código subyacente de
JavaScript a código subyacente administrado utilizando el mismo XAML.
Silverlight no tiene que hospedarse necesariamente en un explorador. También es posible implementar una
aplicación basada en Silverlight fuera del explorador, o escribir un marco de host alternativo. En estos casos,
puede que no esté disponible el DOM completo y ni sus posibilidades de scripting.
Requisitos previos
Debe leer el tema Modelos de aplicaciónes y programación y entender las diferencias básicas entre la API
administrada y la API de JavaScript. También debe conocer el DOM HTML y saber cómo los modelos de
programación y el árbol de objetos de Silverlight se relacionan con el DOM del explorador.
presentación sin activar el CRL y los ensamblados relacionados de Silverlight, con lo que se acorta el tiempo
de inicio.
Contenido y mantenimiento de aplicaciones de la época de Silverlight 1.0
El complemento Silverlight 2 admite un modo de compatibilidad para aplicaciones escritas en la época de
Silverlight 1.0. En particular, el complemento se puede inicializar tomando como base la cadena de era de
Silverlight 1.0 para la application pasada al elemento object, una versión de "1.0" pasada a Silverlight.js para
su inicialización, o ambas cosas. En general, los sitios que se escribieron originalmente para Silverlight 1.0
deberían continuar funcionando en clientes que dispongan del complemento Silverlight 2.
Nota:
Si utiliza Silverlight.js para la inicialización, debe considerar la posibilidad de actualizar el archivo
Silverlight.js utilizado en la implementación original, porque puede haber habido actualizaciones de la
lógica de script que se encarga de las cadenas de agente para distintos exploradores y otros cambios
técnicos producidos desde la versión Silverlight 1.0.
Silverlight 2 sigue siendo compatible con la API de JavaScript proporcionando a JavaScript el acceso al árbol
de objetos y admitiendo un valor Source que especifique una única página XAML. Si tiene una aplicación de
la época de Silverlight 1.0 y simplemente agrega algunas mejoras o características concretas, el proceso de
toma de decisiones comerciales y técnicas podría determinar que lo mejor es introducir las nuevas
características en la base de código existente y continuar utilizando la API de JavaScript.
Nivel de experiencia del programador
Si tiene amplia experiencia con JavaScript, la mejor manera de sacar partido a sus conocimientos sería
continuar usando la API de JavaScript. Sin embargo, muchas características que se encuentran en
Silverlight 2 requieren la API administrada y no están disponibles para JavaScript.
Otras consideraciones
Si el uso que realiza del contenido de Silverlight en una página HTML mayor tiene requisitos relativamente
mínimos o si utiliza ampliamente DOM HTML para integrar muchas áreas de contenido HTML diferentes y
otros complementos o controles en una sola página, el proceso de toma de decisiones podría determinar
que la API de JavaScript proporciona la solución de integración más rentable.
crear estos objetos creando instancias de XAML y, seguidamente, script para el árbol de objetos. Para
utilizar estos objetos, el cliente que ejecuta la aplicación basada en Silverlight también debe ser un cliente
de Silverlight versión 2.
Los objetos adicionales para la API de JavaScript se incluyen en la API de JavaScript para la documentación
de Silverlight (así como las propiedades, los métodos, los eventos y las enumeraciones). Estos se
documentan en un nivel básico. Los nuevos objetos y miembros llevan anotada una sección de información
de versión en las páginas de referencia, mientras que los objetos y los miembros existentes en la versión 1.0
no tienen una sección de información de versión.
En XAML, la API que se usa (administrada o de JavaScript) afecta a la técnica de especificación de los
controladores de eventos. La API es mutuamente excluyente en un nivel de página XAML. La señal por la
que se usa la API es la presencia o ausencia del atributo x:Class en el elemento raíz de una página XAML. Si
existe x:Class, la página usa la API administrada. Si x:Class no está presente, la página usa la API de
JavaScript.
En el ejemplo de XAML siguiente se muestra cómo agregar un controlador para el evento Loaded para
Canvas, que en este ejemplo es la raíz de un archivo de XAML. La ausencia de x:Class en esta raíz indica el
uso de la API de JavaScript. La resolución del nombre de función se aplaza por tanto al tiempo de ejecución.
En tiempo de ejecución, cuando se produce el evento, se comprueba el ámbito de scripting de JavaScript en
busca de un miembro denominado "onLoaded" y se ejecuta dicha función.
<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Loaded="onLoaded" />
La función denominada onLoaded se define en un archivo de JavaScript. Este archivo de JavaScript está
asociado al HTML de la página de hospedaje a través del parámetro src de la etiqueta <SCRIPT> del HTML.
Esto es necesario porque se trata del host del explorador que realmente está interpretando el script; el
complemento Silverlight es solamente un intermediario en el procesamiento de la API de JavaScript y no
proporciona el motor de scripts real. No hay nada en el XAML que deba hacer referencia a un archivo de
JavaScript concreto; solo es pertinente en el explorador y en el DOM.
<!-- Reference the JavaScript file where the event functions are defined
from the plug-in host HTML page. -->
<script type="text/javascript" src="eventfunctions.js">
...
</script>
fragmento XAML que se crea está desconectado del árbol de objetos de Silverlight. Esto significa que el
fragmento todavía no se representa. Sin embargo, incluso antes de agregarlo al árbol de objetos, puede
modificar las propiedades de los objetos en el fragmento XAML. Los métodos de los objetos no se pueden
invocar antes de conectar el árbol.
Después de haber creado un conjunto de objetos desconectado del fragmento XAML, por lo general suele
ser conveniente agregarlo al árbol de objetos de Silverlight activo. El fragmento se puede agregar como un
objeto secundario a un objeto primario, o bien puede establecer un valor de la propiedad de un objeto.
Cuando el fragmento forma parte del árbol de objetos de Silverlight, se representan los objetos del
fragmento XAML. Dependiendo de la extensión del código XAML proporcionado como información para
CreateFromXaml, puede crear un objeto Silverlight único, como TextBlock, o bien un árbol complejo de
objetos de Silverlight.
Hay varios requisitos para agregar dinámicamente contenido de XAML al árbol de objetos de Silverlight:
Debe haber contenido XAML existente asociado al complemento Silverlight. No se puede utilizar
CreateFromXaml para reemplazar el árbol de contenido completo; debe conservar el elemento raíz
original por lo menos. Si desea reemplazar todo el árbol, puede establecer Source, pero tenga en
cuenta que Source requiere que exista un archivo real en un URI y este no se puede inicializar
simplemente con una cadena. Sin embargo, puede solucionar este problema utilizando código
XAML insertado como Source y empleando el DOM HTML para aplicar el método document.write
al contenido del bloque SCRIPT que contiene el código XAML de origen deseado.
El método CreateFromXaml solamente se puede invocar a través del complemento Silverlight. Sin
embargo, en la API de JavaScript resulta sencillo obtener una referencia de objeto al complemento:
basta con llamar a GetHost para cualquier objeto de Silverlight.
El contenido de XAML que se crea con el método CreateFromXaml solamente puede estar asignado
a un objeto. Si desea agregar objetos creados a partir de código XAML idéntico a áreas diferentes
de la aplicación, debe invocar CreateFromXaml varias veces y utilizar variables diferentes para el
valor devuelto. (Si lo hace, tenga cuidado con los conflictos de nombres; vea la sección Crear
ámbitos de nombres con CreateFromXAML más adelante en este mismo tema).
El objeto de Silverlight que incluirá el nuevo contenido de XAML debe ser capaz de encapsular un
objeto, como un elemento secundario o como un valor de propiedad.
La cadena que especifique para xamlContent de CreateFromXaml debe especificar código XML con
el formato correcto (en concreto, debe tener un único elemento raíz). CreateFromXaml producirá
un error si la cadena XML proporcionada no tiene el formato correcto.
El elemento raíz utiliza implícitamente el espacio de nombres XML de Silverlight. Puede establecer
el espacio de nombres de Silverlight explícitamente, pero no establezca el espacio de nombres XML
predeterminado en ningún otro valor distinto del espacio de nombres de Silverlight.
que se usa para crear un árbol de objetos desconectado creará igualmente un ámbito de nombres XAML
preliminar que evalúa todos los nombres definidos en el código XAML proporcionado para comprobar que
son únicos. Si los nombres del código XAML proporcionado no son únicos internamente en este punto,
CreateFromXaml produce un error. La diferencia en el comportamiento es que el árbol de objetos
desconectado ahora está marcado para evitar que se combine su ámbito de nombres XAML con el ámbito
de nombres XAML primario cuando se conecte al árbol de objetos de la aplicación principal. De hecho,
después de conectar los árboles, la aplicación tendrá un árbol de objetos unificado pero ámbitos de
nombres XAML discretos. Un nombre definido en la raíz de CreateFromXaml o en cualquier objeto del árbol
previamente desconectado no se asocia al ámbito de nombres XAML primario; tiene su propio ámbito de
nombres XAML discreto.
La complicación de tener ámbitos de nombres XAML discretos es que las llamadas al método FindName ya
no funcionan con un ámbito de nombres unificado. En lugar de ello, el objeto en concreto en el que se
llama a FindName definirá implícitamente el ámbito, y el ámbito será el ámbito de nombres XAML donde
reside el objeto que realiza la llamada. Por tanto, si intenta llamar a FindName para obtener un objeto con
nombre en el ámbito de nombres XAML primario, no se encontrarán los objetos de un ámbito de nombres
XAML discreto creado por CreateFromXaml. A la inversa, al llamar a FindName desde el ámbito de nombres
XAML discreto no se encontrarán los objetos con nombre del ámbito de nombres XAML primario. El
método FindName definido en el objeto de complemento Silverlight no evita totalmente este problema; su
ámbito de nombres XAML siempre es el ámbito de nombres XAML primario.
Este problema de ámbitos de nombres XAML discretos solamente afecta a los ámbitos de nombres XAML y
a la llamada a FindName. Todavía puede recorrer la estructura del árbol de objetos de forma ascendente en
algunos casos llamando al método GetParent o de forma descendente realizando llamadas en las
propiedades o propiedades de colección pertinentes (como la colección devuelta por Canvas.Children).
Para llegar a los objetos que se definen en un ámbito de nombres XAML discreto, puede emplear varias
técnicas:
Recorrer el árbol de objetos con GetParent y/o propiedades de colección.
Si va a realizar la llamada desde un ámbito de nombres XAML discreto y desea obtener el ámbito
de nombres XAML primario, le resultará sencillo obtener una referencia al complemento Silverlight
y, a continuación, llamar a FindName en esta referencia. La llamada de script concatenada para
realizar esta operación se incluye en una única línea:
returnedObject = objeto .GetHost().content.FindName("nameToFind");
donde objeto es el objeto que realiza la llamada en un ámbito de nombres XAML discreto. .content
en esta sintaxis es el paso a través del subobjeto de complemento Silverlight específico que define
el método FindName.
Si va a realizar la llamada desde el ámbito de nombres XAML primario y desea obtener un objeto
dentro de un ámbito de nombres XAML discreto, debe planear con antelación esta operación en el
código y conservar una referencia al objeto devuelto por CreateFromXaml. Este objeto es ahora un
objeto válido para llamar a FindName dentro del ámbito de nombres XAML discreto. Puede
mantener este objeto como una variable global o pasarlo de algún otro modo mediante
parámetros de método.
Nota importante:
El código XAML insertado es un concepto que solo es utilizable con la API de JavaScript para Silverlight. El
código XAML insertado no es compatible con la API administrada para Silverlight.
administrado, que especifique x:Class en su raíz, no hay modo de que una solución de XAML insertado sepa
cómo conectar el código subyacente y el XAML, y ninguna instrucción concreta para compilar y conectar el
código administrado.
Para utilizar XAML insertado, debe agregar el XAML en un bloque < SCRIPT > especial y especificar
"text/xaml" como atributo type. La declaración de tipos del documento XML, <?xml version="1.0"?>,
precede el contenido XAML. Se debe identificar el contenido XAML de forma única para que el parámetro
de inicialización de Source del complemento Silverlight pueda hacer referencia a él. El parámetro source
utiliza el prefijo "#" seguido por el valor id en el elemento < SCRIPT > para identificar el contenido XAML. El
contenido XAML también puede definir eventos que hacen referencia a controladores de eventos en la
página HTML.
En el siguiente ejemplo HTML se muestra cómo crear contenido de código XAML insertado. En este caso, la
página HTML incluye JavaScript y contenido XAML. Tenga en cuenta la construcción del elemento object
que especifica el parámetro source.
Nota:
El elemento < SCRIPT > que incluye el contenido XAML insertado debe preceder al elemento HTML que
contiene el complemento Silverlight, que hace referencia al XAML insertado para la inicialización del origen.
<html>
<head>
<title>Display Date</title>
<!-- Define Loaded event handler for TextBlock. -->
<script type="text/javascript">
function setDate(sender, eventArgs)
{
sender.text = Date();
}
</script>
</head>
<body bgcolor="Teal">
<!-- Define XAML content. -->
<script type="text/xaml" id="xamlContent"><?xml version="1.0"?>
<Canvas
xmlns="http://schemas.microsoft.com/client/2007"
Background="Wheat">
<TextBlock
Canvas.Left="20"
FontSize="24"
Loaded="setDate" />
</Canvas>
</script>
<div id="silverlightControlHost">
<object type="application/x-silverlight" width="100%" height="100%" id="slc">
<param name="source" value="#xamlContent"/>
<param name="onload" value="onLoaded" />
<param name="iswindowless" value="true" />
</object>
<iframe style='visibility:hidden;height:0;width:0;border:0px'></iframe>
</div>
</body>
</html>
Cuando se muestra esta página, se carga el complemento Silverlight y se genera el evento Loaded para el
objeto TextBlock, que hace que TextBlock muestre la fecha y la hora.
propiedades y propiedades adjuntas para la API de JavaScript, y el uso de los métodos de utilidad
GetValue/SetValue.
GetValue y SetValue
Las propiedades del modelo de objetos de Silverlight se exponen a JavaScript a través de una notación
objeto.propiedad similar a muchos otros modelos de programación en explorador. Dado que se basa en
prototipos, también es posible establecer valores de propiedad no incluidos en la API en cualquier objeto
de JavaScript y obtener ese valor posteriormente.
La API de JavaScript para Silverlight también proporciona dos métodos de descriptor de acceso, GetValue y
SetValue, que obtienen y establecen las propiedades pasando el nombre de propiedad relevante como una
cadena. Estos métodos realmente proporcionan una implementación de "contenedor" intermedia que
procesa JavaScript en objetos nativos para Silverlight, pero se exponen como parte de la API del usuario
general porque, en ocasiones, resultan útiles para ciertos escenarios. Se proporcionan ejemplos de uso en
las páginas de referencia de GetValue y SetValue, en caso de que se encuentre ante un escenario de este
tipo. Dicho esto, en general no necesitará crear instancias para usar los métodos GetValue / SetValue. La
notación objeto.propiedad para obtener y establecer propiedades es equivalente y suele ser más intuitiva.
Nota:
Si está familiarizado con WPF o con la API administrada para Silverlight, es probable que conozca los
métodos SetValue y GetValue que forman parte del sistema de propiedades. Estos métodos no son
exactamente equivalentes a los métodos GetValue/SetValue de JavaScript de Silverlight. En WPF o en la API
administrada para Silverlight, los métodos GetValue y SetValue solo pueden actuar en propiedades de
dependencia, mientras que los métodos GetValue/SetValue pueden actuar en cualquier propiedad de
Silverlight disponible en la API de JavaScript.
En XAML, en el nivel de elemento, no existe ninguna diferencia en cuanto a la forma de hacer referencia al
controlador entre la API administrada y la API de JavaScript. En ambos casos, se proporciona una cadena
que designa una función (o un método) del controlador de eventos.
definiciones de sender que puede ver en la documentación básica de .NET Framework acerca de los eventos
de CLR, donde sender es el objeto que generó el evento. Esto último no es necesariamente cierto en el caso
de un evento enrutado; el evento podría haber sido generado por un objeto secundario del árbol de
objetos y haberse enrutado ascendentemente. Este concepto de evento enrutado también se describe a
veces en la documentación de Silverlight y de WPF como un evento de propagación.
referencia al objeto con nombre en el árbol de objetos extendido. En el siguiente XAML se crea un árbol de
objetos con un TextBlock con nombre y un controlador de eventos en el Canvas primario.
<Canvas
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Loaded="onLoaded">
<TextBlock x:Name="myTextBlock" />
</Canvas>
En el ejemplo de JavaScript siguiente se muestra cómo usar el método FindName para buscar un objeto con
nombre concreto en el árbol de objetos de Silverlight. En este caso, el código muestra la fecha actual como
la propiedad Text del objeto TextBlock.
function onLoaded(sender, eventArgs)
{
// Set the TextBlock to display the current date and time.
sender.findName("myTextBlock").text = Date();
}
En el ejemplo anterior, es posible que haya observado los "tokens" devueltos. En algunas circunstancias, es
posible que desee quitar los controladores de eventos. Puede hacerlo si tiene pensado reemplazar un
controlador de eventos previamente agregado por una función de control diferente. Para quitar una función
de controlador de eventos existente, use el método RemoveEventListener. En el ejemplo de JavaScript
siguiente se muestra cómo quitar los controladores de dos eventos diferentes de un objeto TextBlock.
function removeEvents()
{
textBlock.removeEventListener("MouseEnter", entertoken1);
textBlock.removeEventListener("MouseLeave", leavetoken1);
}
Tenga en cuenta el modo en que el código destinado a quitar el controlador de eventos hace referencia a
los mencionados tokens que se declararon como variables en el código anterior destinado a agregar
controladores de eventos. En realidad, los tokens son simplemente valores enteros. Los tokens los
devuelven las llamadas a AddEventListener, puesto que puede resultar necesario diferenciar los
controladores si se define más de un controlador para el mismo evento en la misma instancia. Si no tiene
intención de quitar los controladores posteriormente, no es necesario que almacene los tokens devueltos
por la llamada a AddEventListener.
También puede quitar los controladores en casos en los que el evento se haya agregado a través de un
atributo de evento XAML. En el caso de un atributo de evento XAML, no hay ninguna llamada de función
que pueda devolver un token. Sin embargo, puede proporcionar el valor 0 (cero) al parámetro token para
quitar un evento en el que se agregó el controlador utilizando un atributo XAML. Los tokens representan el
orden en que se agregaron los controladores, de 0 en adelante. Dado que los controladores de atributos
XAML son los primeros controladores que se agregan (el análisis de XAML tiene lugar antes de que
cualquier script pueda agregar controladores) y dado que solo puede agregarse un controlador de eventos
por evento/instancia utilizando XAML, el valor token del controlador de eventos agregado por XAML
siempre es 0.
Nota:
El DOM de Gecko admite un método DOM en muchos elementos que también se denominan
AddEventHandler y tiene un propósito conceptual similar. La versión Gecko del DOM se diferencia de
AddEventHandler de Silverlight en que la versión Gecko del DOM tiene tres parámetros y la versión de
Silverlight tiene dos. No es posible usar la versión Gecko del DOM de AddEventHandler para agregar
controladores de objetos en el árbol de objetos de Silverlight. No obstante, puede usarla para agregar
controladores a cualquier elemento de la página HTML que realmente se encuentre en el DOM HTML.
En este ejemplo, el código de JavaScript se define insertado, en lugar de hacer referencia a una función de
controlador de eventos. Esto no es posible con los eventos de Silverlight; es necesario definir funciones y
hacer referencia a ellas.
Además, tenga en cuenta la similitud que existe entre el evento del DOM HTML onload y el evento Loaded
de Silverlight. El evento onload del DOM HTML no se genera hasta que la página web se ha cargado por
completo. Esto significa que cualquier complemento Silverlight incluido dentro de la página generará su
evento Loaded antes que el evento onload del DOM HTML.
Eventos de error
Los errores de la API de JavaScript pueden controlarse a menudo escribiendo un controlador para el evento
OnError definido para el objeto de complemento Silverlight. Los eventos de error siempre incluyen los datos
del evento en forma de ErrorEventArgs que se encuentran disponibles para el controlador de errores, y los
eventos del analizador y los eventos en tiempo de ejecución proporcionan las subclases especializadas
ParserErrorEventArgs o RuntimeErrorEventArgs respectivamente.
forma predeterminada. Al crear el emisor, debe identificar el receptor correspondiente. Si solo especifica un
nombre, el emisor supondrá que el receptor se hospeda en el mismo dominio y que utiliza un nombre cuyo
nombre está asignado al dominio.
El ámbito de nombres garantiza que el receptor va a recibir únicamente los mensajes dirigidos al mismo. Es
posible usar el ámbito global si no se desea restringir las aplicaciones a dominios concretos. Sin embargo,
esto aumenta la posibilidad de que se produzcan conflictos de nombres, a menos que se elijan nombres
que tengan probabilidad de ser únicos. El ámbito de dominio permite elegir nombres de receptor más
simples si se está familiarizado con todas las aplicaciones basadas en Silverlight que se hospedan en un
dominio.
En el ejemplo de código siguiente se muestra una configuración básica donde las aplicaciones emisora y
receptora se hospedan en el mismo dominio.
' In the receiving application:
Dim messageReceiver As New LocalMessageReceiver("receiver")
' In the sending application:
Dim messageSender As New LocalMessageSender("receiver")
Puede crear varios objetos receptores y emisores. Cada receptor puede recibir los mensajes de cualquier
número de emisores. Cada emisor, sin embargo, solo puede enviar mensajes al receptor identificado en su
constructor. Además, puede configurar el receptor de forma que reciba únicamente los mensajes de los
dominios emisores especificados, o desde cualquier dominio.
En el ejemplo siguiente se muestra una configuración más compleja en virtud de la cual las aplicaciones
emisora y receptora se pueden hospedar en el mismo dominio o en dominios diferentes.
' In the receiving application:
Dim messageReceiver As New LocalMessageReceiver("receiver", ReceiverNameScope.Global,
LocalMessageReceiver.AnyDomain)
' In the sending application:
Dim messageSender As New LocalMessageSender("receiver", LocalMessageSender.Global)
En este ejemplo, el receptor recibe un nombre en el ámbito global y puede recibir mensajes de cualquier
dominio. También el emisor especifica el ámbito global. El ámbito global resulta útil para que el emisor no
tenga que saber cuál es el dominio del receptor. Sin embargo, cuando se utiliza el ámbito global se deben
elegir cuidadosamente los nombres de los receptores, a fin de evitar la posibilidad de conflictos. Para
obtener más información, vea la sección "Escenarios avanzados y solución de problemas" más adelante en
este mismo tema.
Después de crear los objetos emisores y receptores, agregue controladores de los eventos LocalMessage
Sender.SendCompleted y LocalMessageReceiver.MessageReceived para completar la configuración. Estos
eventos se describen en la sección siguiente.
Cuando el receptor esté talmente configurado, llame al método LocalMessageReceiver.Listen. Este método
registra la identidad del receptor y le permite recibir los eventos MessageReceived. Este método también
inicia una excepción ListenFailedException si ya hay un receptor registrado con el mismo nombre y ámbito
de nombres. Por ejemplo, esto puede suceder si se usa un nombre codificado de forma rígida y un usuario
carga al mismo tiempo la página web host en más de una ventana o pestaña del explorador. Para obtener
más información, vea la sección "Escenarios avanzados y solución de problemas".
No se puede modificar la configuración del receptor después de llamar al método Listen. El receptor seguirá
recibiendo mensajes hasta que se llame a su método Dispose.
En el ejemplo de código siguiente se muestran los detalles de configuración completos donde las
aplicaciones emisora y receptora se hospedan en el mismo dominio.
' In the receiving application:
Dim messageReceiver As New LocalMessageReceiver("receiver")
AddHandler messageReceiver.MessageReceived, AddressOf receiver_MessageReceived
Try
messageReceiver.Listen()
Catch ex As ListenFailedException
MessageBox.Show("Cannot receive messages." & Environment.NewLine & _
"There is already a receiver with the name 'receiver'.", "LocalMessageReceiver", MessageBoxButton.OK)
End Try
' In the sending application:
Dim messageSender As New LocalMessageSender("receiver")
AddHandler messageSender.SendCompleted, AddressOf sender_SendCompleted
No es necesario que el emisor controle el evento SendCompleted. Sin embargo, si lo hace, el evento se
produce con independencia de si el mensaje se recibe correctamente o no, y de si el receptor envía una
respuesta o no. No obstante, si el mensaje no se recibe, la propiedad AsyncCompletedEventArgs.Error
(heredada por la clase SendCompletedEventArgs) se establecerá en una instancia de SendFailedException.
Por ejemplo, esto se puede producir si no se ha registrado el nombre del destinatario especificado o si no
está configurado para recibir los mensajes del dominio del remitente.
Diagrama de ejemplo
En el diagrama siguiente se resumen los comportamientos descritos en las secciones anteriores.
Con la mensajería local entre dominios, a veces es preciso tomar precauciones adicionales para evitar
conflictos de nombre o la asunción del control de mensajes. Recuerde que la primera aplicación que registra
el nombre de un receptor dentro de un ámbito de nombres determinado recibirá los mensajes dirigidos a
esa identidad. Esto podría provocar problemas si una aplicación desconocida con la misma identidad ya
está abierta en otra ventana o pestaña del explorador cuando se carga la aplicación.
Si se utiliza el ámbito de nombres global, debe evitarse el uso de nombres de receptor comunes. Si la
seguridad es una cuestión importante, puede ser conveniente utilizar ámbitos de nombres de dominio y
restringir los dominios desde los que el receptor puede recibir mensajes. Por último, debe evitarse el envío
de información confidencial a través de un canal de mensajería local no cifrado.
Enviar mensajes complejos
Con la mensajería local, se puede enviar cualquier cadena de hasta 40 kilobytes. En muchas situaciones, el
mensaje tendrá que ser solamente una notificación simple o un conjunto de valores simple que el receptor
puede analizar e interpretar con facilidad. Sin embargo, dentro del límite de 40 kilobytes, pueden enviarse
mensajes arbitrariamente complejos, incluso objetos serializados y mensajes cifrados.
Silverlight proporciona API para serializar y deserializar datos XML o JSON. Se trata de formatos de datos
comunes cuando se trabaja con servicios Web. Aunque la mensajería local tiene lugar por completo en un
equipo único, estos formatos de datos se pueden utilizar de la misma manera que con un servicio Web.
Trabajar con datos XML resulta particularmente fácil porque Silverlight incluye LINQ to XML. Sin embargo,
los datos XML ocupan más espacio, de modo que si se van a serializar objetos grandes que pueden superar
el límite de 40 kilobytes, puede ser conveniente usar JSON.
Silverlight proporciona API para criptografía en el espacio de nombres System.Security.Cryptography.
Enviar mensajes durante el inicio de la aplicación
Según su tamaño, las aplicaciones emisora y receptora podrían terminar de cargarse en momentos distintos.
Aunque ambas aplicaciones sean pequeñas, no hay ninguna garantía de que la aplicación receptora esté
disponible cuando la aplicación emisora esté lista para enviar. Si necesita enviar un mensaje local durante el
tiempo de inicio de la aplicación, debe tener esto en cuenta.
Una manera de evitar este problema es hacer que la aplicación emisora envíe el mensaje repetidamente
hasta que se reciba. Para ello, puede reenviar el mensaje en el controlador de eventos SendCompleted si la
propiedad AsyncCompletedEventArgs.Error no es null. Esta técnica se utiliza en el ejemplo de código de
Cómo: Implementar la comunicación entre aplicaciones locales basadas en Silverlight.
Otro enfoque es utilizar la característica Puente HTML para comunicarse a través de la página web host y
avisar a la aplicación emisora cuando se haya cargado la aplicación receptora. Obviamente, podría utilizar
Puente HTML como canal de comunicación en lugar de la mensajería local. Sin embargo, la mensajería local
suele ser más conveniente una vez que el emisor ha determinado que el receptor está disponible y
preparado para recibir mensajes. También debe tenerse en cuenta que la característica Puente HTML
requiere una página HTML host, de modo que no funciona con aplicaciones de ejecución fuera del
explorador.
Evitar conflictos de nombres con varias instancias de una misma aplicación web
En algunos casos, puede ser necesario permitir que los usuarios ejecuten más de una instancia de la
aplicación web a la vez. En este caso, se precisará código adicional para asegurarse de que las instancias de
LocalMessageReceiver tengan nombres únicos.
Tal y como se ha mencionado, se puede controlar la excepción ListenFailedException iniciada por el método
LocalMessageReceiver.Listen para determinar si ya se ga registrado un nombre de receptor. Esto resulta útil
si, sencillamente, desea deshabilitar la mensajería local para las instancias adicionales de la aplicación web.
No obstante, si desea que las instancias adicionales se ejecuten normalmente, deberá generar nombres de
receptor únicos para esas instancias.
En este caso, puede generar los nombres de receptor en JavaScript, utilizando la fecha y hora actuales para
asegurar su singularidad. A continuación, puede recuperar los nombres generados en las aplicaciones
emisora y receptora por medio de la característica Puente HTML.
Imports System
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Messaging
<UserControl x:Class="ReceivingApplication.Receiver"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel x:Name="LayoutRoot">
<TextBlock Text="Receiver" FontSize="20" />
<TextBlock x:Name="output"/>
</StackPanel>
</UserControl>
Imports System
Imports System.Windows.Controls
Imports System.Windows.Messaging
Una aplicación de ejecución fuera del explorador se puede ejecutar sin que haya una conexión de red. Si la
aplicación suele utilizar recursos basados en red, se puede implementar la detección de la red y
proporcionar compatibilidad sin conexión cuando esta última no está disponible. Por ejemplo, puede utilizar
el almacenamiento aislado a modo de memoria caché sin conexión que se sincronice con un almacén de
datos basado en servidor cuando se reanude la conexión. Cuando la conexión está disponible, también
puede comprobarse si hay actualizaciones para la aplicación.
Asimismo, se puede configurar una aplicación de ejecución fuera del explorador de modo que requiera
confianza elevada. Las aplicaciones de confianza pueden omitir algunas de las restricciones del espacio
aislado de seguridad. Por ejemplo, las aplicaciones de confianza pueden utilizar el modo de pantalla
completa sin restricciones de teclado.
Nota:
Las aplicaciones de ejecución fuera del explorador están sometidas a las mismas restricciones de espacio
aislado que las aplicaciones normales de ejecución en explorador. Para flexibilizar algunas de estas
restricciones, se debe configurar la aplicación de modo que requiera confianza elevada. Sin embargo, si se
necesita acceso no restringido al equipo del usuario o se precisan otras capacidades además de las
proporcionadas por Silverlight, puede ser conveniente utilizar Windows Presentation Foundation (WPF).
Como alternativa, se puede hospedar el complemento Silverlight dentro de otra aplicación.
Las aplicaciones de ejecución fuera del explorador pueden tener acceso a los recursos de la red por HTTPS
cuando hay una conexión disponible. Sin embargo, en este momento no existe ningún indicador integrado
de la presencia de un canal seguro y se puede suplantar cualquier indicador que se proporcione. Las
aplicaciones de ejecución fuera del explorador son tan seguras como los sitios web donde se hospedan. Por
consiguiente, los usuarios deben basarse en la seguridad del sitio host al instalar o actualizar una aplicación
de ejecución fuera del explorador. Si la aplicación trata información confidencial, debería usar HTTPS para el
URI de la aplicación y para las comunicaciones seguras. Observe que siempre se utiliza el identificador URI
(incluido el protocolo) de la aplicación original cuando la aplicación comprueba si hay actualizaciones.
Sin embargo, si se configura la aplicación de modo que requiera confianza elevada, aparecerá un cuadro de
diálogo con una advertencia de seguridad. Este cuadro de diálogo contiene las mismas opciones de acceso
directo, pero además informa al usuario de que la aplicación tendrá mayor acceso al equipo.
El nombre de aplicación que aparece en el menú contextual y en el cuadro de diálogo corresponde al
nombre del acceso directo en la configuración de ejecución fuera del explorador. La imagen que aparece en
el cuadro de diálogo corresponde al icono más grande de la configuración. Si no especifica ningún icono en
la configuración, se utiliza el icono predeterminado, como se muestra en la imagen del ejemplo.
Es posible mostrar el cuadro de diálogo de instalación mediante programación llamando al método
Application.Install. Sin embargo, esto funciona solamente dentro de un controlador de eventos para un
evento iniciado por usuario y únicamente si se ha configurado correctamente la aplicación.
Nota:
Los administradores del sistema pueden deshabilitar la capacidad para instalar aplicaciones de confianza. En
ese caso, cuando se intentan instalar dichas aplicaciones, la instalación no se lleva a cabo y el método Install
devuelve false.
Hay varias razones para proporcionar una experiencia de instalación personalizada para las aplicaciones de
ejecución fuera del explorador:
Para asegurarse de que pueda detectarse la opción de instalación de aplicaciones de ejecución
fuera del explorador.
Para describir lo que se va a instalar y la duración de la instalación.
Para indicar si alguna funcionalidad requiere una conexión de red activa.
Los últimos dos puntos son sobre todo importantes para las aplicaciones donde no quedan claros los
límites entre el sitio web, la aplicación y el contenido. Por ejemplo, se debe comunicar a los usuarios si están
descargando una biblioteca completa de vídeos o simplemente un explorador de vídeos que requiere una
conexión de red.
Si controla el evento MouseRightButtonDown, se suprime automáticamente el menú contextual de la
aplicación. En ese caso, deberá proporcionar una interfaz de usuario propia para la instalación de
aplicaciones de ejecución fuera del explorador. Si no controla el evento MouseRightButtonDown y desea
suprimir la opción de instalación del menú contextual, establezca la propiedad OutOfBrowserSettings.
ShowInstallMenuItem en false en la configuración de la ejecución fuera del explorador.
Para la instalación de ejecución fuera del explorador se necesita la aceptación del usuario, de modo que el
cuadro de diálogo de instalación no se puede deshabilitar. Sin embargo, puede tener acceso a los datos de
configuración por medio de la propiedad Deployment.OutOfBrowserSettings si desea mostrarlo en su
propia interfaz de usuario.
No se necesitan privilegios de administrador para realizar una instalación de ejecución fuera del explorador.
Cuando un usuario instala una aplicación, se coloca una copia de ella en una memoria caché de aplicación
de ejecución fuera del explorador situada en la carpeta de perfil del usuario. Esto significa que la aplicación
está disponible únicamente para el usuario que la instaló.
El usuario puede iniciar la aplicación mediante los accesos directos especificados en el cuadro de diálogo de
instalación. Los accesos directos ejecutan un programa denominado sllauncher.exe, al que pasan un
identificador único asignado a la aplicación de ejecución fuera del explorador. El programa sllauncher carga
la aplicación en una ventana para cuya creación se utilizan las propiedades de ancho, alto y texto de la barra
de título especificadas en la configuración de la ejecución fuera del explorador.
Para quitar una aplicación instalada, el usuario debe iniciarla, hacer clic en ella con el botón secundario y, a
continuación, seleccionar Quitar esta aplicación. Asimismo, puede desinstalar la aplicación desde
Programas y características en el Panel de control. Este procedimiento es necesario si se suprime el menú
contextual de la aplicación controlando el evento MouseRightButtonDown.
Los administradores del sistema pueden utilizar la versión de Silverlight 4 de sllauncher.exe para
automatizar la instalación de las aplicaciones de ejecución fuera del explorador.
Para determinar si una aplicación se ha instalado de modo que se ejecute fuera del explorador, compruebe
la propiedad Application.InstallState. Para responder a la instalación de ejecución fuera del explorador,
controle el evento Application.InstallStateChanged. También puede determinar si una aplicación se inició de
fuera del explorador comprobando la propiedad Application.IsRunningOutOfBrowser.
Lo habitual es deshabilitar todas las funcionalidades de la aplicación que se basen en los servicios de red o
del explorador. Si la aplicación almacena información de estado del usuario en su servidor del host mientras
está conectada, puede utilizar el almacenamiento aislado para almacenar en memoria caché los datos entre
dos ejecuciones de la aplicación. A continuación, puede responder a la disponibilidad de la red
sincronizando los datos en caché con el servidor. Asimismo, puede configurar la aplicación de modo que
requiera confianza elevada, lo que permite a la aplicación almacenar información de estado del usuario y
otros datos en el sistema de archivos local.
Puede utilizar la mensajería local para la comunicación entre una aplicación de ejecución fuera del
explorador y una aplicación hospedada en web. Sin embargo, en Internet Explorer, la mensajería local está
deshabilitada de forma predeterminada entre las aplicaciones que se ejecutan en diferentes zonas de
seguridad. Las aplicaciones hospedadas en web suelen ejecutarse dentro de la zona de Internet, mientras
que las de ejecución fuera del explorador lo hacen en la zona confiable. Por consiguiente, para habilitar la
mensajería local en este escenario, debe establecer la propiedad LocalMessageReceiver.DisableSender
TrustCheck en true.
Si la aplicación se ha iniciado desde fuera del explorador y la conectividad de red está disponible, puede
buscar actualizaciones de la aplicación en el servidor del host.
Nota:
En general, solamente debe comprobarse si hay actualizaciones con el consentimiento del usuario, y se le
debe notificar cuando hay una disponible.
Nota:
Si una aplicación de ejecución fuera del explorador requiere los recursos de red que normalmente se cargan
después del inicio, también necesitará implementar la compatibilidad sin conexión.
Si no especifica los valores Ancho y Alto, la ventana de la aplicación usará un tamaño predeterminado de
800x600.
Si no se especifican iconos, se usarán los iconos predeterminados. Si especifica los iconos, debería
especificar uno para cada tamaño indicado en el diseñador (16x16, 32x32, 48x48 y 128x128).
Los iconos deben ser archivos .png agregados al proyecto que tengan como Acción de compilación el
valor Contenido. Además, los archivos .png deben ser de las dimensiones indicadas. El sistema operativo
elegirá el tamaño más adecuado dependiendo de cada situación. Si no se puede cargar un icono adecuado,
aparecerá el predeterminado.
Nota:
Silverlight 3 no admite las propiedades siguientes:
WindowStartupLocation
Top
Left
SecuritySettings
WindowStyle
Ejemplo
Los valores del cuadro de diálogo Configuración de la ejecución fuera del explorador se usan para
generar un archivo OutOfBrowserSettings.xml en la carpeta Propiedades del proyecto (Mi proyecto en
Visual Basic). Cualquier cambio en este archivo se refleja en el diseñador. Este archivo se usa para incluir los
valores especificados en el manifiesto de aplicación (AppManifest.xaml).
Para configurar una aplicación existente para la compatibilidad con la ejecución fuera del explorador sin
volver a compilar, agregue el XML de configuración al manifiesto en un archivo .xap existente. Para ello,
copie el elemento de propiedad Deployment.OutOfBrowserSettings del código de ejemplo siguiente en el
archivo de manifiesto y, a continuación, actualice los valores.
Como alternativa al uso del diseñador, puede especificar la configuración de ejecución fuera del explorador
rellenando la plantilla de manifiesto (AppManifest.xml en la carpeta Propiedades o Mi proyecto), como se
muestra en el ejemplo siguiente. De forma predeterminada, la compilación usa la plantilla de manifiesto
para generar el manifiesto de aplicación. Sin embargo, el XML de plantilla es más fácil de usar en Visual
Studio.
Nota:
Si usa el cuadro de diálogo Configuración de la ejecución fuera del explorador, no puede especificar la
configuración de la ejecución fuera del explorador en el manifiesto de aplicación o en la plantilla de
manifiesto. Si lo hace, se creará información duplicada en el manifiesto. Se generará un error al intentar
ejecutar la aplicación.
<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Deployment.Parts>
</Deployment.Parts>
<Deployment.OutOfBrowserSettings>
<OutOfBrowserSettings
ShortName="Out-of-Browser Application"
EnableGPUAcceleration="True"
ShowInstallMenuItem="True">
<OutOfBrowserSettings.Blurb>
Demonstrates the out-of-browser feature.
</OutOfBrowserSettings.Blurb>
<OutOfBrowserSettings.Icons>
Puede probar el indicador de conectividad de red en la aplicación de ejecución fuera del explorador si la
desconecta y la vuelve a conectar a la red. Observe que el botón de actualización desaparece cuando la
conexión no está disponible.
Para probar el botón de actualización, debería incluir un proyecto de aplicación web en su solución
Silverlight. Después de instalar la aplicación, modifique y recompile la solución en Visual Studio, y, a
continuación, haga clic en el botón de instalación para descargar la actualización.
<UserControl x:Class="OutOfBrowser.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel x:Name="LayoutRoot" Background="White" Margin="20">
<TextBlock x:Name="networkIndicator" FontWeight="Bold" FontSize="20"/>
<Button x:Name="installButton" Content="install"
HorizontalAlignment="Left" Margin="0,10" Padding="10,5"
Click="installButton_Click"/>
<Button x:Name="updateButton" Content="check for update"
HorizontalAlignment="Left" Margin="0,10" Padding="10,5"
Click="updateButton_Click"/>
<StackPanel Orientation="Horizontal">
<TextBlock Text="ShortName = " FontWeight="Bold"/>
<TextBlock Text="{Binding ShortName}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Blurb = " FontWeight="Bold"/>
<TextBlock Text="{Binding Blurb}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="WindowSettings.Title = " FontWeight="Bold"/>
<TextBlock Text="{Binding WindowSettings.Title}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="WindowSettings.Height = " FontWeight="Bold"/>
<TextBlock Text="{Binding WindowSettings.Height}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="WindowSettings.Width = " FontWeight="Bold"/>
<TextBlock Text="{Binding WindowSettings.Width}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="IsRunningOutOfBrowser = " FontWeight="Bold"/>
<TextBlock x:Name="isRunningOutOfBrowserTextBlock"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="InstallState = " FontWeight="Bold"/>
<TextBlock x:Name="installStateTextBlock"/>
</StackPanel>
</StackPanel>
</UserControl>
Imports System
Imports System.Net.NetworkInformation
Imports System.Windows
Imports System.Windows.Controls
modo que requieran confianza elevada. Después de la instalación, estas aplicaciones de confianza pueden
omitir algunas de las restricciones del espacio aislado de seguridad. Por ejemplo, las aplicaciones de
confianza pueden obtener acceso a los archivos de usuario y utilizar el modo de pantalla completa sin
restricciones de teclado.
Se puede utilizar el diseñador de proyectos de Visual Studio para configurar una aplicación de modo que
requiera confianza elevada. El diseñador establece el valor apropiado en el manifiesto de aplicación.
Asimismo, es posible actualizar el manifiesto de una aplicación existente sin recompilar. Sin embargo,
normalmente hay que modificar su funcionalidad para poder aprovechar la confianza elevada.
Cuando se instala una aplicación de ejecución fuera del explorador que requiere confianza elevada, aparece
una advertencia de seguridad en lugar del cuadro de diálogo de instalación predeterminado. Esta
advertencia indica que la aplicación puede obtener acceso a los datos del usuario y que debe instalarse
únicamente desde un sitio web de confianza. Una vez instalada, la aplicación se comporta como una
aplicación de ejecución fuera del explorador normal, con la excepción de lo descrito en este tema.
La advertencia de seguridad varía dependiendo de si la aplicación tiene una firma digital válida. Las
aplicaciones sin firmas válidas (también denominadas aplicaciones no comprobadas) presentan un mayor
riesgo para la seguridad, por lo que la advertencia destaca más. En las siguientes imágenes, se muestra la
advertencia de seguridad para una aplicación antes y después de que se agregue una firma digital.
Advertencia de seguridad para una aplicación no comprobada
La mayoría de la documentación de Silverlight se ha escrito suponiendo que todas las aplicaciones son
aplicaciones en espacio aislado que se hospedan en un explorador. En este tema, se describe en qué se
diferencian las aplicaciones de confianza de las aplicaciones en espacio aislado. En concreto, se describen
las capacidades habilitadas por la confianza elevada y se explica cómo determinar si una aplicación se
ejecuta con confianza elevada.
Nota:
Si bien las aplicaciones de confianza se ejecutan con privilegios de seguridad elevados, no tienen las mismas
capacidades que las aplicaciones de escritorio que se ejecutan con plena confianza. Esto ayuda a mantener
la compatibilidad con varias plataformas. Si se necesita un acceso no restringido al equipo del usuario, o se
precisan otras capacidades además de las proporcionadas por Silverlight, puede ser conveniente utilizar
Windows Presentation Foundation (WPF). Como alternativa, se puede hospedar el complemento Silverlight
Para reemplazar la funcionalidad proporcionada por la barra de título y el borde, puede utilizar las API de la
clase Window. Para que los usuarios puedan arrastrar la ventana o los bordes de la ventana, utilice los
métodos DragResize y DragMove. También puede ajustar el tamaño y la posición de la ventana mediante
las propiedades Left, Top, Width y Height. Para que los usuarios puedan minimizar y maximizar la ventana,
utilice la propiedad WindowState. Para que los usuarios puedan cerrar la ventana, utilice el método Close.
Nota:
Estas carpetas son distintas de las bibliotecas de Windows 7 denominadas Documentos, Música, Imágenes y
Vídeos. Estas carpetas de biblioteca suelen combinar el contenido de las carpetas del usuario con el de otras
carpetas, como carpetas multimedia compartidas. Sin embargo, las aplicaciones de confianza no pueden
obtener acceso a carpetas que no sean del usuario, salvo a través de las clases SaveFileDialog y
OpenFileDialog.
Es preciso utilizar el método Environment.GetFolderPath para obtener las rutas de acceso a las carpetas del
usuario. No se pueden especificar directamente estas rutas de acceso.
En la siguiente tabla, se muestran las clases del espacio de nombres System.IO que las aplicaciones de
confianza pueden utilizar. También se indica qué miembros de cada clase no se admiten.
Integración nativa
Las aplicaciones de confianza pueden obtener acceso a algunas de las capacidades del sistema operativo
nativo. Por ejemplo, en Windows, las aplicaciones de confianza pueden utilizar las características de
automatización y obtener acceso o manipular los componentes expuestos por el conjunto de Office y otras
aplicaciones.
Consideraciones de seguridad
Si bien las aplicaciones de confianza no tienen acceso total al equipo host, pueden obtener acceso a los
datos personales y causar daños. Por consiguiente, se han de tratarlas como aplicaciones de plena confianza
a la hora de realizar evaluaciones de seguridad y auditorías. Para evitar que los usuarios instalen o ejecuten
aplicaciones de confianza, los administradores del sistema pueden utilizar los valores de la directiva de
equipo para denegar el acceso, tal y como se describe en la sección "Restricciones de directiva para la
confianza elevada" que figura en este tema.
Las aplicaciones de confianza se ejecutan con privilegios de usuario, incluso si las instalan usuarios con
privilegios de administrador. Sin embargo, las aplicaciones de confianza se pueden ejecutar con privilegios
elevados durante la depuración en la fase de desarrollo, por lo que es necesario asegurarse de que las
pruebas se realicen en consecuencia.
Silverlight ejecuta todo el código de aplicación en una instancia de AppDomain que tiene un conjunto
uniforme de privilegios (aplicaciones de confianza o en espacio aislado). Es responsabilidad de los
desarrolladores de una aplicación comprobar y validar cualquier componente externo que se agregue a la
aplicación.
Las aplicaciones de ejecución fuera del explorador son tan seguras como los sitios web donde se hospedan.
Por consiguiente, los usuarios deben basarse en la seguridad del sitio host al instalar o actualizar una
aplicación de ejecución fuera del explorador. En la siguiente lista, se describen algunas de las acciones que
se pueden realizar para ayudar a mejorar la seguridad.
Firme las aplicaciones tal y como se describe en la sección "Firma de aplicaciones" que figura en
este tema.
Si la aplicación obtiene acceso a recursos de su servidor host, deberá comprobar que el valor de la
propiedad SilverlightHost.Source se corresponde con el identificador URI del sitio de origen
esperado.
Si la aplicación trata información confidencial o carga código adicional del servidor, se debe usar
HTTPS para el identificador URI de la aplicación y para las comunicaciones seguras. Observe que
siempre se utiliza el identificador URI (incluido el protocolo) de la aplicación original cuando se
comprueba si hay actualizaciones.
Las aplicaciones de ejecución fuera del explorador pueden tener acceso a los recursos de la red por
HTTPS cuando hay una conexión disponible. Los certificados expirados o no válidos darán lugar a
errores en las llamadas de conexión de red. Sin embargo, hoy en día, no hay ningún indicador
integrado de la presencia de un canal seguro. Para aumentar la confianza del usuario, considere la
posibilidad de proporcionar un indicador propio.
Firma de aplicaciones
Agregar una firma digital a una aplicación de confianza es un paso importante para ayudar a proteger la
aplicación y aumentar la confianza del usuario durante la instalación. Además, solamente las aplicaciones de
confianza con firmas digitales válidas pueden utilizar el mecanismo de actualización de ejecución fuera del
explorador. Para actualizar una aplicación de confianza sin firma válida, los usuarios deben desinstalar la
versión anterior e instalar manualmente la nueva versión.
Para agregar una firma digital a una aplicación de confianza, utilice la utilidad SignTool.exe con un
certificado de firma de código Authenicode X.509. Por ejemplo, puede utilizar la siguiente línea de
comandos: signtool sign /v /f archivoDeCertificado.pfx archivoQueSeVaAFirmar
La firma de código es relevante únicamente para las aplicaciones de confianza. Silverlight comprueba la
firma y el certificado cuando el usuario instala o actualiza la aplicación. Una aplicación de confianza se
puede instalar sin firma válida. Sin embargo, Silverlight evita que las aplicaciones de confianza se actualicen,
a menos que la aplicación original y la actualización estén firmadas con el mismo certificado de firma de
código válido y comprobado. Además, el certificado no puede haber expirado en el momento de la
actualización. Asegúrese de tener en cuenta la fecha de expiración del certificado a la hora de planear la
implementación y la actualización.
Nota:
Silverlight no evita las actualizaciones de la aplicación cuando el host del sitio de origen es localhost o
127.0.0.1. Esto permite probar el código de actualización sin firma digital.
Notas de la versión
Silverlight 3 no admite aplicaciones de confianza.
Nota:
Estas carpetas son distintas de las bibliotecas de Windows 7 denominadas Documentos, Música, Imágenes y
Vídeos. Estas carpetas de biblioteca suelen combinar el contenido de las carpetas del usuario con el de otras
carpetas, como carpetas multimedia compartidas. Sin embargo, las aplicaciones de confianza no pueden
obtener acceso a carpetas que no sean del usuario, salvo a través de las clases SaveFileDialog y
OpenFileDialog.
En el tema siguiente se muestra cómo tener acceso a archivos de las carpetas de usuario y se enumeran las
API expuestas para su uso en aplicaciones de confianza.
Nota:
Las aplicaciones de confianza no se admiten en Silverlight 3.
Procedimientos
Para tener acceso a archivos de carpetas de usuario
Use las API compatibles como haría en el marco de escritorio, pero emplee los valores indicados
previamente de la enumeración System.Environment.SpecialFolder para construir las rutas de
acceso. En el ejemplo siguiente se muestra el uso necesario.
Private Sub TestIO()
If (Application.Current.HasElevatedPermissions) Then
Dim myDocuments As String = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
Dim filename As String = "test.txt"
Dim path As String = System.IO.Path.Combine(myDocuments, filename)
If File.Exists(path) Then
Dim contents As String = File.ReadAllText(path)
MessageBox.Show(contents)
End If
End If
End Sub
La automatización es una tecnología que las aplicaciones emplean para exponer funcionalidad a las
herramientas de scripting y otras aplicaciones. Por ejemplo, puede usar Automatización para agregar
características de Office a sus aplicaciones basadas en Silverlight.
Una aplicación o un componente que expone API de Automatización se denomina un servidor de
automatización, mientras que una aplicación que tiene acceso a estas API se denomina un cliente de
automatización. En el tema siguiente se describe cómo permitir que las aplicaciones basadas en Silverlight
funcionen como clientes de automatización.
Nota:
Solo las aplicaciones de confianza con ejecución fuera del explorador que se ejecutan en Windows pueden
tener acceso a las API de Automatización, y solo las expuestas por componentes o aplicaciones que ya están
instalados.
Nota:
No se admiten eventos con valores devueltos.
Private Sub SearchEmail()
UpdateStatusMessage("Searching Inbox for 'Silverlight'...")
' The following code demonstrates three ways to handle Automation
' events. In Visual Basic, all three ways use the AutomationEvent class.
searchEvent = AutomationFactory.GetEvent(outlook, "AdvancedSearchComplete")
' The first way is demonstrated by the Handles clause of the
' SearchEvent_EventRaised method, which requires the WithEvents modifier
' on the searchEvent variable declaration.
' The second way uses the AddHandler syntax with the EventRaised event,
' and does not require the WithEvents modifier.
' AddHandler searchEvent.EventRaised, AddressOf SearchEvent_EventRaised
' The third way uses the AutomationEvent.AddEventHandler method, and
' requires the use of a delegate with an API signature that matches the Automation event.
' searchEvent.AddEventHandler(New AdvancedSearchCompleteDelegate(AddressOf SearchComplete))
' Begin the search.
outlook.AdvancedSearch("Inbox","urn:schemas:mailheader:subject ci_phrasematch 'Silverlight'",
True, "SubjectSearch")
End Sub
' Required only with the second two ways of handling Automation events.
' Private Delegate Sub AdvancedSearchCompleteDelegate(ByRef search As Object)
' Note: Visual Basic does not support the use of custom delegates for events with optional parameters.
Private Sub SearchComplete(ByRef search As Object)
Dim searchResults As New List(Of String)
For Each result As Object In search.Results
searchResults.Add(result.Subject)
Next
SetResultsList(searchResults)
End Sub
Ejemplo
El siguiente código proporciona los métodos auxiliares y el XAML de la interfaz de usuario que se usan en el
código anterior. Para ejecutar el código de este tema, cree un nuevo proyecto de aplicación de Silverlight y,
a continuación, agregue todo el código a la clase MainPage.
<Grid x:Name="LayoutRoot" Background="White">
<TextBlock x:Name="message"/>
<ListBox x:Name="items" Visibility="Collapsed"/>
</Grid>
Nota:
Silverlight está supeditado a las mismas restricciones de recinto de seguridad con independencia del
entorno de host y de la presencia de un explorador web. Sin embargo, el entorno de host podría
proporcionar acceso total al equipo local, con lo que, en la práctica, se estaría eludiendo la seguridad de
Silverlight.
Si no hay un explorador o conexión de red presente, el entorno de host podría tener que proporcionar
funcionalidades de reemplazo, según sus requisitos.
de la página HTML o toda la página HTML. Debido a esto, existen dos marcos de referencia al colocar
objetos de Silverlight:
Dentro del complemento: los objetos se colocan en la superficie de Silverlight dentro del cuadro
de límite del complemento. En la mayoría de los artículos de información general sobre el diseño se
describe este tipo de colocación.
Dentro del HTML: el complemento completo y todos los objetos colocados en su interior están
sujetos al lugar donde se coloca el complemento en HTML.
Sistema de diseño
El término diseño describe el proceso de ajuste de tamaño y colocación de los objetos en la aplicación
basada en Silverlight. Para colocar objetos visuales, se deben insertar en un objeto Panel u otro objeto
contenedor. El objeto Panel primario presenta un comportamiento de diseño definido que determina cómo
se dibujan en pantalla los miembros de la colección Children de un elemento Panel. Se trata de un proceso
intensivo y, cuanto mayor es la colección Children, mayor es el número de cálculos realizados. También se
puede incluir mayor complejidad según el comportamiento de diseño definido por el elemento Panel que
posee la colección. Un diseño relativamente sencillo, como Canvas, puede producir un rendimiento
excelente si no se requiere un Panel más complejo, como Grid.
Cada vez que un elemento UIElement secundario cambia de posición, tiene el potencial de desencadenar un
nuevo paso del sistema de diseño. Es importante entender los eventos que pueden invocar el sistema de
diseño, ya que la invocación innecesaria puede deteriorar el rendimiento de la aplicación.
En su versión más simple, el diseño es un sistema recursivo que conduce a la configuración del tamaño,
posición y representación de un elemento en la pantalla. El sistema de diseño completa dos pasos por cada
miembro de la colección Children: un paso de medida y un paso de organización. En el paso de medida se
determina el tamaño deseado de cada elemento secundario. En el paso de organización se establece el
tamaño y la posición definitivos del elemento secundario.
Nota:
Al hacer referencia al diseño de un elemento, es más exacto hacer referencia al diseño del cuadro de límite
de ese elemento.
Para invalidar el comportamiento de diseño predeterminado de Panel, cada tipo de Panel proporciona sus
propios métodos MeasureOverride y ArrangeOverride para lograr su propio comportamiento de diseño.
Esta es la serie de eventos que se produce cada vez que se invoca el sistema de diseño:
1. Se mide cada elemento UIElement secundario.
2. Se evalúan las propiedades de tamaño definidas en FrameworkElement, como Width, Height y
Margin.
3. Se aplica la lógica específica de Panel, como la propiedad Orientation del apilamiento.
4. El contenido se organiza después de medir todos los elementos secundarios.
5. Se dibuja la colección Children en la pantalla.
6. Se invoca el proceso de nuevo si se agregan propiedades Children adicionales a la colección,
cambian las propiedades de diseño de Children, como Width y Height, o se llama al método
UpdateLayout.
Este proceso y los medios por los que se invoca se definen con mayor detalle en las secciones siguientes.
margen y el relleno, y el comportamiento individual del elemento Panel primario. A partir de estos datos, el
sistema puede calcular la posición de todos los elementos secundarios de un Panel determinado. Es
importante recordar que las características de tamaño definidas en el elemento primario (como un Border)
afectan a sus elementos secundarios.
En la siguiente ilustración se muestran las dimensiones de un panel primario, su elemento secundario y la
ranura de diseño que contiene el elemento secundario.
Puede ver que el área asignada para el elemento secundario es, en realidad, mucho mayor que el elemento
secundario. Corresponde al contenedor primario determinar el tamaño de la ranura de diseño para cada
elemento secundario. El elemento primario puede asignar más o menos espacio del que solicita el elemento
secundario. Puede obtener las dimensiones de la ranura de diseño llamando a GetLayoutSlot. A
continuación, el elemento primario coloca el elemento secundario dentro de su ranura de diseño en función
de las propiedades de alineación establecidas para el elemento secundario.
En la ilustración siguiente se muestra un elemento secundario que se gira y se extiende más allá de su
ranura de diseño asignada.
En este caso, el sistema de diseño recorta el elemento secundario y solo muestra la parte que cabe en la
ranura de diseño. Esta área visible, perfilada en rojo, se denomina clip de diseño y sus dimensiones se
pueden obtener llamando al método GetLayoutClip. Tenga en cuenta que GetLayoutClip devuelve un objeto
Geometry, por lo que el área visible no es necesariamente un rectángulo.
El cuadro de límite que rodea un elemento puede cambiar a medida que se agregan elementos adicionales
al contenedor primario. Puede reducirse o expandirse, en función del tipo y del tamaño de los elementos
que se agregan.
elemento secundario, pero el elemento primario también puede optar por restringir el tamaño del elemento
secundario en función del número de elementos que necesite colocar y el valor de su parámetro
availableSize.
Nota:
Existe una diferencia entre las propiedades de Height y Width, y ActualHeight y ActualWidth. Por ejemplo, la
propiedad ActualHeight es un valor calculado que se basa en otras entradas de alto y en el sistema de
diseño. El propio sistema de diseño establece el valor, basándose en un paso de representación real; por
consiguiente, puede existir un pequeño desfase con respecto al valor establecido de propiedades como
Height, que constituyen la base del cambio de entrada. Es necesario establecer Height y Width puesto que
su valor predeterminado es 0.
Dado que ActualHeight es un valor calculado, debe tener en cuenta que puede sufrir varios cambios o
cambios incrementales como resultado de las diversas operaciones realizadas por el sistema de diseño. El
sistema de diseño puede calcular el espacio de medidas necesario para los elementos secundarios, las
restricciones impuestas por el elemento principal, etc.
El objetivo final del paso de medida es que el sistema de diseño determine el valor de la propiedad
DesiredSize de cada elemento secundario, lo que sucede internamente después de llamar a Measure. Este
valor se almacena y se utiliza durante el proceso de organización.
Organizar
En el paso de organización, el sistema de diseño indica al objeto Panel el valor de finalSize que está
disponible para él y sus elementos secundarios. Durante el paso de organización, el elemento Panel
primario evalúa la propiedad DesiredSize del elemento secundario y los márgenes adicionales que puedan
afectar al tamaño representado del elemento; a continuación, determina el cuadro de límite para cada
elemento secundario. El cuadro de límite determina las dimensiones de la ranura de diseño del elemento
secundario. Luego, el elemento primario Panel llama al método Arrange de cada elemento secundario,
pasando la estructura Rect que establece el punto de origen del elemento secundario en el panel así como
su alto y ancho.
Nota:
Todo el diseño es relativo al elemento primario. Si se establece el punto de origen en 0.0, el elemento
secundario se colocará en la esquina superior izquierda del panel primario y no en la esquina superior
izquierda del complemento Silverlight.
El sistema de diseño efectúa una última evaluación de las propiedades de desplazamiento, como los
márgenes y la alineación, y coloca el elemento secundario dentro de su ranura de diseño. El elemento
secundario no necesita rellenar el espacio asignado completo, y con frecuencia no lo hace. A continuación,
el control se devuelve al Panel primario y el proceso del diseño se completa.
Nombre del
Descripción
panel
Define un área en la que pueden colocarse explícitamente los elementos secundarios
Canvas
utilizando las coordenadas relativas al área del control Canvas.
Grid Define un área de cuadrícula flexible que se compone de columnas y filas.
Organiza los elementos secundarios en una única línea que se puede orientar horizontal o
StackPanel
verticalmente.
Cada uno de estos contenedores de diseño tiene en cuenta distintas propiedades que pueden afectar al
modo en que se organizan los elementos secundarios. Algunos de los más comunes se muestran en la tabla
siguiente.
Además de aplicar la lógica de diseño de panel, puede utilizar transformaciones y animaciones para cambiar
la posición de un objeto.
Para los escenarios que requieren un diseño de aplicación que no es posible utilizando cualquiera de los
elementos Panel predefinidos, se pueden conseguir comportamientos de diseño personalizados heredando
de Panel e invalidando el comportamiento predeterminado de medida y organización mediante los
métodos MeasureOverride y ArrangeOverride.
Requisitos previos
Antes de seguir los pasos en este tema, deberá familiarizarse con el modo en que los objetos se
dimensionan y colocan en Silverlight.
Medir
El primer paso en el diseño de un panel es medir cada elemento secundario y determinar cuánto espacio
asignará el panel a dicho elemento secundario. Además, devuelva la cantidad de espacio disponible para el
panel completo.
En el ejemplo siguiente se muestra una invalidación del método MeasureOverride para un panel
(BlockPanel) que coloca 9 elementos secundarios en una cuadrícula de 3x3 donde cada celda es 100x100.
'First measure all children and return available size of panel
Protected Overloads Overrides Function MeasureOverride(ByVal availableSize As Size) As Size
'Measure first 9 children giving them space up to 100x100, remaining children get 0x0
Dim i As Integer = 0
For Each child As FrameworkElement In Children
If i < 9 Then
child.Measure(New Size(100, 100))
Else
child.Measure(New Size(0, 0))
En MeasureOverride, debe llamar al método Measure de cada elemento secundario, pasando el espacio que
el panel puede asignar. A continuación, el sistema del diseño calcula DesiredSize de cada elemento
secundario basándose en el tamaño disponible. En este ejemplo, asignamos 100x100 a los primeros 9
elementos secundarios y 0x0 a los restantes. El tamaño que el elemento primario asigna al elemento
secundario puede basarse en el valor availableSize que se pasa en el método MeasureOverride. El valor de
availableSize representa el área que el panel puede ocupar en el diseño.
Cuando se llama a Measure, el sistema del diseño determina el DesiredSize del elemento secundario
basándose en availableSize pasado a Measure y el tamaño natural del elemento. El tamaño natural lo
determina el elemento Width y las propiedades Height o el tamaño nativo de una imagen. La propiedad
DesiredSize se establece generalmente en availableSize o en el tamaño natural, el que tenga menor valor.
Una vez establecido DesiredSize de los elementos secundarios, el panel debe determinar cuánto espacio
solicitar de su elemento primario como el valor devuelto de su invalidación de MeasureOverride. El valor
adecuado se puede determinar de varias maneras:
Se calcula dependiendo de los valores DesiredSize totales de todos los elementos secundarios.
Un tamaño predeterminado, como el ejemplo actual.
Un tamaño muy grande, que permitirá exceso de espacio para que el panel organice los elementos
secundarios.
Precaución:
No devuelva el valor availableSize que se pasó a MeasureOverride. El valor devuelto para Measure Override
debe ser finito, pero el availableSize que se pasa puede ser infinito en algunos casos.
Organizar
Una vez completado el paso Medir, comienza el paso Organizar. En este paso debe determinar la posición y
el tamaño de la ranura de diseño de cada elemento secundario, y establecer el tamaño final del panel.
En el código siguiente se muestra el método ArrangeOverride para el BlockPanel de la sección Measuring.
'Second arrange all children and return final size of panel
Protected Overloads Overrides Function ArrangeOverride(ByVal finalSize As Size) As Size
'Get the collection of children
Dim mychildren As UIElementCollection = Children
'Get total number of children
Dim count As Integer = mychildren.Count
'Arrange children We're only allowing 9 children in this panel. More children will get a 0x0 layout slot.
Dim i As Integer
For i = 0 To 8
'Get (left, top) origin point for the element in the 3x3 block
Dim cellOrigin As Point = GetOrigin(i, 3, New Size(100, 100))
'Arrange child Get desired height and width. This will not be larger than 100x100 as set in MeasureOverride.
Dim dw As Double = mychildren(i).DesiredSize.Width
Dim dh As Double = mychildren(i).DesiredSize.Height
mychildren(i).Arrange(New Rect(cellOrigin.X, cellOrigin.Y, dw, dh))
Next
For i = 9 To count - 1
'Give the remaining children a 0x0 layout slot
mychildren(i).Arrange(New Rect(0, 0, 0, 0))
Next
'Return final size of the panel
Return New Size(300, 300)
End Function
En ArrangeOverride, llame a Arrange en cada secundario, pasando un Rect. Esto establece el punto de
origen, el alto y el ancho de la ranura de diseño del elemento secundario en el panel primario. En este
ejemplo, los primeros 9 elementos secundarios se colocan en una celda de una cuadrícula de 3x3 basándose
en su orden en la colección Children. El primer elemento secundario se coloca en la celda superior izquierda,
de modo que el objeto Rect pasado es (0,0,100,100); esto significa que se colocará en la esquina superior
izquierda del panel y que tendrá un ancho y un alto de 100. Los 9 primeros elementos secundarios tienen
asignada una ranura de diseño de 100 x 100. La ranura de diseño asignada a los demás elementos
secundarios es de 0 x 0. Si el tamaño deseado del elemento secundario es mayor que el espacio asignado,
se recortará. Cada elemento secundario se coloca en la ranura del diseño según las demás propiedades de
diseño, como HorizontalAlignment, VerticalAlignment y Margin.
Nota:
El panel personalizado no debería tener en cuenta propiedades que se pueden establecer, como Visibility,
Margin o MinWidth, cuando se determina el diseño. El sistema de diseño de Silverlight administrará todas
estas propiedades. Así que, por ejemplo, no es necesario que omita el diseño para elementos con Visibility
de Collapsed porque el sistema de diseño lo controlará.
Una vez organizados los elementos secundario, devuelva el tamaño final del panel. Este es el tamaño que el
panel solicitará de su contenedor primario. En este ejemplo, BlockPanel se establece siempre en 300x300.
aplicación. También tiene implicaciones con respecto al modo en que el usuario podría establecer los
valores de las propiedades o usar los valores existentes de las propiedades de diseño si ejecuta su propia
lógica de diseño en un panel personalizado o en otra clase.
La propiedad UseLayoutRounding
La superficie de API directa para el comportamiento de redondeo del diseño es la propiedad única
UIElement.UseLayoutRounding. El valor predeterminado de esta propiedad es true, lo que significa que el
redondeo del diseño está activado de forma predeterminada.
Nota:
Establecer con valores Double las propiedades de ajuste de tamaño de Silverlight es una técnica que se usa
principalmente con fines de compatibilidad con WPF. WPF admite un comportamiento de conversión para
otros tipos unitarios y también admite un concepto de píxel independiente del dispositivo que incluye
dependencias de plataforma. Silverlight es multiplataforma y no admite los tipos unitarios; por lo tanto, los
requisitos de conversión de WPF que requieren un tipo Double subyacente no suelen ser relevantes para la
programación en Silverlight.
la lógica de clase. Por ejemplo, podría estar agregando o calculando los valores, y preferir valores exactos a
arriesgarse a perder información en el proceso de redondeo.
Nota:
UseLayoutRounding existe en UIElement porque generalmente controla el comportamiento de las clases de
los contenedores de diseño, como los paneles, pero hay contenedores de diseño que potencialmente no
son paneles (FrameworkElement podría implementar ArrangeOverride y el resto de las API de diseño).
Líneas de ajuste
Las guías de alineación representan una indicación visual que ayuda a alinear un control con respecto a los
otros controles de una aplicación. Cuando se arrastra un control en Silverlight Designer, las guías de
alineación aparecen al alinearse el control con otro control. Las líneas de ajuste aparecen como líneas rojas
que conectan el control que se está arrastrando con el control con el que se está alineado. Las guías de
alineación aparecen cuando el borde superior, inferior, izquierdo o derecho del control que se está
arrastrando se alinea con el correspondiente borde de otro control. Con algunos controles, las líneas de
ajuste aparecen también cuando las líneas base del texto están alineadas.
Para alinear los bordes de los controles
En Silverlight Designer, con al menos dos controles, arrastre o cambie el tamaño de uno de ellos
para que el borde se alinee con otro control.
Cuando los bordes estén alineados, aparecerá una línea de ajuste indicando la alineación. Cuando
las líneas de ajuste aparecen, también verá un número junto a la línea de ajuste que cambia a
medida que arrastra el control. El número indica la distancia entre el borde del control actual y el
borde del otro control.
Para alinear líneas base del texto de controles basados en texto
En Silverlight Designer, con al menos dos controles basados en texto, arrastre uno de ellos de
modo que la línea base del texto se alinee con la línea base del texto de otro control.
Cuando las líneas base del texto estén alineadas, aparecerá una línea de ajuste indicando la
alineación.
Para desactivar las líneas de ajuste
Mientras arrastra un control en Silverlight Designer, mantenga presionada la tecla ALT.
Las líneas de ajuste se deshabilitarán temporalmente y ya no aparecerán.
Márgenes
En Silverlight Designer, el término margen hace referencia a la cantidad de espacio que hay entre el borde
de un control y el borde de su contenedor host. Cuando se selecciona un control en Silverlight Designer, los
márgenes se indican mediante las líneas negras que aparecen entre los bordes del control y los bordes del
contenedor. Si aparece una línea de margen entre un control y el borde de la aplicación, eso indica que el
margen es fijo. Cuando cambia el tamaño del explorador, la distancia entre ese borde del control y ese
borde de la aplicación se mantiene constante. En cambio, si se muestra una línea como un margen variable
que no se ajusta al borde de la aplicación, esto indica que el margen no es fijo y que la distancia entre ese
borde del control y ese borde de la aplicación puede cambiar. Por ejemplo, si los márgenes izquierdo y
superior de un control son fijos, el control mantendrá su posición con respecto a la esquina superior
izquierda de la aplicación cuando cambie el tamaño del explorador. Por otro lado, si los márgenes inferior y
derecho son fijos, el control cambiará de posición con respecto a la esquina superior izquierda de la
aplicación cuando cambie el tamaño del explorador. Si los márgenes contrarios, por ejemplo, el margen
inferior y el margen superior, son fijos, el control se ajustará cuando cambie el tamaño del explorador.
Para fijar o liberar los márgenes de un control
1. En Silverlight Designer, arrastre un control hasta la ubicación que desee.
Observe que en cada lado del control hay líneas o códigos auxiliares. Las líneas se ajustan desde el
borde del control al borde correspondiente del contenedor.
2. Para fijar un margen, muévase sobre un código auxiliar hasta que el puntero se convierta en un
dedo señalador.
3. Haga clic en el código auxiliar. El código auxiliar se expande para formar una línea de margen y se
fija el margen.
4. Para liberar un margen, muévase sobre una línea hasta que el puntero se convierta en un dedo
señalador.
5. Haga clic en la línea del margen. La línea se contrae en un código auxiliar y el margen de ese lado
se libera.
Líneas de la cuadrícula
Las líneas de la cuadrícula se pueden utilizar para alinear los controles de Silverlight Designer que se han
diseñado mediante el control contenedor Grid. Las líneas de la cuadrícula representan las divisiones entre
las filas y columnas de un Grid. Cuando los controles se colocan dentro de una fila, columna o celda de Grid,
los márgenes mostrados son relativos a los bordes de la fila, columna o celda, y las líneas de ajuste de Grid,
se pueden utilizar para alinear el control a los lados de la fila o columna.
Cuando se selecciona un control Grid en Silverlight Designer, aparecen carriles en los lados superior e
izquierdo. Puede utilizar los raíles para agregar, quitar o cambiar el tamaño de las filas y columnas de la
cuadrícula.
Nota:
Si la propiedad FlowDirection está establecida en RighToLeft, el raíl de las filas aparece en el lado derecho
de Grid.
Nota:
Si la fila no tiene contenido, el ajuste de tamaño automático hace que se contraiga a un alto de
tamaño cero. Esto puede provocar dificultades a medida que sigue diseñando el objeto Grid. Para
evitar este problema, agregue contenido a la fila antes de establecer el ajuste de tamaño
automático. También podrá usar la variación de tamaño proporcional mientras trabaje y cambiar a
Automático cuando termine.
8. Para salir sin seleccionar una opción de tamaño, presione ESC o mueva el puntero fuera de la barra
de tamaño.
Para establecer el ancho de una columna mediante el diseñador, siga los pasos anteriores pero mueva el
puntero sobre el raíl superior para activar la barra de tamaño.
Una aplicación basada en Silverlight entra en modo de pantalla completa cuando se establece la propiedad
IsFullScreen en true. En el momento de entrar en modo de pantalla completa, la aplicación muestra durante
unos instantes el mensaje "Presione ESC para salir del modo de pantalla completa". Este mensaje avisa al
usuario de que la aplicación está en modo de pantalla completa, y proporciona información sobre cómo
volver al modo incrustado.
Mensaje del modo de pantalla completa
En el ejemplo de código siguiente, se muestra cómo habilitar y deshabilitar el modo de pantalla completa
alternando el valor de la propiedad IsFullScreen.
Private WithEvents rootPage As Page = New Page()
Private WithEvents htmlContent As Content
Private Sub Application_Startup(ByVal o As Object, ByVal e As StartupEventArgs) Handles Me.Startup
Me.RootVisual = rootPage
htmlContent = Me.Host.Content
End Sub
Nota:
La iniciación por parte del usuario y los demás requisitos no se aplican a las aplicaciones de confianza. Para
obtener más información, vea la siguiente sección.
De forma predeterminada, solamente puede haber una aplicación a la vez en modo de pantalla completa.
Normalmente, una aplicación sale del modo de pantalla completa cuando el usuario pasa a otra aplicación.
Para configurar una aplicación basada en Silverlight de modo que permanezca en modo de pantalla
completa independientemente de si está activa o no, establezca la propiedad FullScreenOptions en
StaysFullScreenWhenUnfocused. De este modo, los usuarios podrán ver una aplicación en modo de pantalla
completa mientras interactúan con otras aplicaciones. Asimismo, podrán mostrar varias aplicaciones en
modo de pantalla completa.
Cuando una aplicación permanece en modo de pantalla completa mientras está inactiva, los usuarios
pueden cambiar a otras aplicaciones. Entre ellas se encuentra el explorador del host original o la ventana de
ejecución fuera del explorador, donde el complemento Silverlight incrustado mostrará un área vacía
mientras la aplicación esté en modo de pantalla completa.
En la mayoría de los casos, al pasar de nuevo a una aplicación en modo de pantalla completa, no se vuelve a
mostrar el mensaje referente al modo de pantalla completa. Esto significa que las aplicaciones
malintencionadas tienen una oportunidad más para suplantar la identidad de otras aplicaciones. Para
intentar evitarlo, el valor StaysFullScreenWhenUnfocused hace que la aplicación muestre un cuadro de
diálogo para el consentimiento del usuario antes de entrar en modo de pantalla completa. Si el usuario no
da su consentimiento, la aplicación utilizaŕa el comportamiento predeterminado del modo de pantalla
completa.
Este cuadro de diálogo incluye una casilla que permite a los usuarios guardar sus preferencias. Los usuarios
pueden modificar sus preferencias en Configuración de Microsoft Silverlight (Cuadro de diálogo).
Cuando una aplicación basada en Silverlight está en modo de pantalla completa, la mayoría de los eventos
de teclado están deshabilitados. Esta limitación de las acciones del teclado durante el modo de pantalla
completa es una característica de seguridad, dirigida a minimizar la posibilidad de que el usuario escriba
información imprevista. En modo de pantalla completa, las únicas entradas permitidas son las
correspondientes a las siguientes teclas:
FLECHA ARRIBA
FLECHA ABAJO
FLECHA IZQUIERDA
FLECHA DERECHA
BARRA ESPACIADORA
TAB
RE PÁG
AV PÁG
INICIO
FIN
ENTRAR
Silverlight no admite cuadros de diálogo en modo de pantalla completa. Esto incluye las clases
SaveFileDialog y OpenFileDialog, además de los cuadros de diálogo para el consentimiento del usuario. En
la mayoría de los casos, si se muestra un cuadro de diálogo en modo de pantalla completa, la aplicación se
revertirá al modo incrustado. Sin embargo, para evitar problemas en algunos exploradores, se debe salir del
modo de pantalla completa antes de utilizar una característica que muestra un cuadro de diálogo.
El modo de pantalla completa no admite operaciones de arrastrar y colocar ni entradas multitoque. Si una
aplicación utiliza estas características, se debe proporcionar al usuario información sobre las alternativas que
puede usar cuando la aplicación entra en modo de pantalla completa.
Modo de pantalla completa con aplicaciones de confianza
El mensaje referente al modo de pantalla completa, el requisito de la iniciación por parte del usuario, las
restricciones de teclado y de cuadro de diálogo no se aplican a las aplicaciones de confianza. Además, las
aplicaciones de confianza no muestran el cuadro de diálogo para el consentimiento del usuario cuando
usan el valor StaysFullScreenWhenUnfocused.
Dado que la tecla ESC no tiene ningún efecto integrado para las aplicaciones de confianza, se puede
utilizarla para fines propios. Para ello, sin embargo, es necesario implementar una alternativa para que los
usuarios puedan salir del modo de pantalla completa.
Tamaño de la aplicación en modo de pantalla completa
Cuando una aplicación basada en Silverlight está en modo de pantalla completa, su tamaño equivale a la
resolución actual de la pantalla. Sin embargo, los valores de las propiedades width y height del
complemento no se ven afectados al cambiar al modo de pantalla completa. Para determinar el tamaño real
de la aplicación en modo de pantalla completa, utilice las propiedades Content.ActualWidth y
Content.ActualHeight. En modo de pantalla completa, el valor de estas propiedades se establece en la
resolución actual de la pantalla.
Cuando una aplicación en modo de pantalla completa vuelve a pasar al modo incrustado, su tamaño
cambia a los valores de las propiedades width y height.
Características de rendimiento durante un cambio de modo
Cambiar entre el modo incrustado y el modo de pantalla completa tiene un efecto mínimo sobre el
rendimiento del contenido de la aplicación. En la mayoría de los casos, esto significa que la reproducción de
audio o vídeo se realiza sin problemas.
Nota:
Para obtener el máximo rendimiento, cuando la aplicación pase al modo de pantalla completa, oculte o
desconecte del árbol visual todos los objetos que no se representen en ese modo. Puede ocultar un objeto
estableciendo su propiedad Visibility en Collapsed.
Evento FullScreenChanged
El evento Content.FullScreenChanged se produce siempre que cambia la propiedad IsFullScreen. Este evento
se puede controlar para cambiar la interfaz de usuario en modo de pantalla completa.
Nota:
El evento Resized no se produce cuando la aplicación entra en modo de pantalla completa. Sin embargo,
normalmente este tipo de cambios de diseño se realizan en los controladores de los eventos
FullScreenChanged y Resized.
Notas de la versión
Silverlight 3 no admite las siguientes características que se han mencionado en este tema:
Propiedad FullScreenOptions.
Aplicaciones de confianza.
El control WebBrowser.
4.3. Entrada
En esta sección se describe la compatibilidad de Silverlight con los datos proporcionados por el usuario.
Silverlight proporciona un conjunto de eventos que permiten responder a las acciones del mouse, como
mover el mouse o hacer clic con el mouse. Silverlight también puede promover las entradas de lápiz y las
entradas multitoque a acciones de mouse equivalentes.
Evento Descripción
Se produce cuando el elemento de la interfaz de usuario pierde la captura del
LostMouseCapture
mouse.
Se produce cuando cambia la posición de las coordenadas del puntero del mouse
MouseMove
(o del lápiz).
MouseEnter Se produce cuando el mouse (o lápiz) entra en el área delimitadora de un objeto.
MouseLeave Se produce cuando el mouse (o lápiz) sale del área delimitadora de un objeto.
Se produce cuando se presiona el botón primario del mouse o cuando la punta
MouseLeftButtonDown
del lápiz toca la pantalla.
Se produce cuando se suelta el botón primario del mouse o cuando la punta del
MouseLeftButtonUp lápiz deja de tocar la pantalla, normalmente a continuación de un evento
MouseLeftButtonDown.
MouseRightButtonDown Se produce cuando se presiona el botón secundario del mouse.
MouseRightButtonUp Se produce cuando se suelta el botón secundario del mouse.
En este tema, no se explica cómo adjuntar un controlador de eventos del mouse mediante código. La
técnica para adjuntar controladores de eventos mediante código suele ser la misma para todos los eventos
de Silverlight o eventos del mouse.
En el ejemplo siguiente se muestra cómo recuperar la posición actual del puntero del mouse
correspondiente al objeto utilizando un desplazamiento relativo a otro objeto referenceObject del árbol.
Private Sub Rectangle_MouseLeftButtonDown(ByVal sender As Object, ByVal e As MouseButtonEventArgs)
' Return a Point object representing the x- and y-coordinates of the current mouse position
' relative to the reference object.
Dim pt As Point = e.GetPosition(referenceObject)
' Display the current mouse position on statusText, an existing textblock.
statusText.Text = pt.X & " : " & pt.Y
End Sub
Nota:
Si bien MouseLeave utiliza MouseEventArgs, no hay ninguna posición de mouse significativa disponible a
través de GetPosition para el evento MouseLeave.
La decisión de establecer o no la propiedad Handled en true representa una decisión consciente de detener
la ruta. El significado exacto de que un evento de entrada determinado esté controlado ("Handled") sigue
estando en sus manos en el contexto de la aplicación, pero su decisión de establecer o no Handled no tiene
ningún efecto tangible sobre el comportamiento de enrutamiento posterior de dicho evento de entrada en
concreto.
Eventos del mouse AddHandler y Already-Handled
Se puede utilizar una técnica especial para adjuntar controladores que pueden actuar sobre eventos ya
marcados como controlados. En esta técnica, se utiliza el método AddHandler para registrar un controlador,
en lugar de usar atributos XAML o una sintaxis específica del lenguaje para agregar un controlador, como
+= en C#. Esta técnica tiene como limitación que la API de AddHandler toma un parámetro de tipo
RoutedEvent que identifica el evento enrutado en cuestión. No todos los eventos enrutados de Silverlight
proporcionan un identificador de RoutedEvent, por lo que esta consideración determina qué eventos
enrutados se podrán controlar en el caso de Handled. Los eventos del mouse MouseLeftButtonDown,
MouseLeftButtonUp y MouseWheel tienen identificadores de evento enrutado como campos en UIElement.
Los demás eventos del mouse (MouseEnter, MouseLeave, MouseMove, MouseRightButtonDown,
MouseRightButtonUp) no tienen identificadores de evento enrutado en Silverlight.
Eventos MouseEnter y MouseLeave
Los eventos MouseEnter y MouseLeave no se enrutan. Estos eventos los generan y los controlan únicamente
los elementos en los que entra o de los que sale el puntero del mouse. Este diseño de eventos es igual que
en WPF y también se basa en el modelo de diseño del DOM HTML de Internet Explorer.
Si desea que los elementos primarios sepan que los elementos secundarios han recibido eventos
MouseEnter y MouseLeave, deberá configurarlo de modo que forme parte de su propia lógica de control o
de aplicación. Para los autores de controles, reemplazar OnMouseEnter o OnMouseLeave puede resultar útil
en este escenario.
LostMouseCapture es la última posición conocida y puede ser que estos datos no sean útiles para una
acción de la interfaz de usuario.
Además, no es un diseño robusto emparejar siempre una llamada a ReleaseMouseCapture al evento
MouseLeave en un elemento concreto de la interfaz de usuario que se va a usar como origen de captura. El
motivo es el siguiente: cuando LostMouseCapture notifica la última posición conocida del mouse, se genera
un evento MouseEnter y, a continuación, se generan otros eventos MouseEnter a medida que se mueve el
mouse. En lugar de llamar al método ReleaseMouseCapture al producirse el evento MouseLeave, se ha de
escuchar el evento LostMouseCapture.
Eventos que se producen al hacer clic con el botón secundario del mouse
Los eventos que se producen al hacer clic con el botón secundario del mouse son nuevos en Silverlight 4.
Para capturar estos eventos, el cliente debe ejecutar una plataforma capaz, por su diseño de hardware y de
sistema operativo, de generar una acción de entrada de hacer clic con el botón secundario del mouse. Los
datos de evento MouseButtonEventArgs no contienen información sobre el botón en el que se ha hecho
clic. Es responsabilidad del controlador responder a los eventos apropiados que denotan un clic con el
botón primario con respecto a los que denotan un clic con el botón secundario. Los eventos de clic con el
botón secundario son eventos enrutados, son similares a los eventos de clic con el botón primario pero no
comparten los datos de evento para la determinación de Handled ni se relacionan de ninguna otra manera
con las acciones de clic con el botón primario. Si el usuario presiona simultáneamente ambos botones del
mouse, se generan dos eventos independientes.
Doble clic
Silverlight no proporciona ningún evento designado para el doble clic de un botón del mouse. Le
corresponde al código de la aplicación determinar si los eventos de los botones del mouse constituyen un
doble clic, si los dos clics se han producido en un ámbito aceptable, etc. Normalmente, el código de una
aplicación usa un objeto Timer en el primer controlador del botón del mouse y, a continuación, comprueba
el temporizador en la llamada al siguiente controlador.
Arrastrar y colocar
Arrastrar y colocar es un comportamiento relacionado con el mouse, pero no se aborda en este tema.
La aplicación se implementa fuera del explorador, por lo que no hay ninguna página HTML de
hospedaje para controlar los eventos DOM.
El evento MouseWheel administrado admite estos dos casos. Por tanto, debe usar el evento MouseWheel
en lugar de eventos DOM siempre que sea posible. Esto es especialmente cierto si implementa o usa
controles con determinado control de eventos de rueda del mouse. El evento MouseWheel se enruta a
través de otros objetos administrados de la interfaz de usuario de Silverlight, se puede cancelar con la
propiedad Handled, y se integra con las plantillas de control y el modelo de estados visuales en general.
Debido a las dependencias de la plataforma, es posible que todavía desee usar el control del DOM HTML de
OnMouseWheel. Esto se describe con más detalle en "Dependencias de la plataforma", más adelante en
este tema.
Dependencias de la plataforma
El evento MouseWheel solo se genera y se puede controlar para las plataformas compatibles. Por ejemplo,
en Microsoft Windows, MouseWheel es compatible en Internet Explorer y Firefox, y en las aplicaciones con
ejecución fuera del explorador. Cualquier cliente y host de explorador que use un sistema operativo
Macintosh no genera el evento. En la tabla siguiente se enumeran varias plataformas y si se admite
MouseWheel.
Para procesar información de rueda del mouse para los clientes o situaciones que no generan MouseWheel,
se debe usar el control de eventos del DOM HTML para los eventos mouseWheel (el atributo
onMouseWheel especifica un controlador) que están disponibles en el scripting de cliente y el puente
HTML.
Hardware multitoque
El concepto de multitoque necesita dispositivos de hardware capaces de registrar la presión táctil que se
produce en una superficie. La superficie podría ser directamente la pantalla (como en un dispositivo Tablet
PC) o un dispositivo de entrada dedicado independiente (como una tableta gráfica). De éstos, el dispositivo
Tablet PC o dispositivos similares con sensibilidad táctil directamente en la pantalla son por lo general los
más pertinentes para Silverlight.
Requisitos de plataforma
La entrada multitoque necesita un entorno (dispositivo; plataforma y sistema operativo; aplicación host
como un explorador) que pueda difundir la entrada táctil a una aplicación individual, como una aplicación
basada en Silverlight.
Los dispositivos compatibles con la entrada multitoque son un mercado en evolución y los dispositivos
concretos no se tratan en este tema.
Windows 7 admite la entrada multitoque en el nivel del sistema operativo. Esto se admite en parte a través
de un mensaje (WM_TOUCH). En este nivel, el sistema operativo proporciona una promoción de mensajes
multitoque a mensajes del mouse. La promoción está presente de forma que los usuarios de entrada
multitoque puedan usar el toque y los gestos como sustitutos de movimientos del mouse o clics del mouse.
Esto es útil al interactuar con aplicaciones que quizás no estén preparadas para el toque y la aplicación
realiza todos sus procesamientos de entrada espacial a través de eventos del mouse y mensajes. Windows 7
también combina los mensajes cuando es necesario, por lo que las aplicaciones no tienen que procesar una
gran cantidad de mensajes intermedios que generan eventos incrementales.
La versión 8 de Internet Explorer como un host de explorador también reconoce la entrada multitoque.
Internet Explorer versión 8 reenvía los mensajes multitoque de plataforma a complementos como Silverlight
que se ejecutan dentro de Internet Explorer, por lo que las aplicaciones de Silverlight pueden interactuar
con la entrada multitoque.
Entrada multitoque para Silverlight (se muestra para el host IE8)
La entrada multitoque también se admite para Silverlight en las versiones actuales de hosts Firefox que se
ejecutan en Windows 7 y para las aplicaciones con ejecución fuera del explorador que se ejecutan en
Windows 7. Sin embargo, la entrada multitoque no se admite para las aplicaciones que se ejecutan en modo
de pantalla completa.
Registro para la entrada multitoque
Como parte de la arquitectura de plataforma más amplia para entradas multitoque, cada aplicación que
desee recibir mensajes multitoque debe registrar su HWND (la API táctil para Windows 7 incluye
RegisterTouchWindow con esta finalidad). El runtime de Silverlight 4 se ocupa de este paso de registro, y
registra Silverlight como un runtime y todas las aplicaciones que usen Silverlight como runtime. Por lo tanto,
generalmente no es necesario interactuar de forma directa con el código de plataforma para procesar la
entrada multitoque. Sin embargo, las características de interacción multitoque dentro de la API táctil para la
entrada multitoque de Windows 7 y Silverlight 4 son bastante concretas:
Silverlight 4 se registra para la entrada táctil sin formato, no gestos. Si entre sus requisitos se
incluyen los movimientos, debe procesar la entrada táctil en movimientos utilizando su propio
código de aplicación, dentro del contexto de Silverlight. Alternativamente, puede necesitar un
diseño de interoperación mayor para poder incluir un HWND independiente registrado para los
movimientos multitoque desde la plataforma y que interopere con una área de contenido de
Silverlight.
En general, Silverlight 4 promueve la entrada táctil sin formato a eventos del mouse. (Sin embargo,
se puede deshabilitar la promoción por marco táctil, como se describe en secciones posteriores de
este tema).
Dentro de un host, el host del explorador puede promover que ciertos gestos se conviertan en
eventos distintos de MouseDown, MouseMove y MouseUp.
Si desea procesar la entrada multitoque mediante la metáfora de gestos, el código debe controlar los
eventos de toque y usar la API expuesta bajo Silverlight 4 para procesarlos en gestos, usando o no la API de
plataforma para los gestos. Esto no es trivial.
API táctil
Una diferencia importante entre la entrada multitoque y otras técnicas de entrada admitidas en Silverlight
(mouse, teclado o lápiz) es que es preciso registrarse para los eventos multitoque en el nivel de aplicación, y
no se agregan controladores a elementos de entrada específicos (objetos UIElement ). Esto es coherente
con la metáfora de que Silverlight en su conjunto es la "aplicación" registrada con la plataforma.
Para asignar un controlador de eventos multitoque, se asigna un controlador para el evento
estático Touch.FrameReported. System.Windows.Input.Touch es una clase de servicio estática que
existe solamente para este fin con Touch.FrameReported como su única API.
El controlador que se escribe para Touch.FrameReported está basado en el delegado de
TouchFrameEventHandler.
En un diseño de interfaz de usuario típico, podría haber áreas de la interfaz de usuario dentro de las
cuales se admitirían acciones multitoque concretas y otras áreas donde sería mejor usar la
promoción a eventos del mouse y no necesariamente procesar las entradas como multitoque. Para
determinar dónde se encuentra el punto táctil principal, es posible que tenga que evaluar las
coordenadas generales con respecto a la ubicación del elemento que reconoce la entrada
multitoque, así como sus límites. Para obtener más información y código de ejemplo, vea
GetPrimaryTouchPoint.
Tal y como se ha mencionado previamente, quizás desee suspender la promoción a eventos del
mouse como parte de la lógica de TouchFrameEventHandler. Para ello, llame a
SuspendMousePromotionUntilTouchUp como una de las primeras operaciones.
Los mensajes de entrada táctil, tal y como se notifican a Silverlight 4, suelen combinarse como
marcos, que comienzan con un punto táctil "descendente" principal. A veces tan solo interesa el
primer punto táctil y la primera acción "ascendente", pero el marco puede contener otros puntos
táctiles y acciones de "movimiento". Para tener acceso a la colección completa de puntos de un
marco en sus controladores, llame a GetTouchPoints. Probablemente para un punto táctil
determinado la información más importante sea su Position.
Otras API exponen información que en la API de plataforma se encontraría en la estructura
TOUCHINPUT. Estos son algunos ejemplos de esa API: TouchFrameEventArgs.Timestamp;
TouchDevice.DirectlyOver; TouchPoint.Size; TouchPoint.TouchDevice. Dependiendo del escenario,
no siempre necesitaría este nivel de información.
Eventos de teclado
Silverlight proporciona los eventos de teclado que se describen en la tabla siguiente.
Evento Descripción
Se produce cuando se presiona una tecla mientras el foco se encuentra en el complemento (y
KeyDown
algún elemento interno).
Se produce cuando se suelta una tecla mientras el foco se encuentra en el complemento (y algún
KeyUp
elemento interno).
KeyUp. Estas teclas se pueden utilizar para iniciar acciones en la aplicación, incluso si se ejecuta en
modo de pantalla completa.
Todas las demás teclas no generan eventos KeyDown ni KeyUp, por lo que no se puede actuar
sobre las acciones de estas teclas.
Silverlight controla la tecla ESC, que devuelve la aplicaciónal modo incrustado.
Esta limitación de entradas de teclado en el modo de pantalla completa es una característica de seguridad.
Sin embargo, una aplicación de ejecución fuera del explorador que utiliza confianza elevada no tiene esta
restricción y puede controlar todos los eventos de tecla mientras se ejecuta en modo de pantalla completa.
Uso de KeyEventArgs
Todos los eventos de teclado utilizan KeyEventArgs para los datos de evento, y KeyEventArgs contiene las
propiedades siguientes:
Key
PlatformKeyCode
Handled
OriginalSource (heredada de RoutedEventArgs)
Key
El evento KeyDown se genera si se presiona una tecla (del mismo modo, se genera el evento KeyUp cuando
ésta se suelta). Normalmente, el usuario escucha los eventos para procesar un valor de tecla concreto. Para
determinar qué tecla se presiona o se libera, ha de comprobar el valor de Key en los datos del evento. Key
devuelve un valor de tecla portátil (un miembro de la enumeración Key) o devuelve Key.Unknown.
Si el valor de Key no es Unknown, el evento representa un solo y específico valor de tecla portátil, y se
puede comprobar comparándolo con los valores esperados del controlador para ver si este debe seguir
respondiendo.
Los códigos de tecla portátiles son un subconjunto común de todos los códigos de tecla posibles de las
plataformas compatibles de Silverlight. Por ejemplo, la pulsación de tecla 'v' se representa como un valor
Key.V de la propiedad Key.
PlatformKeyCode
Algunas pulsaciones de tecla no son portátiles. Un ejemplo es la tecla BLOQ DESPL en Microsoft Windows.
Si el valor de Key es Unknown, ello significa que se ha presionado o liberado una tecla, pero dicha tecla es
de una plataforma determinada. En este caso, se puede comprobar el valor de la propiedad
PlatformKeyCode. Esta propiedad devuelve un entero. El entero se debe evaluar en el contexto de lo que
dicho valor significa para una plataforma determinada y cómo asigna los códigos de tecla.
Nota:
En este tema no se aborda cómo determinar la plataforma (lo que podría ser necesario para interpretar el
valor de la propiedad PlatformKeyCode). Dependiendo del diseño global de la aplicación, se puede hacerlo
en el nivel de HTML o el nivel del host del explorador analizando los encabezados de las solicitudes HTTP de
la página HTML de hospedaje o estableciendo una variable en el momento de instalar una aplicación de
ejecución fuera del explorador. Dentro de la API administrada, Silverlight proporciona la clase
BrowserInformation, así como otros tipos en el espacio de nombres System.Windows.Browser que podrían
ser útiles para capturar información que también está disponible en el DOM HTML o en el host del
explorador.
Teclas modificadoras
Se considera que algunas pulsaciones de tecla son modificadoras. Se trata de teclas que normalmente se
presionan junto con otras. Las teclas modificadoras de todas las plataformas incluyen las teclas MAYÚS y
CTRL. Algunas teclas modificadoras son específicas de la plataforma.
Nota:
La tecla CTRL puede tener un nombre diferente en algunos teclados. En esta documentación, se usa la
cadena CTRL para identificar la tecla porque se corresponde con el valor Key.Ctrl en la API.
Normalmente, las teclas modificadoras se interpretan para comprobar si se mantiene presionada una tecla
modificadora mientras se recibe otro evento de tecla. Esto es porque la otra tecla y una tecla modificadora
representan una combinación de teclas de interés para la aplicación. En este caso, la información de la tecla
modificadora no se transmite como parte de los mismos datos de evento. En su lugar, se utiliza la clase de
utilidad Keyboard desde el interior de los controladores de eventos para comprobar los modificadores,
como parte del control del evento correspondiente al valor de tecla que se modifica potencialmente.
Para determinar qué modificadores se aplican, compruebe el valor de la propiedad Modifiers de la clase
estática Keyboard. Esta propiedad devuelve un valor de enumeración de marcador ModifierKeys. El valor es
un marcador porque se podrían presionar varios modificadores.
Sin embargo, independientemente de cómo se procesen las teclas modificadoras para otros eventos
correspondientes a teclas no modificadoras, una tecla modificadora genera sus propios eventos de tecla.
Puede decidir controlar estos eventos o llevar a cabo el seguimiento del estado propio de la tecla
modificadora, pero el uso del valor de Modifiers es generalmente más práctico.
Nota:
Se podría usar la tecla CTRL en combinación con un clic del mouse para generar un equivalente a entradas
mediante el botón secundario del mouse en las plataformas Macintosh.
En el ejemplo siguiente se muestra cómo implementar el controlador del evento KeyUp para el contenido
XAML correspondiente del ejemplo anterior.
Private Sub TopLevelKB(ByVal sender As Object, ByVal e As KeyEventArgs)
If Not (e.Key = Key.Unknown) Then
Dim fe As FrameworkElement = e.OriginalSource
Dim msg As String = "The key " & e.Key.ToString()
msg = msg & " was pressed while focus was on "
msg = msg & fe.Name
statusTextBlock.Text = msg
End If
End Sub
Controles y foco
Solo un elemento que sea una clase Control puede recibir el foco. Los elementos visuales más notables que,
por lo tanto, no pueden recibir el foco, son:
Paneles, como StackPanel o Grid
TextBlock
Objetos de texto alineado, como Run
Para que un control reciba el foco, debe cumplirse lo siguiente:
IsEnabled es true.
Visibility es Visible.
El foco no puede estar completamente fuera del área de contenido de Silverlight.
IsTabStop debe ser true.
Los controles que pueden recibir y presentar las acciones del teclado constituyen los casos más evidentes
para los que es importante recibir el foco. Esto se debe a que únicamente el elemento con el foco puede
generar los eventos KeyDown y KeyUp. Sin embargo, puede que haya otros controles diseñados para recibir
el foco con el fin de poder usar las teclas del teclado como activadores o aceleradores. Por ejemplo, un
control Button admite una característica que permite seleccionarlo recorriendo la secuencia de tabulación y
presionar la tecla BARRA ESPACIADORA para "hacer clic" en Button sin mover el mouse.
Como parte del comportamiento predeterminado, la mayoría de los controles de Silverlight proporciona un
estilo específico del foco que indica visualmente qué control tiene el foco. En WPF sin el modelo de estados
visuales, una propiedad FocusVisualStyle diferente proporcionaba este estilo. En Silverlight o cuando se usa
el modelo de estados visuales con WPF, usted proporciona estados con nombre que realizan los ajustes
necesarios en la apariencia visual del control. Esos estados se suelen denominar Focused o Unfocused, y se
aplican a veces a las partes de un control compuesto en lugar de a todo el árbol visual.
GotFocus y LostFocus
GotFocus se genera cada vez que el foco cambia de un control a otro dentro del área de contenido de
Silverlight, y también en caso de que una aplicación se inicie por primera vez y la primera vez que un control
recibe el foco. El control que recibe el foco genera GotFocus. El control que tenía el foco anteriormente
genera LostFocus.
Tanto GotFocus como LostFocus son eventos enrutados que se propagan. El escenario de la propagación
corresponde a la composición de controles. En el nivel de composición, el foco podría estar en un objeto
que sea una parte compuesta de un control mayor. El implementador del control compuesto podría desear
que el diseño del control realizara acciones que se apliquen con independencia de la parte del componente
que tenga el foco, o bien realizara acciones diferentes si el foco sale de la composición inmediata y se
desplaza a otro control.
Si utiliza controles existentes, generalmente interesan más los comportamientos de foco del control y no de
las partes que lo componen, ya que es el primer punto al que el usuario de controles puede asociar los
controladores de eventos sin tener que recurrir a la aplicación de una plantilla distinta al control. Sin
embargo, también puede comprobar los eventos LostFocus y GotFocus de propagación en los
contenedores para la composición de páginas más grandes: objetos tales como StackPanel o Grid, o
también el elemento raíz UserControl. Sin embargo, debido al comportamiento de propagación, puede
resultar útil comprobar el valor de OriginalSource en cada evento LostFocus y GotFocus. Puede hacerlo si
desea comprobar si el origen de ese evento de foco es pertinente a algo que se deba hacer con el objeto al
que está asociado el controlador. Puede que ese objeto esté por encima de OriginalSource en el árbol de
objetos.
Además, si va a crear un control, puede que le interesen los métodos de invalidación relacionados con
eventos OnGotFocus y OnLostFocus. Estos métodos proporcionan una manera de implementar el control
del evento como un método de clase, en lugar de como un controlador asociado para las instancias.
Los eventos de foco tienen una implementación asincrónica, lo que constituye una optimización de
rendimiento necesaria en Silverlight. Sin embargo, puede comprobar sincrónicamente el foco en el cuerpo
de un controlador llamando a FocusManager.GetFocusedElement.
Método Focus
La clase base Control proporciona un método Focus. Al llamar a este método mediante programación, se
intenta establecer el foco en el control donde se llama al método. Focus tiene un tipo de valor devuelto que
informa de si el intento se realiza correctamente. Las posibles razones de que se produzca un error incluyen
todos los puntos mencionados en Controles y foco anteriormente en este mismo tema. Si llama a Focus en
el control que ya tiene el foco, no se genera ningún evento, pero el método devuelve true igualmente para
que la llamada al método no se interprete como un error real al establecer el foco en el destino pretendido.
Secuencias de tabulación
Los controles que se representan en una interfaz de usuario se colocan en una secuencia de tabulación
predeterminada. La tecla TAB controla de una manera especial los controles a fin de habilitar esta
funcionalidad, de tal forma que el elemento que recibe la entrada de la tecla TAB pierde el foco y el control
siguiente de la secuencia obtiene foco; en este proceso se generan los eventos LostFocus y GotFocus
pertinentes. Si llama al método Focus, el foco podría salir del punto anterior de la secuencia de tabulación;
al presionar TAB el usuario va al control siguiente de la secuencia. El comportamiento es similar a presionar
MAYÚS+TAB, pero la secuencia de tabulación se recorre en dirección inversa. Para estar contenido en la
secuencia de tabulación, el control debe poder recibir el foco según los requisitos enumerados en Controles
y foco.
Los controles poseen las propiedades TabIndex y TabNavigation. Estas propiedades le permiten modificar la
secuencia de tabulación y el comportamiento predeterminados. TabIndex declara la secuencia y
TabNavigation declara el comportamiento para cualquier secuencia de tabulación anidada dentro del
control.
Los controles tienen una propiedad IsTabStop que se puede establecer. Algunas clases de controles, como
Label, se inicializan con IsTabStopfalse. Si IsTabStop es false, no puede establecer el foco en el control
mediante Focus, los usuarios no pueden enfocarlo y el control no recibe ningún evento de entrada de
teclado. Para un control como Label, todo ello es inherente al diseño.
En el caso de una aplicación hospedada en el explorador, la secuencia de tabulación del contenido de
Silverlight es una secuencia anidada dentro de la secuencia de tabulación del host del explorador. Los
usuarios pueden salir del área de contenido de Silverlight y enfocar otros elementos de la página HTML de
hospedaje, así como traer el foco a los controles de la interfaz de usuario de la aplicación de explorador de
hospedaje (por ejemplo, una barra de direcciones).
Automatización
El foco de los controles es pertinente para la accesibilidad y automatización de Silverlight.
Nota:
Si el destino es Silverlight 4, las pruebas de posicionamiento son también importantes para los eventos de
arrastrar y colocar, como DragEnter.
' Global variables used to keep track of the mouse position and whether the object is captured by the mouse.
Dim isMouseCaptured As Boolean
Dim mouseVerticalPosition As Double
Dim mouseHorizontalPosition As Double
4.4. Imprimir
A veces deseará agregar funciones de impresión a la aplicación de Silverlight y no confiar en las opciones de
impresión del explorador. Por ejemplo, quizás desee permitir al usuario imprimir un control de imagen que
contiene un mapa. La clase PrintDocument proporciona la función de impresión para una aplicación de
Silverlight. En este tema se describe cómo agregar funciones de impresión a sus aplicaciones de Silverlight y
contiene las siguientes secciones:
Dentro del cuadro de diálogo de impresión, el usuario puede seleccionar la configuración de impresora que
desee y, a continuación, hacer clic en Imprimir para continuar con la operación de impresión o en Cancelar
para cancelar la operación de impresión. En la ilustración siguiente se muestra un ejemplo del cuadro de
diálogo de impresión para Windows.
End Sub
<StackPanel x:Name="LayoutRoot">
<Button Margin="5" Width="200" Content="Click to print" x:Name="PrintButton"
Click="PrintButton_Click" />
<Image Width="600" Height="600" Source="RedmondMap.jpg" x:Name="mapImage"/>
</StackPanel>
Además de especificar UIElement, puede obtener el tamaño físico del área de impresión con la propiedad
PrintPageEventArgs.PrintableArea. Si UIElement supera PrintableArea, el contenido se recortará en los
límites de PrintableArea. Las dimensiones del área imprimible son en píxeles basándose en la configuración
de pantalla.
5. Controles
Silverlight proporciona una completa biblioteca de controles que admiten el desarrollo de interfaces de
usuario.
A
Proporciona un cuadro de texto para los datos proporcionados por el
SDK de
AutoCompleteBox usuario y una lista desplegable que contiene posibles coincidencias basadas
Silverlight
en la entrada del cuadro de texto.
B
Proporciona un borde, un fondo o ambos a otro control. Un borde puede Motor en tiempo
Border
contener un único elemento secundario. de ejecución
Proporciona un evento de clic para responder a los datos proporcionados por el Motor en tiempo
Button
usuario con un mouse, teclado, lápiz u otro dispositivo de entrada. de ejecución
C
Proporciona una interfaz de usuario gráfica que permite al usuario seleccionar
SDK de
Calendar una fecha. Muestra a la vez las fechas de un mes y proporciona la capacidad
Silverlight
de desplazarse de mes en mes o de cambiar a la vista de todo el año.
Proporciona una superficie para mostrar elementos secundarios en las Motor en
Canvas coordenadas concretas del lienzo. Un lienzo puede contener uno o varios tiempo de
objetos UIElement. ejecución
CheckBox Permite al usuario seleccionar (activar) una opción o cancelar su selección Motor en
D
Proporciona una forma flexible de mostrar una colección de datos en filas y
columnas. Los tipos de columnas integrados incluyen la columna de cuadros
de texto, la columna de casillas y la columna de plantilla para hospedar SDK de
DataGrid
contenido personalizado. El tipo de fila integrado incluye una sección de Silverlight
detalles desplegable que se puede utilizar para mostrar contenido adicional
debajo de los valores de celda.
Proporciona una interfaz de usuario para la paginación a través de una SDK de
DataPager
colección de datos que implementa IPagedCollectionView. Silverlight
Permite al usuario seleccionar una fecha escribiéndola en un control TextBox SDK de
DatePicker
o utilizando un control Calendar desplegable. Silverlight
Muestra una descripción y realiza el seguimiento del estado del error para un SDK de
DescriptionViewer
control asociado. Silverlight
F
Frame Admite la navegación a los controles Page. SDK de Silverlight
G
Proporciona una superficie compuesta de filas y columnas para mostrar
Motor en
elementos secundarios. Se definen las filas y columnas para un objeto Grid y, a
Grid tiempo de
continuación, se asignan los objetos a una fila o columna concreta de la
ejecución
cuadrícula. Opcionalmente, puede mostrar las líneas de la cuadrícula.
Permite al usuario redistribuir el espacio entre las filas o columnas de un control
Grid. Representa un elemento gráfico que el usuario puede agarrar y arrastrar. Las
SDK de
GridSplitter propiedades adjuntas que rigen su alineación y las propiedades de fila o columna
Silverlight
de Grid determinan la dirección y manera en las que GridSplitter distribuye el
espacio.
H
Representa un control que contiene una colección de elementos y un SDK de
HeaderedItemsControl
encabezado. Silverlight
Representa un control de botón que muestra un hipervínculo.
Motor en
Cuando se hace clic en él, HyperlinkButton permite al usuario visitar
HyperlinkButton tiempo de
una página web que pertenece a la misma aplicación web o que es
ejecución
externa a la aplicación actual.
I
Muestra una imagen en formato PNG o JPEG. El control Image muestra Motor en
Image imágenes indizadas con una profundidad de color de 1, 4 u 8 bits o imágenes tiempo de
en color verdadero con una profundidad de color de 24 ó 32 bits. ejecución
Proporciona una superficie de dibujo que admite las características de Tablet Motor en
InkPresenter PC. InkPresenter se deriva de Canvas y puede mostrar uno o más trazos y tiempo de
objetos UIElement. ejecución
L
Muestra una leyenda, el indicador de campo obligatorio y el indicador de error de SDK de
Label
validación para un control asociado. Silverlight
Contiene una colección de elementos. Puede rellenar el control enlazándolo a un
Motor en
origen de datos o mostrando elementos independientes. El cuadro de lista es un
ListBox tiempo de
control de elementos, lo que significa que puede rellenarlo con elementos que
ejecución
contengan texto u otros controles.
M
Hospeda contenido de audio o vídeo. Un control MediaElement Motor en
MediaElement proporciona una región rectangular que puede mostrar vídeo en su tiempo de
superficie o reproducir audio si no hay vídeo presente. ejecución
Permite al usuario abrir una imagen en varias resoluciones que se puede Motor en
MultiScaleImage escalar y se puede cambiar de posición para verla con detalle. tiempo de
MultiScaleImage es para su uso con la tecnología Deep Zoom. ejecución
O
Representa un cuadro de diálogo de archivos abierto que permite al Motor en tiempo de
OpenFileDialog
usuario seleccionar uno o varios archivos. ejecución
P
SDK de
Page Encapsula el contenido al que puede navegar un control Frame.
Silverlight
Se usa para escribir información confidencial o privada en un área de texto de Motor en
PasswordBox una sola línea sin ajuste. No se ve el texto real sino los caracteres que tiempo de
representan el contenido. ejecución
Superpone el contenido al contenido existente. Un control Popup resulta útil
Motor en
para mostrar temporalmente información que realiza una tarea determinada.
Popup tiempo de
Un control emergente siempre aparecerá encima del contenido existente, a
ejecución
menos que otro control emergente se abra encima de él.
Motor en
Indica el progreso de una operación. Este control se puede utilizar para mostrar
ProgressBar tiempo de
un progreso genérico o un progreso que cambia según un valor.
ejecución
R
Permite al usuario seleccionar una sola opción de un grupo de opciones. Los
controles RadioButton se agrupan colocándolos dentro de un elemento Motor en
RadioButton primario o estableciendo la propiedad GroupName de cada RadioButton en un tiempo de
grupo concreto. Cuando están agrupados, los controles RadioButton son ejecución
mutuamente excluyentes.
Representa un botón que genera su evento de clic repetidamente desde el
Motor en
momento en que se presiona el botón hasta que se suelta. Un control
RepeatButton tiempo de
RepeatButton contiene propiedades que especifican el retraso antes de que se
ejecución
repitan los clics y el intervalo entre los clics.
Motor en
Representa un control de edición de texto enriquecido que admite texto con
RichTextBox tiempo de
formato, hipervínculos, imágenes insertadas y otro contenido enriquecido.
ejecución
S
SaveFileDialog Proporciona un cuadro de diálogo que permite al usuario especificar Motor en
T
Proporciona una interfaz con fichas en la que mostrar elementos. Los elementos SDK de
TabControl
secundarios se hospedan en un control TabItem. Silverlight
Muestra pequeñas cantidades de contenido de texto. Puede establecer el
Motor en
contenido de TextBlock mediante la propiedad Text. Como alternativa, puede
TextBlock tiempo de
establecer la propiedad Inlines en una colección de objetos Inline, tales como los
ejecución
objetos Run o LineBreak.
Se usa para obtener datos proporcionados por el usuario o para mostrar texto. El
Motor en
control de cuadro de texto se utiliza generalmente para el texto que se puede
TextBox tiempo de
editar, aunque también puede configurarse como control de solo lectura. Los
ejecución
cuadros de texto pueden mostrar varias y ajustar el texto al tamaño del control.
Motor en
Proporciona información al usuario sobre un elemento de la interfaz de usuario
ToolTip tiempo de
mediante una ventana emergente.
ejecución
SDK de
TreeView Representa un control que muestra datos jerárquicos.
Silverlight
V
SDK de
ValidationSummary Muestra un resumen de los errores de validación en un formulario.
Silverlight
Motor en
Proporciona un control que puede ajustar o escalar su contenido
Viewbox tiempo de
para rellenar el espacio disponible.
ejecución
Proporciona un control de panel de pila que organiza el contenido Motor en
VirtualizingStackPanel que está visible en la pantalla, creando los elementos adicionales de tiempo de
la interfaz de usuario que sean necesarios. ejecución
W
Proporciona una superficie para mostrar contenido HTML cuando la Motor en tiempo de
WebBrowser
aplicación se hospeda fuera del explorador. ejecución
Controles de texto
Controles que muestran un elemento único
Controles que muestran un elemento único y un encabezado
Controles que muestran una colección de elementos
Controles que muestran una colección de elementos y un encabezado
Controles que muestran otros elementos de la interfaz de usuario
Información general
En la tabla siguiente se muestra una lista de muchos de los controles de Silverlight más comunes, con su
tipo de contenido y su propiedad de contenido correspondientes.
Controles de texto
Los controles de texto muestran contenido de tipo string. Hay tres tipos de controles de texto.
TextBlock
TextBox y PasswordBox
RichTextBox
Estos controles permiten elegir entre texto de solo lectura con varios formatos aplicados, texto editable con
un formato único y texto editable con formato enriquecido.
TextBlock
El control TextBlock hereda directamente de la clase FrameworkElement. Muestra texto de solo lectura al
que se puede dar formato de modo extensivo. Su contenido se establece con las propiedades Inlines o Text.
La propiedad Text toma como valor String. La propiedad Inlines toma como valor InlineCollection.
InlineCollection acepta objetos Inline. Inline es una clase abstracta; así pues, para rellenar la colección se
utilizan objetos Run o LineBreak que se derivan de Inline. Una ventaja de establecer la propiedad Inlines es
que se puede especificar la familia de fuentes, el estilo, el peso y el tamaño para cada objeto Inline de la
colección Inlines. Sin embargo, si desea utilizar la misma fuente o estilo de fuente para todo el texto de
TextBlock, la propiedad Text es la opción más fácil.
En el ejemplo siguiente se muestra cómo establecer el contenido de los objetos TextBlock mediante las
propiedades Inlines y Text en XAML y en código.
<TextBlock Margin="10" Text="TextBlock" />
...
<TextBlock Margin="10">
<Run FontFamily="Arial" FontSize="20">TextBlock</Run>
<LineBreak />
<Run FontFamily="Courier New" FontWeight="Bold" FontSize="14">using Inlines</Run>
</TextBlock>
TextBox y PasswordBox
La clase TextBox hereda de Control y muestra texto que el usuario puede modificar. El contenido de TextBox
se establece mediante la propiedad Text. El formato del texto mostrado se limita al formato que se aplica al
control, que es aplicable a todo el texto que contiene. La propiedad TextWrapping permite establecer el
ajuste del texto. El estilo de fuente, así como su grosor, tamaño y familia se especifican mediante las
propiedades FontStyle, FontWeight, FontSize y FontFamily, respectivamente. Los valores de las propiedades
se aplican a todo el texto mostrado en el control TextBox.
PasswordBox hereda de TextBox. Su contenido se establece mediante la propiedad Text. PasswordBox
permite una línea de texto única y oculta el texto con un símbolo. Esto permite que el usuario escriba datos
confidenciales, como su contraseña.
En el ejemplo de código siguiente se muestra cómo se establece la propiedad Text de un control TextBox en
XAML y en código.
<TextBox Margin="10" HorizontalAlignment="Left" Width="100"
Text="TextBox with a line of text that wraps."
FontFamily="Arial" TextWrapping="Wrap" />
RichTextBox
La clase RichTextBox hereda de Control y muestra texto enriquecido que el usuario puede editar. Establezca
el contenido de un control RichTextBox con la propiedad Blocks. La propiedad Blocks contiene una
colección de elementos Paragraph. Un elemento Paragraph puede contener muchos tipos de elementos,
incluyendo los siguientes:
Inline
InlineUIContainer , que puede contener objetos FrameworkElement, como Image o Button
Run
Span
Bold
Hyperlink
Italic
Underline
Nota:
El control TabItem forma parte del SDK de Silverlight y requiere la siguiente declaración de espacio de
nombres XAML:
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
<sdk:TabControl>
<sdk:TabItem Header="TabItem1" >
<sdk:TabItem.Content>
<StackPanel Orientation="Horizontal">
<Rectangle Width="10" Fill="Green" />
<TextBlock Margin="2" Text="TabItem1 Content" />
</StackPanel>
</sdk:TabItem.Content>
</sdk:TabItem>
<sdk:TabItem Content="TabItem 2 Content">
<sdk:TabItem.Header>
<StackPanel Orientation="Horizontal">
<Rectangle Width="10" Fill="Green" />
Propiedad Items
Puede rellenar directamente un control de elementos estableciendo su propiedad Items. La propiedad Items
es del tipo ItemCollection, que es una colección PresentationFrameworkCollection(Of T) genérica. También
puede agregar elementos a una colección existente mediante el método Add. No se pueden agregar
elementos a una colección creada mediante la propiedad ItemsSource. Al crear los contenedores de
elementos en XAML, se agregan elementos a la colección de elementos. En el ejemplo siguiente se muestra
cómo crear y agregar objetos ComboBoxItem a un control ComboBox en XAML y en código.
<ComboBox>
<ComboBox.Items>
<ComboBoxItem Content="Item 1" />
<ComboBoxItem Content="Item 2" />
<ComboBoxItem Content="Item 3" />
</ComboBox.Items>
</ComboBox>
Propiedad ItemsSource
La propiedad ItemsSource del control ItemsControl permite utilizar cualquier tipo que implemente
IEnumerable como contenido de ItemsControl. Normalmente, se utiliza ItemsSource para mostrar una
recolección de datos o enlazar un control ItemsControl a un objeto de colección. Al establecer la propiedad
ItemsSource, se crean automáticamente los contenedores de elementos para cada elemento de la colección.
En el ejemplo siguiente se muestra cómo establecer la propiedad ItemsSource en una colección de objetos
Uri mediante una combinación de XAML y código.
<ComboBox x:Name="UriBox1" />
También puede enlazar a una colección estableciendo la propiedad ItemsSource en un objeto Binding y
estableciendo DataContext para el control. En el ejemplo siguiente se muestra cómo establecer la propiedad
ItemsSource en un objeto Binding y la propiedad DataContext en la colección de identificadores URI
mediante una combinación de XAML y código.
<ComboBox ItemsSource="{Binding}" x:Name="UriBox2" />
AutoCompleteBox
AutoCompleteBox es un control especial que combina un cuadro de texto para los datos proporcionados
por el usuario y un control de elementos que se muestra en una lista desplegable. El control de elementos
contiene posibles coincidencias basadas en la entrada del cuadro de texto. Se agrega contenido a la parte
de texto del control mediante la propiedad Text y se agrega contenido a la lista desplegable mediante la
creación de un enlace a una lista con la propiedad ItemsSource.
DataGrid
DataGrid es útil para mostrar recolecciones de datos, pero no es un control de elementos. El control
DataGrid hereda directamente de la clase Control. Su contenido se establece estableciendo la propiedad
ItemsSource en una colección de IEnumerable o en Binding, que resulta parecido a un control de elementos.
Sin embargo, un control DataGrid no se puede rellenar manualmente como un control de elementos. Al
establecer ItemsSource en una colección de objetos, se crea automáticamente una fila para cada objeto de
la colección. Puede establecer AutoGenerateColumns en true a fin de generar automáticamente una
columna para cada propiedad del tipo de objeto. También puede especificar las columnas personalmente
con la propiedad Columns. Hay tipos diferentes de columnas que contienen tipos diferentes de contenido.
Nota:
El control DataGrid forma parte del SDK de Silverlight y requiere la siguiente declaración de espacio de
nombres:
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
En el ejemplo siguiente, se muestra cómo establecer la propiedad ItemsSource en una colección de objetos
Uri mediante una combinación de XAML y código. AutoGenerateColumns se establece en true, para que se
cree automáticamente una columna para cada propiedad pública de Uri.
<sdk:DataGrid x:Name="UriGrid1" AutoGenerateColumns="True" />
desplegable.
Presentación de la Motor en
Muestra cantidades pequeñas de texto de solo
información (solo TextBlock tiempo de
lectura.
lectura) ejecución
Motor en
Muestra el progreso actual de una operación al
ProgressBar tiempo de
usuario.
ejecución
Proporciona un control para mostrar o editar texto
Motor en enriquecido. Admite texto con formato,
RichTextBox tiempo de hipervínculos, imágenes y otro contenido
ejecución enriquecido. Se puede establecer como de solo
lectura.
Representa un control que proporciona un cuadro
de texto para los datos proporcionados por el
Presentación y SDK de
AutoCompleteBox usuario y una lista desplegable que contiene
edición de texto Silverlight
posibles coincidencias basadas en la entrada del
cuadro de texto.
Motor en Proporciona un control que permite al usuario
PasswordBox tiempo de escribir datos confidenciales, como una
ejecución contraseña.
Motor en
Proporciona un control para mostrar o editar
TextBox tiempo de
texto.
ejecución
Proporciona un control para mostrar o editar texto
Motor en
enriquecido. Admite texto con formato,
RichTextBox tiempo de
hipervínculos, imágenes y otro contenido
ejecución
enriquecido.
Muestra una colección de datos en filas y
Presentación de SDK de
DataGrid columnas. Puede cambiar el tipo de fila o columna
datos Silverlight
para adaptarlo a las necesidades de su aplicación.
Proporciona una interfaz de usuario para la
SDK de
DataPager paginación a través de una colección de datos que
Silverlight
implementa IPagedCollectionView.
Muestra datos jerárquicos en una estructura de
SDK de
TreeView árbol con elementos que se pueden expandir y
Silverlight
contraer.
Motor en
Presentación de
Image tiempo de Muestra una imagen.
gráficos y vídeo
ejecución
Motor en Permite al usuario abrir una imagen con varias
MultiScaleImage tiempo de resoluciones que se puede escalar o cambiar de
ejecución posición para verla con detalle.
Hospeda contenido de audio o vídeo. Proporciona
Motor en
una región rectangular que puede mostrar vídeo
MediaElement tiempo de
en su superficie o reproducir audio si no hay vídeo
ejecución
presente.
Motor en
Proporciona una superficie de dibujo que admite
InkPresenter tiempo de
las características de Tablet PC.
ejecución
Presentación HTML, Motor en Proporciona una superficie para mostrar contenido
ejecución fuera del WebBrowser tiempo de HTML cuando la aplicación se hospeda fuera del
explorador ejecución explorador.
Diseño y agrupación Motor en Proporciona un borde, un fondo o ambos a otro
Border
de elementos tiempo de control.
ejecución
Motor en Proporciona una superficie para mostrar
Canvas tiempo de elementos secundarios en las coordenadas
ejecución concretas del lienzo.
Motor en
Representa un control con una sola parte de
ContentControl tiempo de
contenido.
ejecución
Proporciona una superficie compuesta de filas y
Motor en columnas para mostrar elementos secundarios. Se
Grid tiempo de definen las filas y columnas para una cuadrícula y,
ejecución a continuación, se asignan los objetos a una fila o
columna concreta de la cuadrícula.
SDK de Permite al usuario cambiar el tamaño de las
GridSplitter
Silverlight columnas o filas de un control Grid.
Motor en Proporciona una superficie para mostrar
StackPanel tiempo de elementos secundarios en una línea en sentido
ejecución horizontal o vertical.
Motor en Proporciona un control que puede ajustar o
Viewbox tiempo de escalar su contenido para rellenar el espacio
ejecución disponible.
Proporciona un control de panel de pila que
Motor en
organiza el contenido que está visible en la
VirtualizingStackPanel tiempo de
pantalla, creando los elementos adicionales de la
ejecución
interfaz de usuario que sean necesarios.
Representa un control que proporciona una barra
Motor en
de desplazamiento con un control de posición
ScrollBar tiempo de
(Thumb) deslizante cuya posición corresponde a
ejecución
un valor.
Motor en
Proporciona una superficie que se puede
ScrollViewer tiempo de
desplazar para mostrar un elemento secundario.
ejecución
Proporciona una interfaz con fichas en la que
SDK de
TabControl mostrar elementos. Los elementos secundarios se
Silverlight
hospedan en un control TabItem.
SDK de Muestra una descripción y realiza el seguimiento
Ayuda del usuario DescriptionViewer
Silverlight del estado del error para un control asociado.
Muestra una leyenda, el indicador de campo
SDK de
Label obligatorio y el indicador de error de validación
Silverlight
para un control asociado.
Motor en Proporciona información al usuario sobre un
ToolTip tiempo de elemento de la interfaz de usuario mediante una
ejecución ventana emergente.
SDK de Muestra un resumen de los errores de validación
ValidationSummary
Silverlight en un formulario.
SDK de
Navegación Frame Admite la navegación a los controles Page.
Silverlight
SDK de Encapsula el contenido al que puede navegar un
Page
Silverlight control Frame.
Motor en
Ventanas y cuadros Permite al usuario seleccionar uno o más archivos
OpenFileDialog tiempo de
de diálogo del sistema de archivos.
ejecución
Motor en
Permite al usuario especificar opciones para
SaveFileDialog tiempo de
guardar un archivo.
ejecución
Se construye el control.
O bien
2. Seleccione Propiedades.
3. En la ventana Propiedades, busque la propiedad que desee establecer y especifique el nuevo valor.
En la ilustración siguiente, se muestra un ejemplo de la ventana Propiedades.
En el ejemplo siguiente, se muestra cómo establecer mediante XAML propiedades que cambian la
apariencia de un botón. Las propiedades utilizadas en este ejemplo se aplican a muchos controles
de Silverlight.
<Button Margin="5" Height="50" Width="100" Background="Blue" Content="Click Me!" x:Name="button2" />
1. Cree un estilo como un recurso siguiendo los pasos descritos en el procedimiento anterior.
2. Seleccione el control al que desee aplicar el estilo.
3. Abra la ventana Propiedades y busque la propiedad Style.
4. Haga clic en la columna de valores a la derecha para que se abra el editor de recursos de
propiedad.
5. Expanda la sección Local y seleccione el estilo en la lista.
Se agrega al control una propiedad Style junto con una Extensión de marcado StaticResource
mediante XAML.
Los valores de propiedad y los estilos permiten cambiar solo algunos aspectos de la apariencia de un
control. Para cambiar completamente la apariencia y el comportamiento de un control, es preciso usar su
plantilla. El objeto ControlTemplate se define en XAML, ya sea de forma insertada o en un archivo
independiente, y contiene la apariencia visual y el comportamiento de un control. Para cambiar la plantilla
de un control, se establece la propiedad Template en XAML al crear un estilo. La mayoría de los controles
tienen una plantilla predeterminada. Se puede reemplazar la plantilla predeterminada de un control o se
puede modificar la plantilla para agregar, reorganizar o eliminar determinados elementos de un control.
3. Haga doble clic en el evento que desee controlar para crear un nuevo controlador de eventos.
Se crea el controlador de eventos para el control. Se abre el archivo de código subyacente y el
cursor se coloca en el controlador de eventos. En los proyectos de Visual C#, se agrega al archivo
XAML un atributo que especifica el controlador de eventos. En los proyectos de Visual Basic, no se
modifica el archivo XAML.
Para crear un controlador de eventos en el editor de XAML
1. En la vista XAML, seleccione el control para el que desee crear un controlador de eventos.
2. En la etiqueta de apertura del elemento, empiece a escribir el nombre del evento que desee
controlar, por ejemplo, el evento Click o MouseEnter.
Cuando empiece a escribir el nombre del evento, aparecerá una ventana de IntelliSense con los
eventos disponibles, tal y como se muestra en la ilustración siguiente.
5.5.2. DataGrid
El control DataGrid proporciona una forma flexible de mostrar una colección de datos en filas y columnas.
Los tipos de columnas integrados incluyen la columna de texto, la columna de casillas y la columna de
plantilla para hospedar contenido personalizado. El tipo de fila integrado incluye una sección de detalles
desplegable que se puede utilizar para mostrar contenido adicional debajo de los valores de celda.
El control DataGrid admite las opciones de formato de tabla comunes, como los fondos de fila alternos y la
capacidad de mostrar u ocultar encabezados, líneas de cuadrícula y barras de desplazamiento. Además, el
control proporciona varias propiedades de estilo y plantilla que puede usar para cambiar por completo la
apariencia del control y de sus filas, columnas, celdas y encabezados de fila o columna.
En los temas de esta sección se describen los conceptos y las técnicas adicionales que puede usar para crear
características del control DataGrid en las aplicaciones.
Nota:
En un equipo Macintosh, use la tecla Comando en lugar de la tecla CTRL.
Tecla o
combinación de Descripción
teclas
Mueve el foco a la celda que se encuentra directamente debajo de la celda actual. Si el
FLECHA ABAJO
foco está en la última fila, al presionar la FLECHA ABAJO, no sucede nada.
Mueve el foco a la celda que se encuentra directamente encima de la celda actual. Si el
FLECHA ARRIBA
foco está en la primera fila, al presionar la FLECHA ARRIBA, no sucede nada.
Mueve el foco a la celda anterior de la fila. Si el foco está en la primera celda de la fila, al
FLECHA
presionar la FLECHA IZQUIERDA, no sucede nada. Si el foco se encuentra en un
IZQUIERDA
encabezado de grupo de filas, al presionar la FLECHA IZQUIERDA, se contrae el grupo.
Mueve el foco a la siguiente celda de la fila. Si el foco está en la última celda de la fila, al
FLECHA
presionar la FLECHA DERECHA, no sucede nada. Si el foco se encuentra en un encabezado
DERECHA
de grupo de filas, al presionar la FLECHA DERECHA, se expande el grupo.
INICIO Mueve el foco a la primera celda de la fila actual.
FIN Mueve el foco a la última celda de la fila actual.
Desplaza el control hacia abajo por el número de filas que se muestran. Mueve el foco
AV PÁG hasta la última fila mostrada sin cambiar las columnas. Si la última fila se muestra solo
parcialmente, desplaza la cuadrícula de modo que se muestre totalmente la última fila.
Desplaza el control hacia arriba por el número de filas que se muestran. Desplaza el foco
RE PÁG a la primera fila mostrada sin cambiar las columnas. Si la primera fila se muestra solo
parcialmente, desplaza la cuadrícula de modo que se muestre totalmente la primera fila.
Si la celda actual está en modo de edición, mueve el foco a la celda siguiente de la fila
actual. Si el foco ya está en la última celda de la fila, confirma los cambios realizados y
mueve el foco a la primera celda de la siguiente fila. Si el foco está en la última celda del
control, desplaza el foco al siguiente control en el orden de tabulación del contenedor
TAB
primario.
actual. Si el foco ya está en la primera celda de la fila, confirma los cambios realizados y
mueve el foco a la última celda de la fila anterior. Si el foco está en la primera celda del
control, desplaza el foco al control anterior en el orden de tabulación del contenedor
primario.
Teclas de selección
Si el valor de la propiedad SelectionMode se establece en Extended, el comportamiento de navegación no
cambia, pero si se navega con el teclado y al mismo tiempo se presiona la tecla MAYÚS (incluida la
combinación de teclas CTRL+MAYÚS), se modifica una selección de varias filas. Antes de comenzar la
navegación, el control marca la fila actual como fila delimitadora. Cuando se navega presionando la tecla
MAYÚS, la selección incluye todas las filas comprendidas entre la fila delimitadora y la fila actual.
Las siguientes teclas de selección modifican una selección de varias filas.
MAYÚS+FLECHA ABAJO
MAYÚS+FLECHA ARRIBA
MAYÚS+FLECHA IZQUIERDA
MAYÚS+FLECHA DERECHA
MAYÚS+INICIO
MAYÚS+FIN
MAYÚS+AV PÁG
MAYÚS+RE PÁG
CTRL+MAYÚS+FLECHA ABAJO
CTRL+MAYÚS+FLECHA ARRIBA
CTRL+MAYÚS+FLECHA IZQUIERDA
CTRL+MAYÚS+FLECHA DERECHA
CTRL+MAYÚS+INICIO
CTRL+MAYÚS+FIN
CTRL+MAYÚS+AV PÁG
CTRL+MAYÚS+RE PÁG
Nota:
Al hacer clic en una celda con el botón primario del mouse, siempre se cambia la celda actual. En Silverlight,
cuando se hace clic con el botón secundario del mouse, siempre se abre el menú contextual Configuración
de Silverlight.
Acción del mouse Descripción
Hacer clic en una fila no
La fila en la que se ha hecho clic se convierte en la fila actual.
seleccionada
Hacer clic en una celda de
Coloca la celda en la que se ha hecho clic en modo de edición.
la fila actual
Si el valor de la propiedad DataGrid.CanUserReorderColumns es true y el valor
Arrastrar una celda de
de la propiedad DataGridColumn.CanUserReorder es true para la columna
encabezado de columna
actual, mueve la columna de modo que se pueda colocar en la nueva posición.
Arrastrar una línea de Si el valor de la propiedad DataGrid.CanUserResizeColumns es true y el valor de
separación de encabezados la propiedad DataGridColumn.CanUserResize es true para la columna actual,
de columna cambia el tamaño de la columna.
Si el valor de la propiedad DataGrid.CanUserSortColumns es true y el valor de la
propiedad DataGridColumn.CanUserSort es true para la columna actual, ordena
la columna.
Hacer clic en una celda de Al hacer clic en el encabezado de una columna que ya está ordenada, se
encabezado de columna invertirá la dirección de ordenación de esa columna.
Ejemplo
En el ejemplo de código siguiente se crea una List(Of T) de objetos Task y la lista de tareas se muestra en
una DataGrid denominada dataGrid1. DataGrid es de solo lectura, pero muestra una sección de detalles de
fila que permite la edición. La sección de detalles de fila se enlaza al mismo DataContext que DataGridRow.
Para que muestren los cambios hechos en los datos de origen en la sección de detalles de fila que se va a
mostrar en DataGridRow, la clase Task implementa la interfaz INotifyPropertyChanged. También se
proporciona una interfaz de usuario para establecer las opciones de los detalles de fila.
<UserControl x:Class="DGRowDetails.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">
<ScrollViewer VerticalScrollBarVisibility="Auto" BorderThickness="0" Padding="0">
<StackPanel x:Name="LayoutRoot" Background="White" Margin="5">
<StackPanel Margin="0,0,0,5">
<StackPanel Orientation="Horizontal">
<Border BorderBrush="Black" BorderThickness="1" Padding="3" Width="180">
<StackPanel>
<TextBlock Text="Row Details Visibility" FontSize="12"/>
<ComboBox SelectionChanged="cbRowDetailsVis_SelectionChanged">
<ComboBoxItem Content="Selected Row (Default)" IsSelected="True" />
<ComboBoxItem Content="All"/>
<ComboBoxItem Content="None"/>
</ComboBox>
<CheckBox Content="Freeze Row Details" Margin="0,3,0,0"
Checked="cbFreezeRowDetails_Changed"
Unchecked="cbFreezeRowDetails_Changed" />
</StackPanel>
</Border>
</StackPanel>
</StackPanel>
<sdk:DataGrid x:Name="dataGrid1" Height="400" IsReadOnly="True" >
<sdk:DataGrid.RowDetailsTemplate>
<!-- Begin row details section. -->
<DataTemplate>
<Border BorderBrush="Black" BorderThickness="1" Background="Tan">
<StackPanel Orientation="Horizontal">
<StackPanel>
<StackPanel Orientation="Horizontal">
<!-- Controls are bound to Task properties. -->
<TextBlock FontSize="16" Foreground="MidnightBlue" Text="{Binding Name}"
Margin="0,0,10,0" VerticalAlignment="Bottom" />
<TextBlock FontSize="12" Text="Due Date: " VerticalAlignment="Bottom"/>
<sdk:DatePicker SelectedDate="{Binding DueDate, Mode=TwoWay}" VerticalAlignment="Bottom" />
<TextBlock FontSize="12" Text=" Complete:" VerticalAlignment="Bottom" />
<CheckBox IsChecked="{Binding Complete, Mode=TwoWay}"
VerticalAlignment="Center" />
</StackPanel>
<TextBlock FontSize="12" Text="Notes: " />
<TextBox FontSize="12" Text="{Binding Notes, Mode=TwoWay}"
Width="420" TextWrapping="Wrap"/>
</StackPanel>
</StackPanel>
</Border>
</DataTemplate>
<!-- End row details section. -->
</sdk:DataGrid.RowDetailsTemplate>
</sdk:DataGrid>
' Generate some task data and add it to the task list.
For index = 1 To itemsCount
taskList.Add(New Task() With _
{.Name = "Task " & index.ToString(), _
.DueDate = Date.Now.AddDays(index), _
.Complete = (index Mod 3 = 0), _
.Notes = "Task " & index.ToString() & " is due on " & Date.Now.AddDays(index) & ". Lorum ipsum..." _
})
Next
Me.dataGrid1.ItemsSource = taskList
End Sub
' Set the row details visibility to the option selected in the combo box.
Private Sub cbRowDetailsVis_SelectionChanged(ByVal sender As System.Object, ByVal e As
System.Windows.Controls.SelectionChangedEventArgs)
Dim cb As ComboBox = sender
Dim cbi As ComboBoxItem = cb.SelectedItem
If Me.dataGrid1 IsNot Nothing Then
If cbi.Content.ToString() = "Selected Row (Default)" Then
Me.dataGrid1.RowDetailsVisibilityMode = DataGridRowDetailsVisibilityMode.VisibleWhenSelected
ElseIf cbi.Content.ToString() = "None" Then
Me.dataGrid1.RowDetailsVisibilityMode = DataGridRowDetailsVisibilityMode.Collapsed
ElseIf cbi.Content.ToString() = "All" Then
Me.dataGrid1.RowDetailsVisibilityMode = DataGridRowDetailsVisibilityMode.Visible
End If
End If
End Sub
' Freeze the row details if the check box is checked.
Private Sub cbFreezeRowDetails_Changed(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
Dim cb As CheckBox = sender
If Me.dataGrid1 IsNot Nothing Then
Me.dataGrid1.AreRowDetailsFrozen = cb.IsChecked
End If
End Sub
End Class
Imports System.ComponentModel
Ejemplo
En el ejemplo de código siguiente se crea una List(Of T) de objetos Task y la lista de tareas se muestra en
una DataGrid denominada dataGrid1. En el controlador de eventos AutoGeneratingColumn de dataGrid1, se
realizan las personalizaciones siguientes.
El encabezado Header de la columna 'Name' se modifica por 'Task'.
La columna DueDate generada automáticamente se reemplaza por un objeto DataGridTemplate
Column personalizado.
Se cancela la generación automática de todas las columnas que muestran datos de tipo Boolean.
<UserControl
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
x:Class="DGAutoGenColumn.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<UserControl.Resources>
<DataTemplate x:Key="dueDateCellTemplate">
<TextBlock
Text="{Binding DueDate}"
Margin="5,4,5,4" />
</DataTemplate>
<DataTemplate x:Key="dueDateCellEditingTemplate">
<sdk:DatePicker
SelectedDate="{Binding DueDate, Mode=TwoWay}" />
</DataTemplate>
</UserControl.Resources>
<StackPanel x:Name="LayoutRoot" Background="White" Margin="5">
<TextBlock Text="Column AutoGeneration" Foreground="#FF5C9AC9"
FontSize="18" FontFamily="Verdana" FontWeight="Bold" />
<sdk:DataGrid x:Name="dataGrid1"
AutoGenerateColumns="True"
AutoGeneratingColumn="dataGrid1_AutoGeneratingColumn" />
</StackPanel>
</UserControl>
End If
' Cancel AutoGeneration of all boolean columns.
If e.PropertyType Is GetType(Boolean) Then
e.Cancel = True
End If
End Sub
End Class
Nota:
Los objetos de la colección deben implementar la interfaz INotifyPropertyChanged y la interfaz
IEditableObject para que DataGrid responda correctamente a los cambios y ediciones de
propiedad.
Cuando los elementos se agrupan en DataGrid, cada grupo tiene un encabezado. Puede cambiar el aspecto
de DataGridRowGroupHeader definiendo un Style personalizado y agregándolo a la colección
RowGroupHeaderStyles. Si dispone de varios niveles de agrupación, puede aplicar estilos diferentes a cada
nivel de grupo. Los estilos se aplican en el orden en que se definen. Por ejemplo, si define dos estilos, el
primero se aplicará a los grupos de fila de nivel superior. El segundo estilo se aplicará a todos los grupos de
Cuando se agrupan los elementos en DataGrid, se pueden usar los métodos siguientes para contraer y
expandir manualmente los grupos:
Haga clic en la flecha de contraer o expandir en el encabezado del grupo de la filas.
Haga doble clic en cualquier parte del encabezado de grupo.
Presione la tecla de dirección izquierda para contraer el grupo y la tecla de dirección derecha para
expandirlo cuando el encabezado tiene el foco.
Para contraer o expandir un grupo mediante programación, pase CollectionViewGroup al método
CollapseRowGroup o ExpandRowGroup.
Para contraer o expandir grupos de filas
1. Obtenga el objeto CollectionViewGroup que representa el grupo que se va a contraer o expandir.
Nota:
Puede obtener el objeto CollectionViewGroup mediante la colección Groups. Alternativamente,
puede usar el método GetGroupFromItem para obtener un objeto CollectionViewGroup individual,
como se muestra aquí.
Ejemplo
En el ejemplo siguiente se muestra cómo agrupar, ordenar y filtrar los datos en un objeto
PagedCollectionView, además de cómo mostrar los datos agrupados, ordenados y filtrados en un control
DataGrid. Una colección de objetos Task se encapsula en un objeto PagedCollectionView.
PagedCollectionView se usa como ItemsSource de DataGrid. La agrupación, ordenación y filtrado se realizan
en PagedCollectionView y se muestran en la interfaz de usuario de DataGrid.
<UserControl x:Class="DataGridGrouping.MainPage"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
Imports System.Collections.ObjectModel
Imports System.ComponentModel
Imports System.Windows.Data
Requisitos previos
Necesita los componentes siguientes para completar este tutorial:
Silverlight 4.
Silverlight 4 Tools para Visual Studio 2010.
Visual Studio 2010.
Este código controla los eventos de cambio para los controles de interfaz de usuario de opciones
de DataGrid que agregó en la sección anterior. Cuando se modifica una opción, se establece la
propiedad DataGrid correspondiente.
' READ ONLY
Private Sub cbReadOnly_Changed(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
Dim cb As CheckBox = sender
If Me.dataGrid1 IsNot Nothing Then
Me.dataGrid1.IsReadOnly = cb.IsChecked
End If
End Sub
' FREEZE COLUMN
Private Sub cbFreezeColumn_Changed(ByVal sender As System.Object, ByVal e As
System.Windows.RoutedEventArgs)
Dim cb As CheckBox = sender
If Me.dataGrid1 IsNot Nothing Then
If cb.IsChecked = True Then
Me.dataGrid1.FrozenColumnCount = 1
ElseIf cb.IsChecked = False Then
Me.dataGrid1.FrozenColumnCount = 0
End If
End If
End Sub
' HIDE COLUMN
Private Sub cbHideColumn_Changed(ByVal sender As System.Object, ByVal e As
System.Windows.RoutedEventArgs)
Dim cb As CheckBox = sender
If Me.dataGrid1 IsNot Nothing Then
If cb.IsChecked = True Then
Me.dataGrid1.Columns(0).Visibility = Windows.Visibility.Collapsed
ElseIf cb.IsChecked = False Then
Me.dataGrid1.Columns(0).Visibility = Windows.Visibility.Visible
End If
End If
End Sub
' SELECTION MODE
Private Sub cbSelectionMode_Changed(ByVal sender As System.Object, ByVal e As
System.Windows.RoutedEventArgs)
Dim cb As CheckBox = sender
If Me.dataGrid1 IsNot Nothing Then
If cb.IsChecked = True Then
Me.dataGrid1.SelectionMode = DataGridSelectionMode.Single
ElseIf cb.IsChecked = False Then
Me.dataGrid1.SelectionMode = DataGridSelectionMode.Extended
End If
End If
End Sub
' COLUMN OPTIONS
Private Sub cbColReorder_Changed(ByVal sender As System.Object, ByVal e As
System.Windows.RoutedEventArgs)
Dim cb As CheckBox = sender
If Me.dataGrid1 IsNot Nothing Then
Me.dataGrid1.CanUserReorderColumns = cb.IsChecked
End If
End Sub
Private Sub cbColResize_Changed(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
Dim cb As CheckBox = sender
If Me.dataGrid1 IsNot Nothing Then
Me.dataGrid1.CanUserResizeColumns = cb.IsChecked
End If
End Sub
Private Sub cbColSort_Changed(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
Dim cb As CheckBox = sender
If Me.dataGrid1 IsNot Nothing Then
Me.dataGrid1.CanUserSortColumns = cb.IsChecked
End If
End Sub
' SCROLL BARS VISIBILITY
Private Sub cbVerticalScroll_Changed(ByVal sender As System.Object, ByVal e As
System.Windows.RoutedEventArgs)
Dim cb As CheckBox = sender
If Me.dataGrid1 IsNot Nothing Then
If cb.IsChecked = True Then
Me.dataGrid1.VerticalScrollBarVisibility = ScrollBarVisibility.Visible
ElseIf cb.IsChecked = False Then
Me.dataGrid1.VerticalScrollBarVisibility = ScrollBarVisibility.Hidden
Else
Me.dataGrid1.VerticalScrollBarVisibility = ScrollBarVisibility.Auto
Pasos siguientes
Normalmente, las propiedades de DataGrid se establecen en XAML si no tienen que establecerse
dinámicamente en tiempo de ejecución. Si desea obtener la sintaxis XAML para establecer una propiedad,
vea la sección Uso de atributos XAML de la documentación de la propiedad de DataGrid.
También puede personalizar un control DataGrid aplicando estilos y plantillas al mismo. Los estilos y
plantillas permiten personalizar el control aún más que estableciendo propiedades.
Dimensionar DataGrid
Precauciones cuando se utiliza el tamaño automático
De forma predeterminada, las propiedades Width y Height de DataGrid se establecen en Double.NaN
("Auto" en XAML) y DataGrid se ajustará al tamaño de su contenido.
Cuando se coloca dentro de un contenedor que no restringe el tamaño de sus elementos secundarios,
como Canvas o StackPanel, DataGrid se expandirá más allá de los límites visibles del contenedor y las barras
de desplazamiento no se mostrarán. Esta condición tiene implicaciones de utilidad y rendimiento.
Cuando se enlaza un conjunto de datos, si Height de DataGrid no se restringe, continuará agregando una
fila para cada elemento de datos en el conjunto de datos enlazado. Esto puede hacer que DataGrid crezca
fuera de los límites visibles de la aplicación cuando se agreguen filas. DataGrid no mostrará las barras de
desplazamiento en este caso porque Height continuará creciendo para alojar las nuevas filas.
Se crea un objeto para cada fila de DataGrid. Si está trabajando con un conjunto de datos grande y permite
que DataGrid se dimensione automáticamente, la creación de un número grande de objetos puede afectar
al rendimiento de la aplicación.
Para evitar estos problemas al trabajar con conjuntos de datos grandes, se recomienda que establezca
Height de DataGrid específicamente o que lo coloque en un contenedor que restrinja su Height, por
ejemplo, Grid. Cuando Height se restringe, DataGrid creará solo las filas que se ajusten a su Height
especificado y reciclará según sea necesario esas filas para mostrar los nuevos datos.
Establecer el tamaño de DataGrid
DataGrid se puede establecer para que se dimensione dentro de los límites especificados automáticamente
o DataGrid se puede establecer en un tamaño concreto. En la siguiente lista se muestran las propiedades
que pueden establecerse para controlar el tamaño de DataGrid.
Propiedad Descripción
Height Establece un alto concreto para DataGrid.
Establece el límite superior para el alto de DataGrid. DataGrid crecerá verticalmente hasta que
MaxHeight
llegue a este alto.
Establece el límite inferior para el alto de DataGrid. DataGrid disminuirá verticalmente hasta que
MinHeight
llegue a este alto.
Width Establece un ancho concreto para DataGrid.
Establece el límite superior para el ancho de DataGrid. DataGrid crecerá horizontalmente hasta
MaxWidth
que llegue a este ancho.
Establece el límite inferior para el ancho de DataGrid. DataGrid disminuirá horizontalmente hasta
MinWidth
que llegue a este ancho.
Nombre Descripción
El modo de ajuste de tamaño automático predeterminado ajusta el tamaño de las columnas
Auto
de DataGrid en función del contenido de los encabezados de celda y columna.
El modo de ajuste de tamaño automático basado en celdas ajusta el tamaño de las columnas
SizeToCells de DataGrid en función del contenido de las celdas en la columna, sin incluir los encabezados
de columna.
El modo de ajuste de tamaño automático basado en encabezados ajusta el tamaño de las
SizeToHeader
columnas de DataGrid en función solamente del contenido de los encabezados de columna.
El modo de ajuste de tamaño basado en píxeles dimensiona las columnas de DataGrid
Pixel
basándose en el valor numérico proporcionado.
El modo de ajuste de tamaño mediante asterisco se usa para distribuir el espacio disponible
Star en proporciones ponderadas.
En el lenguaje XAML, los valores de asterisco se expresan como n*, donde n representa un
La clase DataGridLengthConverter se puede utilizar para convertir datos entre valores numéricos o de
cadena y valores DataGridLength.
De manera predeterminada, la propiedad DataGrid.ColumnWidth se establece en Auto y la propiedad
DataGridColumn.Width es null. Cuando el modo de tamaño se establece en Auto o SizeToCells, las
columnas crecerán hasta el tamaño de su contenido visible más ancho. Al desplazarse, estos modos de
tamaño harán que las columnas se expandan si el contenido que es mayor que el tamaño de columna se
desplaza en la vista. La columna no se reducirá cuando el contenido se desplace fuera de la vista.
Las columnas de DataGrid también se pueden establecer para dimensionarse automáticamente solo dentro
de los límites especificados, o las columnas se pueden establecer en un tamaño concreto. En la siguiente
lista se muestran las propiedades que se pueden establecer para controlar el tamaño de columna.
Propiedad Descripción
DataGrid.MaxColumnWidth Establece el límite superior de todas las columnas de DataGrid.
Establece el límite superior de una columna individual. Invalida
DataGridColumn.MaxWidth
DataGrid.MaxColumnWidth.
DataGrid.MinColumnWidth Establece el límite inferior de todas las columnas de DataGrid.
Establece el límite inferior de una columna individual. Invalida
DataGridColumn.MinWidth
DataGrid.MinColumnWidth.
DataGrid.ColumnWidth Establece un ancho específico para todas las columnas de DataGrid.
Establece un ancho específico para una columna individual. Invalida
DataGridColumn.Width
DataGrid.ColumnWidth.
Cuadros de mensaje
Silverlight proporciona un objeto MessageBox que se puede utilizar para mostrar un mensaje y solicitar una
respuesta. Para mostrar un cuadro de mensaje, se llama al método Show(String) estático. De manera
opcional, se puede especificar un título y un botón de cancelación para el cuadro de mensaje mediante el
Si desea mostrar un cuadro de diálogo para abrir un archivo, puede usar el método ShowDialog.
ShowDialog devuelve true si el usuario ha seleccionado un archivo y ha hecho clic en Abrir; devuelve false si
el usuario ha hecho clic en Cancelar. Tal y como se ha mencionado anteriormente, para que se muestre el
cuadro de diálogo, el usuario debe realizar alguna acción, por ejemplo, hacer clic en un botón.
La carpeta inicial que aparece la primera vez que se muestra el control OpenFileDialog de una aplicación se
basa en la configuración del usuario. En las siguientes presentaciones del control OpenFileDialog, se utiliza
la carpeta del último archivo seleccionado. Por motivos de seguridad, no se puede especificar una carpeta
inicial para el control OpenFileDialog.
Es posible filtrar los tipos de archivo que se muestran en OpenFileDialog mediante la propiedad Filter. A
continuación, se muestra un ejemplo de una configuración de filtro.
Text Files (.txt)| *.txt"
Se puede habilitar al usuario para que pueda seleccionar varios archivos mediante la propiedad Multiselect.
Una vez seleccionados los archivos, es posible recuperar información sobre los mismos mediante la
propiedad File o Files, en función de que se hayan seleccionado uno o varios archivos.
En el siguiente ejemplo, se refleja cómo mostrar un control OpenFileDialog.
Private ofd As OpenFileDialog
Private Sub OpenButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
ofd = New OpenFileDialog()
ofd.Filter = "Text Files (.txt)| *.txt"
ofd.Multiselect = False
Dim result As System.Nullable(Of Boolean) = ofd.ShowDialog()
Para mostrar un cuadro de diálogo que permite guardar un archivo, se usa el método ShowDialog.
ShowDialog devuelve true si el
si el usuario ha hecho clic en Guardar; devuelve false si el usuario ha hecho clic en Cancelar. Tal y como se
ha mencionado anteriormente, para que se muestre el cuadro de diálogo, el usuario debe realizar alguna
acción, por ejemplo, hacer clic en un botón.
De manera similar a lo que sucede con el control OpenFileDialog, es posible filtrar los tipos de archivo que
se muestran en el control SaveFileDialog mediante la propiedad Filter. Una vez especificada, la descripción
del filtro aparece en la lista desplegable Guardar como tipo del cuadro de diálogo. A continuación se
incluye un ejemplo de una descripción de filtro.
Text Files (.txt)| *.txt"
Es posible especificar la extensión de archivo predeterminada que se anexa al archivo guardado mediante la
propiedad DefaultExt.
Para recuperar el nombre del archivo guardado, se usa la propiedad SafeFileName. Tal y como indica el
nombre de la propiedad, por razones de seguridad, SafeFileName devuelve únicamente el nombre del
archivo sin su ruta de acceso.
En el ejemplo de código siguiente, se muestra cómo establecer la propiedad Filter y mostrar un control
SaveFileDialog.
Private sfd As SaveFileDialog
Private Sub SaveButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
sfd = New SaveFileDialog()
sfd.Filter = "Video Files (.wmv) | *.wmv"
para cancelar la operación de impresión. En la ilustración siguiente, se muestra un ejemplo del cuadro de
diálogo de impresión para Windows.
Imprimir (Cuadro de diálogo)
Para que se lleve a cabo la operación de impresión, es preciso controlar el evento PrintPage del documento
de impresión y especificar el elemento que se desea imprimir.
La plantilla Ventana secundaria de Silverlight agrega al proyecto una nueva clase derivada de la ventana
secundaria, incluidos el archivo XAML y el archivo de código subyacente. El archivo XAML contiene los
botones Aceptar y Cancelar y el archivo de código subyacente contiene para cada botón los controladores
de eventos Click que establecen el resultado apropiado.
Control emergente
Es posible mostrar un control de usuario en un control Popup similar a un cuadro de diálogo. Para ello, se
crea un control de usuario derivado de la clase UserControl y se establece la propiedad Child de Popup en
una instancia del control de usuario. Para mostrar un objeto Popup, se establece la propiedad IsOpen en
true.
Para establecer la posición de un objeto Popup con respecto a la esquina superior izquierda del
complemento Silverlight, se usan las propiedades VerticalOffset y HorizontalOffset.
Nota:
Si un archivo seleccionado se envía al servidor para su procesamiento, deberá informar al usuario.
Para mostrar el cuadro de diálogo Abrir archivo y procesar las acciones del
usuario
1. Cree una instancia de la clase OpenFileDialog.
2. A título opcional, especifique la cadena de filtro de archivos y el índice del filtro estableciendo las
propiedades FilterIndex y Filter.
3. Llame al método ShowDialog para que muestre el cuadro de diálogo Abrir archivo.
4. Cuando el método devuelva el resultado, determine si el cuadro de diálogo se cerró con el botón
Aceptar o con el botón Cancelar. Si se cerró con el botón Aceptar, procese la selección del
usuario.
En el ejemplo siguiente se indica cómo mostrar el cuadro de diálogo, probar la selección del usuario y, a
continuación, procesar el archivo.
<UserControl x:Class="SL_OpenFileDialog_VB.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<Button x:Name="bOpenFileDialog" Content="Open File"
Height="30" Width="60" Margin="10"
HorizontalAlignment="Left" VerticalAlignment="Top"
Click="bOpenFileDialog_Click" />
<TextBox x:Name="tbResults" Text="Silverlight Results"
Height="30" Width="300" Margin="10,50"
Nota:
Los ensamblados y ejecutables deben ser ensamblados y ejecutables de Silverlight. Si se intentan
agregar controles de ensamblados que no son ensamblados ni ejecutables de Silverlight, aparecerá
un cuadro de diálogo para indicar que no hay componentes para agregar al cuadro de
herramientas.
7. Los controles del ensamblado aparecen en el cuadro de diálogo Elegir elementos del cuadro de
herramientas.
8. Active la casilla situada junto al control que desee agregar y, a continuación, haga clic en Aceptar.
El control seleccionado aparece en la parte inferior de la pestaña seleccionada en el Cuadro de
herramientas.
9. Desde el Cuadro de herramientas, arrastre el control hasta la superficie de diseño.
El control seleccionado se mostrará en la superficie de diseño. Además, el ensamblado del control
se agrega como referencia de proyecto y se agrega al archivo XAML una asignación de espacio de
nombres XAML.
Utilizar el diseñador
Puede agregar un elemento de fichas a TabControl haciendo clic con el botón secundario en la superficie de
diseño.
Para agregar elementos de fichas a un TabControl utilizando el diseñador
1. En Silverlight Designer, arrastre un control TabControl del cuadro de herramientas hasta la
superficie de diseño o seleccione un control TabControl existente. Cuando se arrastra un control
TabControl desde el cuadro de herramientas hasta la superficie de diseño, se agrega
automáticamente TabItem al control.
2. En la parte superior del TabControl, haga clic con el botón secundario en TabItem.
3. Seleccione Agregar ficha del menú contextual. En la siguiente ilustración se muestra el menú
contextual.
Nota:
De forma predeterminada, Silverlight Designer usa Grid como contenedor raíz del elemento de
pestaña. Si necesita un contenedor raíz diferente, puede eliminar Grid y agregar otro contenedor,
por ejemplo, un control StackPanel.
5.5.6. Cómo: Crear aplicaciones cuyo tamaño pueda ser modificado por el
usuario con GridSplitter
Se puede usar el control GridSplitter junto con el control contenedor Grid para crear diseños cuyo tamaño
pueda ajustar el usuario en tiempo de ejecución. Por ejemplo, en una aplicación que tiene una interfaz
dividida en áreas, el usuario puede arrastrar un divisor para agrandar el área que desee ver mejor. En este
tema, se incluyen algunos procedimientos recomendados de GridSplitter y se describe cómo crear un
control GridSplitter vertical y horizontal.
Cuando se agrega un control GridSplitter a un control Grid, el primero es un elemento secundario del
control Grid y debe colocarse en una fila y una columna como cualquier otro control secundario. El control
GridSplitter debe tener un ancho o alto distinto de cero, para que el usuario pueda agarrarlo y arrastrarlo en
tiempo de ejecución.
Algunos procedimientos recomendados para GridSplitter incluyen los siguientes:
Coloque GridSplitter en una fila o columna dedicada que no contenga ningún otro control.
Establezca el alto de la fila o el ancho de la columna que contiene el GridSplitter en Auto.
Dedique un control Grid único al control GridSplitter. Agregue paneles contenedores adicionales a
Grid para completar el diseño.
Nota:
En ocasiones, puede que sea difícil colocar filas y columnas en el diseñador. En ese caso, puede
configurar Grid utilizando el editor XAML. Vea un ejemplo de marcado XAML en la sección de
ejemplo al final de este tema.
Propiedad Valor
Grid.Column 0
Grid.RowSpan Número total de filas de Grid.
Ancho Un número distinto de cero. Por ejemplo: 10.
Alto Auto
HorizontalAlignment Right
VerticalAlignment Stretch
Margin 0
Nota:
En ocasiones, puede que sea difícil colocar filas y columnas en el diseñador. En ese caso, puede
configurar Grid utilizando el editor XAML. Vea un ejemplo de marcado XAML en la sección de
ejemplo al final de este tema.
Propiedad Valor
Grid.ColumnSpan Número total de columnas de Grid.
Grid.Row 0
Ancho Auto
Alto Un número distinto de cero. Por ejemplo: 10.
HorizontalAlignment Stretch
VerticalAlignment Bottom
Margin 0
Ejemplo
El siguiente XAML crea un control GridSplitter horizontal y otro vertical.
<Grid x:Name="LayoutRoot" Background="White" Height="400" Width="400" ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="60" />
<RowDefinition Height="60" />
<RowDefinition Height="60" />
<RowDefinition Height="60" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="80" />
<ColumnDefinition Width="80" />
<ColumnDefinition Width="80" />
</Grid.ColumnDefinitions>
<sdk:GridSplitter Grid.Column="0" Grid.RowSpan="5" Width="10" HorizontalAlignment="Right" VerticalAlignment="Stretch" />
<sdk:GridSplitter Grid.Row="0" Grid.ColumnSpan="4" Height="10" HorizontalAlignment="Stretch" VerticalAlignment="Bottom"/>
<Rectangle Grid.Column="1" Fill="LightCoral" />
<Rectangle Grid.Row="1" Fill="LightBlue" />
</Grid>
Ejemplo
En el código siguiente se muestra cómo controlar los eventos Checked y Indeterminate.
Private Sub HandleCheck(ByVal sender As Object, ByVal e As RoutedEventArgs)
Dim cb As CheckBox = CType(sender, CheckBox)
If (cb.Name = "cb1") Then
text1.Text = "Two state CheckBox checked."
Else
text2.Text = "Three state CheckBox checked."
End If
End Sub
Public Sub New(ByVal firstName As String, ByVal lastName As String, ByVal address As String)
Me.FirstName = firstName
Me.LastName = lastName
Me.Address = address
End Sub
End Class
Nota:
Asegúrese de agregar una referencia al espacio de nombres local en el archivo XAML, como la que
figura a continuación.
xmlns:src="clr-namespace:ListBoxSnippetEx"
<UserControl x:Class="ListBoxSnippetEx.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:src="clr-namespace:ListBoxSnippetEx" >
<Grid>
<Grid.Resources>
<src:Customers x:Key="customers"/>
</Grid.Resources>
<ListBox ItemsSource="{StaticResource customers}" Width="350" Margin="0,5,0,10">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Padding="5,0,5,0" Text="{Binding FirstName}" />
<TextBlock Text="{Binding LastName}" />
<TextBlock Text=", " />
<TextBlock Text="{Binding Address}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</UserControl>
Public Sub New(ByVal firstName As String, ByVal lastName As String, ByVal address As String)
Me.FirstName = firstName
Me.LastName = lastName
Me.Address = address
End Sub
End Class
End Class
' Handle the Populating event, but cancel it. Make the call to the web service.
Private Sub AutoCompleteBox_Populating(ByVal sender As Object, ByVal e As PopulatingEventArgs)
e.Cancel = True
CallToWebService()
End Sub
Ejemplo
En el ejemplo siguiente se muestran dos plantillas de datos jerárquicos declaradas en orden ascendente. En
el ejemplo se muestra un control TreeView con la propiedad ItemsControl.ItemTemplate establecida en la
plantilla que se aplica a los nodos de nivel superior.
Partial Public Class MainPage
Inherits UserControl
Public Shared Topics As New ObservableCollection(Of Topic)()
Public Sub New()
InitializeComponent()
5.5.11. InkPresenter
El elemento InkPresenter proporciona una superficie de dibujo que admite las características de entrada
manuscrita. InkPresenter se deriva de Canvas y puede mostrar uno o varios objetos UIElement y un objeto
StrokeCollection.
El uso de la entrada manuscrita en Silverlight abre nuevos escenarios para la interacción natural en el
contenido de los juegos en línea. Silverlight simplifica la implementación de estos escenarios. La flexibilidad
del modelo de entrada permite a su vez una gran flexibilidad al implementarlo en el contenido de los
juegos.
En el ejemplo anterior, se agrega un Rectangle a Canvas con el mismo margen que el elemento
InkPresenter. Esto se debe a que InkPresenter no incluye propiedades para proporcionar límites visuales. La
propiedad Stroke de Rectangle está establecida en Black, lo que hace que actúe como borde de
InkPresenter. El orden Z de InkPresenter debe ser superior al de Rectangle. De lo contrario, Rectangle
ocultará InkPresenter.
Para anotar fotografías con un lápiz o un mouse, Image y InkPresenter se agregan a un elemento Canvas. En
el siguiente ejemplo de código se muestra cómo anotar una fotografía.
<Canvas>
<Image Source="flower.jpg" Stretch="Fill" Width="500" Height="500" />
<InkPresenter x:Name="MyIP" Background="Transparent" Width="500" Height="500"
MouseLeftButtonDown="MyIP_MouseLeftButtonDown"
MouseMove="MyIP_MouseMove"
LostMouseCapture="MyIP_LostMouseCapture">
</InkPresenter>
</Canvas>
puede ser un punto, una línea recta o una línea curva. Cada Stroke contiene un objeto StylusPointCollection,
que a su vez contiene objetos StylusPoint individuales. Los objetos StylusPoint se recogen al mover el lápiz
mientras está en contacto con el digitalizador. Stroke también incluye una serie de características, como
alto, ancho, color y color del contorno, todas ellas incluidas en la clase DrawingAttributes.
Recopilación de entradas manuscritas
Puede crear o capturar los trazos mediante programación, respondiendo a los eventos en InkPresenter. Los
eventos típicos para hacer esto son MouseLeftButtonDown, MouseMove y LostMouseCapture.
Nota:
Use los eventos del mouse para detectar las acciones de un dispositivo de lápiz. Los eventos
MouseLeftButtonDown, LostMouseCapture y MouseMove corresponden a acciones de descenso del lápiz,
movimiento y subida del lápiz, respectivamente.
En el siguiente ejemplo de código se muestra cómo recoger y mostrar los datos de trazo en InkPresenter.
Public Sub New()
MyBase.New()
InitializeComponent()
SetBoundary()
End Sub
'A new stroke object, MyStroke, is created and is added to the StrokeCollection object of the InkPresenter, MyIP
Private Sub MyIP_MouseLeftButtonDown(ByVal sender As Object, ByVal e As MouseEventArgs)
MyIP.CaptureMouse()
Dim MyStylusPointCollection As StylusPointCollection = New StylusPointCollection
MyStylusPointCollection.Add(e.StylusDevice.GetStylusPoints(MyIP))
NewStroke = New Stroke(MyStylusPointCollection)
MyIP.Strokes.Add(NewStroke)
End Sub
'StylusPoint objects are collected from the MouseEventArgs and added to MyStroke.
Private Sub MyIP_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs)
If (Not (NewStroke) Is Nothing) Then
NewStroke.StylusPoints.Add(e.StylusDevice.GetStylusPoints(MyIP))
End If
End Sub
'MyStroke is completed
Private Sub MyIP_LostMouseCapture(ByVal sender As Object, ByVal e As MouseEventArgs)
NewStroke = Nothing
End Sub
'Set the Clip property of the inkpresenter so that the strokes are contained within the boundary of the inkpresenter
Private Sub SetBoundary()
Dim MyRectangleGeometry As RectangleGeometry = New RectangleGeometry
MyRectangleGeometry.Rect = New Rect(0, 0, MyIP.ActualWidth, MyIP.ActualHeight)
MyIP.Clip = MyRectangleGeometry
End Sub
Requisitos previos
En este tema se supone que el usuario entiende cómo obtener entradas de lápiz en un control InkPresenter.
Borrado de trazos
El borrado de trazos elimina trazos completos. Por ejemplo, un trazado de lápiz o de mouse que interseca
con un trazo puede iniciar un borrado de trazos. El borrado de trazos se puede implementar pasando la
colección StylusPointCollection obtenida por el trazado del mouse o el lápiz al método HitTest de la
colección de trazos de lápiz. El valor devuelto indicará qué trazo se debe quitar de la colección.
En los pasos siguientes se describe cómo implementar un algoritmo de borrado de trazos. En este
algoritmo, el usuario hace clic con el mouse o con el lápiz y mueve el puntero sobre un trazo para borrarlo.
Para implementar el borrado de trazos
1. En el controlador de eventos MouseLeftButtonDown, obtenga los puntos del lápiz y almacénelos en
un objeto StylusPointCollection.
Private Sub _presenter_MouseLeftButtonDown(ByVal sender As Object, ByVal e As MouseButtonEventArgs)
If _mode = InkMode.StrokeErase Then
_erasePoints = e.StylusDevice.GetStylusPoints(_presenter)
End If
End Sub
Borrado de puntos
El borrado de puntos elimina únicamente una parte del trazo. La implementación del borrado de puntos es
similar al borrado de trazos. Sin embargo, en el borrado de puntos, un trazo que interseca con el trazado
del mouse o del lápiz se reemplaza con dos trazos.
En los pasos siguientes se describe cómo implementar un algoritmo de borrado de puntos. En este
algoritmo, el usuario hace clic con el mouse o con el lápiz y mueve el puntero sobre un trazo para dividirlo
en dos.
Para implementar el borrado de puntos
1. En el controlador de eventos MouseLeftButtonDown, obtenga los puntos del lápiz y almacénelos en
un objeto StylusPointCollection. Almacene el último punto del lápiz en la colección de puntos del
lápiz por separado. Guardar el último punto permite asegurarse de que el punto en que se llamó al
evento de clic del mouse se procese también en el controlador de movimiento de mouse
subsiguiente.
Private Sub _presenter_MouseLeftButtonDown(ByVal sender As Object, ByVal e As MouseButtonEventArgs)
If _mode = InkMode.PointErase Then
Dim pointErasePoints As StylusPointCollection = e.StylusDevice.GetStylusPoints(_presenter)
'Store the last point in the stylus point collection.
_lastPoint = pointErasePoints(pointErasePoints.Count - 1)
End If
End Sub
colección de trazos del elemento InkPresenter mediante el método HitTest y almacene los trazos
que intersequen. Quite la intersección de puntos entre el trazo y el trazado del mouse o del lápiz.
En el método ProcessPointErase del paso siguiente se implementa la eliminación de los puntos que
intersecan.
Private Sub _presenter_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs)
If _mode = InkMode.PointErase AndAlso _lastPoint IsNot Nothing Then
Dim pointErasePoints As StylusPointCollection = e.StylusDevice.GetStylusPoints(_presenter)
pointErasePoints.Insert(0, _lastPoint.Value)
'Compare collected stylus points with the ink presenter strokes and store the intersecting strokes.
Dim hitStrokes As StrokeCollection = _presenter.Strokes.HitTest(pointErasePoints)
If hitStrokes.Count > 0 Then
For Each hitStroke As Stroke In hitStrokes
'For each intersecting stroke, split the stroke into two while removing the intersecting points.
ProcessPointErase(hitStroke, pointErasePoints)
Next
End If
_lastPoint = pointErasePoints(pointErasePoints.Count - 1)
End If
End Sub
3. Implemente el método ProcessPointErase para reemplazar el trazo que interseca con dos trazos. El
método ProcessPointErase toma un objeto Stroke denominado stroke y una colección
StylusPointCollection denominada pointErasePoints como entrada y quita los puntos que
intersecan de InkPresenter. Determine la intersección partiendo del primer punto en de stroke y
agregue cada punto del lápiz de stroke a splitStroke1 hasta llegar a un punto del lápiz que
interseque con pointErasePoints. Repita el proceso empezando por el último punto de stroke y
agregue cada punto del lápiz a splitStroke2 hasta llegar a un punto del lápiz que interseque con el
objeto pointErasePoints de entrada. Por último, reemplace stroke con splitStroke1 y splitStroke2.
Para ello, puede utilizar el método remove y agregar splitstroke1 y splitstroke2 a InkPresenter.
Private Sub ProcessPointErase(ByVal stroke As Stroke, ByVal pointErasePoints As StylusPointCollection)
Dim splitStroke1 As Stroke, splitStroke2 As Stroke, hitTestStroke As Stroke
Modelo de contenido
RichTextBox admite un modelo de contenido basado en bloques. La propiedad de contenido del control
RichTextBox es Blocks, que es una colección de elementos Paragraph. El elemento Paragraph puede
contener elementos derivados de Inline. En la siguiente ilustración, se resume el modelo de contenido del
control RichTextBox y se muestra cómo los elementos derivados de Block e Inline encajan en este modelo.
Diagrama del modelo de contenido de RichTextBox
Elementos de bloque
Los elementos de bloque son clases que heredan de Block. Actualmente, Paragraph y Section se derivan de
Block, pero Section no forma parte del modelo de documento de RichTextBox.
Elemento de
Descripción
bloque
Paragraph se utiliza para agrupar el contenido en un párrafo. El uso más sencillo y común de
Paragraph Paragraph es crear un párrafo de texto. Un objeto Paragraph también puede contener
elementos incorporados.
Elementos incorporados
Los elementos incorporados son clases que heredan de Inline; un elemento incorporado está incluido en un
elemento de bloque u otro elemento incorporado. Los elementos incorporados se utilizan a menudo como
contenedor directo del contenido que se representa en la pantalla. Por ejemplo, un elemento de bloque
Paragraph puede contener un elemento incorporado Run, pero es Run el que contiene en realidad el texto
que se representa en la pantalla. El contenido de cada elemento Paragraph puede incluir muchos tipos de
elementos, incluidos los siguientes:
Elemento
Descripción
incorporado
Run se utiliza para contener texto sin formato. Podría pensarse que el objeto Run se
Run utiliza en gran medida en el contenido; sin embargo, en el marcado no es necesario
utilizar los elementos Run de forma explícita.
Span agrupa otros elementos de contenido inline. No se aplica ninguna representación
inherente al contenido dentro de un elemento Span. Es decir, no se da formato al
Span contenido si se coloca dentro de un elemento Span sin ningún atributo. Sin embargo, los
elementos que heredan de Span, como Hyperlink, Bold, Italic y Underline, aplican
formato al texto.
InlineUIContainer permite incrustar elementos UIElement (por ejemplo, controles Image
InlineUIContainer
o Button) en un elemento de contenido Inline.
A continuación, se muestra cómo crear un control RichTextBox con un párrafo y texto en negrita en XAML y
en código. El valor de la propiedad VerticalScrollBarVisibility se establece en Auto.
<!--A RichTextBox with intial content in it.-->
<RichTextBox VerticalScrollBarVisibility="Auto">
<Paragraph>
A RichTextBox with <Bold>initial content</Bold> in it.
</Paragraph>
</RichTextBox>
' Create a paragraph and add the Run and Bold to it.
Dim myParagraph As New Paragraph()
myParagraph.Inlines.Add(myRun1)
myParagraph.Inlines.Add(myBold)
myParagraph.Inlines.Add(myRun2)
Elementos como Paragraph y Bold determinan cómo aparece el contenido en el control RichTextBox.
Cuando un usuario edita el contenido de RichTextBox, modifica dicho contenido.
Hipervínculos
RichTextBox admite hipervínculos. Se puede usar el elemento Hyperlink para mostrar hipervínculos en el
control RichTextBox. Los hipervínculos proporcionan un comportamiento integrado al situar el mouse sobre
ellos así como compatibilidad con el foco. Utilice la propiedad NavigateUri del elemento Hyperlink para
especificar la dirección URL.
Nota:
Es preciso establecer la propiedad IsReadOnly del control RichTextBox en true para que funcione el
elemento Hyperlink.
A continuación, se muestra cómo crear un control RichTextBox con un hipervínculo en XAML y en código.
<!--A RichTextBox with hyperlink.-->
<RichTextBox IsReadOnly="True">
<Paragraph>
Displaying text with <Hyperlink NavigateUri="http://www.msdn.com">hyperlink</Hyperlink>.
</Paragraph>
</RichTextBox>
' Create a paragraph and add the Run and hyperlink to it.
Dim myParagraph As New Paragraph()
myParagraph.Inlines.Add(myRun)
myParagraph.Inlines.Add(MyLink)
Recorrer el contenido
Es posible recorrer el contenido de un control RichTextBox mediante la clase TextPointer y sus miembros.
Un objeto TextPointer representa una posición en el contenido de un control RichTextBox. La posición
puede encontrarse entre caracteres del contenido o entre las etiquetas de elemento que definen la
estructura del contenido. Si la posición está entre caracteres del contenido, se trata de una posición de
inserción. Es decir, se puede agregar nuevo contenido en esa posición sin infringir ninguna regla semántica
para el contenido asociado. En la práctica, una posición de inserción se puede encontrar en cualquier parte
del contenido donde se pueda colocar un cursor. En la mayoría de los casos, si la posición se encuentra
entre las etiquetas de elemento que definen la estructura del contenido, no se trata de una posición de
inserción. Un ejemplo de una posición de TextPointer válida que no sea una posición de inserción es la
posición entre dos etiquetas de párrafo adyacentes (es decir, entre la etiqueta de cierre del párrafo anterior
y la etiqueta de apertura del párrafo siguiente).
Entre las operaciones que se pueden realizar con la clase TextPointer se encuentran las siguientes:
Realice una comparación de ordinales de la posición actual con una segunda posición especificada.
Un escenario más común sería seleccionar una parte del contenido y, a continuación, aplicar el formato a la
selección. La clase TextSelection representa una selección de texto en el control RichTextBox. Para obtener
acceso al texto seleccionado en el control RichTextBox, se usa su propiedad Selection. Para realizar
operaciones con el texto seleccionado, se pueden usar los métodos GetPropertyValue y
ApplyPropertyValue. En el siguiente ejemplo, se muestra cómo aplicar formato de negrita, cursiva y
subrayado al texto seleccionado.
<!--Create a RichTextBox and three buttons.-->
<StackPanel>
<RichTextBox x:Name="MyRTB" Width="600" Height="400" />
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Button Content="Bold" Height="30" Margin="2" Width="50" Click="BtnBold_Click" />
<Button Content="Italic" Height="30" Margin="2" Width="50" Click="BtnItalic_Click" />
<Button Content="Underline" Height="30" Margin="2" Width="65" Click="BtnUnderline_Click" />
</StackPanel>
</StackPanel>
Asimismo, existe la posibilidad de seleccionar texto mediante programación. Para seleccionar texto
mediante programación en un control RichTextBox, se usa el método Select. El método Select toma dos
objetos TextPointer como parámetros y selecciona el texto entre los dos objetos. En el siguiente ejemplo de
código, se utiliza el método Select para seleccionar y subrayar mediante programación la última palabra de
un control RichTextBox. En este ejemplo, se usa un carácter de espacio para delimitar las palabras. Este
ejemplo de código forma parte de un ejemplo más extenso referente a la clase TextPointer.
'This method underlines the last word in a RichTextBox
Public Sub UnderlineLastWord()
Dim EndofContent As TextPointer = MyRTB1.ContentEnd.GetNextInsertionPosition(LogicalDirection.Backward)
Dim currentPointer As TextPointer = EndofContent.GetNextInsertionPosition(LogicalDirection.Backward)
If (currentPointer Is Nothing) Then
Return
End If
Dim currentChar As String = GetCurrentChar(MyRTB1, currentPointer, LogicalDirection.Backward)
While ((currentChar <> " ") _
AndAlso (currentChar <> ""))
currentPointer = currentPointer.GetNextInsertionPosition(LogicalDirection.Backward)
currentChar = GetCurrentChar(MyRTB1, currentPointer, LogicalDirection.Backward)
End While
If (currentChar = " ") Then
MyRTB1.Selection.Select(currentPointer.GetNextInsertionPosition(LogicalDirection.Forward), EndofContent)
Else
MyRTB1.Selection.Select(currentPointer, EndofContent)
End If
MyRTB1.Selection.ApplyPropertyValue(Run.TextDecorationsProperty, TextDecorations.Underline)
End Sub
Private Function GetCurrentChar(ByVal RTB As RichTextBox, ByVal pointer As TextPointer, ByVal direction As
LogicalDirection) As String
Dim nextPointer As TextPointer = pointer.GetNextInsertionPosition(direction)
If (Not (nextPointer) Is Nothing) Then
RTB.Selection.Select(pointer, nextPointer)
If (RTB.Selection.Text.Length <> 0) Then
Return RTB.Selection.Text(0).ToString
End If
End If
Return ""
End Function
XAML
Para obtener y establecer una representación en XAML del contenido de un control RichTextBox, se usa la
propiedad Xaml. La cadena de XAML devuelta por la propiedad Xaml incluirá solo los siguientes elementos:
Paragraph
Run
LineBreak
Span
Bold
Hyperlink
Underline
Italic
Nota:
Observe que la cadena de XAML devuelta por la propiedad Xaml no incluirá ningún objeto UIElement del
contenido. Los objetos InlineUIContainer se convertirán en objetos Run vacíos.
En la siguiente tabla, se muestran varios elementos y las correspondientes propiedades que se incluyen en
la cadena devuelta por la propiedad Xaml.
Elemento Propiedades
FontSize
FontFamily
Foreground
FontWeight
FontStyle
TextElement
FontStretch
Nota:
La propiedad Xaml solo admite valores de atributo que se pueden representar como una
cadena. Por ejemplo, para establecer la propiedad Foreground, solo se puede utilizar un
objeto SolidColorBrush y no un objeto LinearGradientBrush.
FlowDirection
Run
Text
Section HasTrailingParagraphBreakOnPaste
Block TextAlignment
TargetName
NavigateUri
Hyperlink
MouseOverForeground
MouseOverTextDecorations
Undo
El control RichTextBox permite realizar varias operaciones de reversión en respuesta a las acciones del
usuario. Además, también se puede revertir una operación de reversión, lo que se denomina rehacer.
Cuando se deshace o se rehace una acción, el control RichTextBox intenta establecer el estado de selección
basándose en esas operaciones.
La operación de deshacer se admite únicamente si el valor de la propiedad IsReadOnly de un control
RichTextBox es false. Asimismo, las operaciones de reversión no se pueden realizar mediante programación.
Elementos de texto
En términos generales, un elemento de texto en Silverlight es:
Un control TextBlock.
Un Control diseñado para mostrar texto o que incluye texto en alguna parte de su plantilla y
presentación habituales, como un control TextBox o RichTextBox.
Una clase derivada de TextElement que se puede usar para aplicar formato al texto que se muestra
en un control TextBlock o RichTextBox.
Ciertos tipos específicos de los controles, como DataGridTextColumn.
Estos elementos comparten la característica de tener un conjunto de propiedades que controlan cómo se
muestra el texto en el elemento o en el contenido del elemento. Estas propiedades son: FontFamily,
FontSize, FontStretch, FontStyle, FontWeight y Foreground. La implementación de las propiedades no
necesariamente se comparte entre los elementos como parte de una herencia común, pero las
implementaciones son similares en cada elemento de texto.
TextBlock
El objeto TextBlock es el elemento principal para mostrar texto de solo lectura en aplicaciones basadas en
Silverlight. En el XAML siguiente, se muestra cómo definir un elemento TextBlock y establecer su propiedad
Text en una cadena.
<TextBlock Text="Hello, world!" />
TextBlock también admite un modelo de texto básico para su contenido, que se describe en la sección
"Modelo de texto de TextBlock" en este mismo tema.
Controles de texto
TextBlock no es el único elemento de la interfaz de usuario de Silverlight que muestra texto directamente.
TextBox, PasswordBox y RichTextBox también son elementos de texto. Estas clases se derivan de la clase
Control, que implementa varias propiedades pertinentes para el texto y las fuentes. Sin embargo, no
siempre es cierto que una clase derivada de Control sea capaz de mostrar texto o incluso admita un modelo
de contenido que pueda contener un elemento de texto. A continuación, se muestra una lista con las
propiedades de texto y fuentes pertinentes que se implementan en la clase Control:
Control.FontFamily
Control.FontSize
Control.FontStretch
Control.FontStyle
Control.FontWeight
Por otra parte, aunque no se usa exclusivamente como una propiedad de fuente, Foreground proporciona
Brush para el texto mostrado en elementos de texto de Silverlight.
Herencia de propiedades de fuente en controles de texto
Uno de los motivos por los cuales las propiedades de fuente y texto se implementan en el nivel de Control
es que los controles puedan admitir la herencia de los valores de las propiedades de fuente. Esto permite
definir un control con componentes que procedan de una plantilla y hacer que las propiedades de fuente
del control primario se apliquen a cualquiera de los componentes o contenido que muestren cadenas de
texto.
Por ejemplo, ComboBox es un control de elementos en el que se pueden mostrar otros elementos o texto.
Si se establecen las propiedades de fuente de ComboBox, los otros elementos o el texto mostrado heredan
automáticamente las propiedades de fuente (sin requerir ningún tipo de control especial por parte de la
lógica del control). En el caso del texto mostrado, la herencia de las propiedades de fuente es especialmente
útil, porque no habría ninguna otra forma de aplicar atributos a ese texto. Los componentes y el contenido
de texto de un control personalizado pueden heredar sus propiedades de fuente basadas en Control
exactamente de la misma manera.
La herencia de las propiedades de fuente funciona cuando el componente es un control TextBlock. Esto es
así aunque TextBlock no es técnicamente un control y no comparte las implementaciones de propiedad con
su control primario. Esa es una de las razones por las que son paralelas las propiedades de fuente entre los
controles y TextBlock.
Si se establecen las propiedades de los elementos de texto a través de Style o una plantilla aplicada, los
elementos secundarios heredan las propiedades en tiempo de ejecución. Los cambios en tiempo de
ejecución de las propiedades de los elementos de texto también propagan sus nuevos valores a los
elementos de texto secundarios herederos.
En el XAML siguiente, se muestra cómo definir un elemento TextBlock y especificar todos los atributos de
fuente mostrados en la tabla anterior (salvo TextDecorations).
Nota:
Dependiendo de la fuente seleccionada por Silverlight, los atributos de fuente especificados pueden no ser
los que se utilizan durante la representación. Para obtener más información, vea la sección "Selección de
fuentes" más adelante en este mismo tema.
<TextBlock
Text="Font Attributes"
FontFamily="Verdana"
FontSize="36"
Fuentes en Silverlight
Las fuentes que se pueden usar en un equipo cliente dependen de la versión de Silverlight. En Silverlight 4,
se puede utilizar en el equipo cliente cualquier fuente para cualquier elemento de texto.
En Silverlight 3, se puede usar en el equipo cliente un subconjunto de las fuentes. Para los elementos de
texto en Silverlight 3, se pueden usar las siguientes fuentes latinas si están disponibles en el equipo local.
Arial
Arial Black
Arial Unicode MS
Calibri
Cambria
Cambria Math
Comic Sans MS
Candara
Consolas
Constantia
Corbel
Courier New
Georgia
Lucida Grande/Lucida Sans Unicode
Segoe UI
Symbol
Tahoma
Times New Roman
Trebuchet MS
Verdana
Wingdings
Wingdings 2
Wingdings 3
Lucida Grande y Lucida Sans Unicode son alias de la misma fuente y se especifican como un par por
motivos de compatibilidad. Portable User Interface es una fuente compuesta. Usa varias fuentes para
implementar el intervalo de idiomas internacionales admitido por Silverlight. Entre estas se incluyen "Lucida
Sans Unicode" y "Lucida Grande" para muchos sistemas de escritura occidentales, así como muchas otras
para los sistemas de escritura de Asia Oriental.
Si desea trabajar con texto de Asia Oriental, los elementos de texto de Silverlight 3 pueden utilizar las
siguientes fuentes de Asia Oriental si están disponibles en el equipo local:
Batang
Meiryo
MS Gothic
MS Mincho
MS PGothic
MS PMincho
PMingLiU
SimSun
En los equipos con Microsoft Windows, los elementos de texto de Silverlight 3 también pueden utilizar las
siguientes fuentes de Asia Oriental si están disponibles en el equipo local:
BatangChe
DFKai-SB
Dotum
DutumChe
FangSong
GulimChe
Gungsuh
GungsuhChe
KaiTi
Malgun Gothic
Microsoft JhengHei
Microsoft YaHei
MingLiU
MingLiu_HKSCS
MingLiu_HKSCS-ExtB
MingLiu-ExtB
MS UI Gothic
NSimSun
NSimSun-18030
PMingLiu-ExtB
SimHei
SimSun-18030
SimSun-ExtB
Si Silverlight 3 se ejecuta en equipos Macintosh, los elementos de texto también pueden usar las siguientes
fuentes de Asia Oriental si están disponibles en el equipo local:
AppleGothic
Gulim
Hiragino Kaku Gothic Pro
STHeiti
Selección de fuentes
La fuente que se especifica no tiene por qué ser la fuente que usa Silverlight. Silverlight elige la fuente entre
las fuentes locales compatibles, las fuentes proporcionadas en un archivo empaquetado al que se hace
referencia en la propiedad FontFamily, o el archivo. zip o .ttf basado en secuencia que se pasa a la
propiedad FontSource. El resultado que se muestra es la coincidencia más adecuada en función de los
valores de las propiedades FontFamily, FontStretch, FontStyle y FontWeight. Es importante especificar estas
cuatro propiedades de fuente para garantizar que la selección de la fuente del elemento de texto sea
adecuada y coherente.
Especificación de fuentes no predeterminadas
Silverlight no incluye ninguna fuente en su paquete de instalación, sino que se basa en las fuentes locales
del sistema para obtener sus valores predeterminados. Si desea usar una fuente para un elemento de texto
que no se encuentra en la lista de fuentes locales admitidas, puede especificar la fuente en XAML mediante
la propiedad FontFamily o en el código mediante la propiedad FontSource. La propiedad FontFamily puede
especificar un archivo de fuentes único o un archivo zip que contenga los archivos de fuentes, y puede
incorporar una secuencia de reserva. Cualquier archivo de fuentes al que se haga referencia para el uso de
FontFamily en XAML se debe incrustar como recurso dentro de un ensamblado. Cuando se usa FontSource,
el código puede cargar el archivo de fuentes de origen para la fuente (o un zip de fuentes) desde una
secuencia, como un almacenamiento aislado, o desde un empaquetado de XAP.
Un color sólido no es la única manera de aplicar un primer plano a una fuente. En Silverlight se puede usar
cualquiera de las clases derivadas de Brush, incluidas RadialGradientBrush, LinearGradientBrush, ImageBrush
y VideoBrush. Si especifica estos pinceles en XAML, debe usar la sintaxis de elementos de propiedad o una
referencia tal como una referencia de recurso. En el código XAML siguiente se muestra un ejemplo de cómo
se usa la sintaxis de elementos de propiedad y cómo se especifica ImageBrush para el texto:
<TextBlock Text="SHRUBBERY">
<TextBlock.Foreground>
<ImageBrush ImageSource="forest.jpg"/>
</TextBlock.Foreground>
</TextBlock>
En la ilustración siguiente, se muestra el texto con formato representado del XAML anterior.
TextBlock rendering multiple Run objects
LineBreak hace que el texto de cada Run se muestre en una línea independiente. Sin LineBreak, el texto de
cada Run fluiría junto, como una sola línea, y a menudo quedaría cortado, ya que se excedería el ancho del
objeto TextBlock o el ancho del área de contenido de Silverlight. En la ilustración siguiente se muestra cómo
se representaría el texto con formato si no se utilizaran objetos LineBreak.
TextBlock que representa varios objetos Run sin objetos LineBreak
TextBox y PasswordBox
Silverlight incluye un control TextBox y el control PasswordBox derivado, en su conjunto básico de controles.
El control TextBox se utiliza normalmente para capturar la entrada de texto de un usuario. El control
PasswordBox se utiliza normalmente en los escenarios de autenticación. La principal diferencia entre estos
controles reside en que se muestran los caracteres que se escriben en un control TextBox y se ocultan los
caracteres que se escriben en un control PasswordBox.
Cuando un control TextBox tiene el foco del teclado o cuando el puntero del mouse se mueve sobre él, el
cursor cambia normalmente a IBeam. Este comportamiento se basa en las plantillas predeterminadas y se
puede modificar para cada instancia.
Ajuste del texto de TextBox
El control TextBox admite el ajuste de texto. De forma predeterminada, la propiedad TextWrapping se
establece en NoWrap. Sin ajuste de texto, si el texto escrito supera el valor explícito de Width o una
restricción de ancho impuesta por un contenedor de diseño primario, se desplazará de forma que el cursor
siempre permanezca a la vista. Si se establece el valor de TextWrapping en Wrap, el texto no se desplazará
horizontalmente y se ajustará dentro del control TextBox. Sigue siendo posible que se den situaciones en las
que el texto de entrada no se vea si se supera el valor de Height o el alto de representación efectivo del
control TextBox.
Texto multilínea de TextBox
TextBox puede admitir texto multilínea, si AcceptsReturn se establece en true. En este modo, la tecla
ENTRAR/RETORNO se registra como una nueva línea. En este caso, cualquier carácter escrito para la línea
nueva se incluye potencialmente en los valores de SelectedText o Text.
Modelo de selección de TextBox
TextBox incluye varias API relacionadas con las áreas de texto seleccionadas:
Las propiedades SelectionBackground y SelectionForeground determinan cómo se muestra el área
seleccionada.
La propiedad SelectedText obtiene el texto seleccionado y también puede establecerse.
Las propiedades SelectionStart y SelectionLength obtienen el intervalo de selección dentro del
control Text global, y se pueden establecer.
El evento SelectionChanged se produce cuando cambia el valor de SelectedText o SelectionStart.
De forma predeterminada, para seleccionar un texto, se arrastra el mouse o se mantiene presionado la tecla
MAYÚS mientras se presiona una de las teclas de dirección. Por esta y otras razones, el control TextBox a
veces administra y suprime algunos de los eventos de entrada generales, como MouseLeftButtonDown o
KeyDown de algunas teclas específicas. Esas teclas son las teclas que pueden mover el cursor, como las
teclas de dirección.
RichTextBox
RichTextBox es un control que permite mostrar o modificar contenido enriquecido, como párrafos,
hipervínculos e imágenes incorporadas.
estilo que afectan al elemento TextBox del control compuesto. AutoCompleteBox está disponible en las
bibliotecas de cliente del SDK de Silverlight.
ItemsControls
ItemsControl o HeaderedItemsControl incluye la capacidad de mostrar elementos de texto mediante
ranuras de contenido. El texto incluido en los elementos es solo una cadena de texto, y no admite la
aplicación de estilos por separado o un modelo de objeto de texto. Sin embargo, se puede usar la
característica de herencia de valores de propiedad de las propiedades de elementos de texto para
establecer los valores del elemento primario del control, que después se aplica al texto de los elementos.
ComboBox tiene una funcionalidad similar (también es un control ItemsControl).
Popup, Tooltip
Popup se usa a menudo para mostrar texto, pero no tiene ninguna propiedad que tome una cadena. En su
lugar, tiene una propiedad Child que puede tomar cualquier UIElement. Normalmente, TextBlock se usa
como valor Child, se establece un valor Text y, opcionalmente, se aplican estilos al texto mediante las otras
propiedades de TextBlock.
ToolTip usa la propiedad adjunta ToolTipService.ToolTip para la posición y se puede usar una cadena para
este valor sin ni siquiera incluir un elemento ToolTip en el código XAML. De lo contrario, se debería
especificar un elemento de objeto ToolTip como valor de elemento de la propiedad ToolTipService.ToolTip.
Por ejemplo, se puede utilizar un control TextBlock y establecer su propiedad Text.
El contenido de Popup o ToolTip no heredarán las propiedades de elemento de fuente, ni siquiera del
elemento raíz de la página XAML. Esto se debe a que se considera que estos objetos están fuera del árbol
visual general de Silverlight cuando se muestran, y los valores de propiedad de los elementos de texto
heredan del árbol visual. Si desea aplicar estilos al texto de un control Popup o ToolTip, establezca los
atributos o aplique los estilos en un control TextBlock explícito que declare como contenido. De lo contrario,
el texto usará los valores predeterminados de la ranura de contenido, que son los valores predeterminados
de TextBlock.
la propagación de los datos con cada pulsación de tecla del usuario antes de que el usuario haya terminado
de escribir el texto.
Glyphs
La clase Glyphs también se usa para mostrar texto. Glyphs administra el texto en un nivel inferior que
TextBlock o TextBox. La clase Glyphs está pensada para tratar cada glifo en su contenido de texto como una
posible entidad independiente, con la capacidad de controlar por separado los desplazamientos de bloque
y otras características. En lugar de la propiedad Text, Glyphs tiene la propiedad UnicodeString. Glyphs no
tiene ningún valor predeterminado activo, ni siquiera para la familia de fuentes ni el tamaño de fuente. Se
espera que los usuarios de Glyphs empaqueten un subconjunto del archivo de fuentes para un valor de
FontUri. En general, el modelo de Glyphs es muy práctico cuando se usan herramientas que generan los
tipos de información de texto de bajo nivel que la clase Glyphs puede utilizar.
Glyphs no se considera un elemento de texto para la herencia de los valores de propiedad de los elementos
de texto. Ninguna de las propiedades de Glyphs se alinea directamente con las propiedades de los
elementos de fuente, como FontFamily o FontSize, debido al diferente enfoque que tiene Glyphs con
respecto a la presentación de texto.
WebBrowser
A partir de Silverlight 3, existe la posibilidad de crear aplicaciones Silverlight que se ejecutan fuera del
entorno de hospedaje del explorador. El control WebBrowser permite mostrar contenido HTML en este
entorno de hospedaje.
El control WebBrowser se puede agregar en XAML o en código. De forma predeterminada, el control
WebBrowser no tiene tamaño. Por consiguiente, es preciso especificar las propiedades Height y Width para
que el control se muestre en la aplicación. Cuando se muestra el control WebBrowser en una aplicación que
se ejecuta en el explorador, se ve un rectángulo con el alto y el ancho especificados en lugar del control.
El contenido HTML que se va a mostrar en el control WebBrowser se puede establecer de varias maneras.
Se puede llamar al método NavigateToString y pasar una cadena que contenga el contenido HTML
que se desea mostrar.
Se puede establecer la propiedad Source en un identificador URI completo o relativo.
Se puede llamar al método Navigate y pasar un identificador URI completo o relativo para el
contenido HTML que se desea mostrar.
Nota de seguridad:
Por razones de seguridad, asegúrese de que el contenido HTML que se va a mostrar con el método
NavigateToString proceda de un origen de confianza.
Además, se puede llamar a los scripts en el contenido HTML llamando al método InvokeScript y pasando el
nombre del script que se desea ejecutar. El script debe encontrarse en el contenido HTML cargado; de lo
contrario, se producirá una excepción.
Se puede usar el método Notify del objeto Window.external para la comunicación entre JavaScript en el
contenido HTML y el código administrado. Cuando esto sucede, se produce el evento ScriptNotify.
En el ejemplo siguiente, se muestra cómo usar el método InvokeScript y controlar el evento ScriptNotify. En
este ejemplo, se llama al método InvokeScript, que a su vez invoca la función LoadSearch en el siguiente
HTML. El archivo HTML debe estar hospedado en el mismo dominio que la aplicación de Silverlight.
Button1.IsEnabled = False
End Sub
No se permite girar, aplicar efectos ni crear controles WebBrowser parcialmente opacos. Además, no se
puede utilizar el control WebBrowser para superponer contenido de Silverlight sobre contenido HTML. Para
estos escenarios, se debe utilizar WebBrowserBrush.
Nota:
Si desea utilizar el control WebBrowser en Silverlight Designer, deberá agregarlo al Cuadro de
herramientas; para ello, haga clic con el botón secundario en el Cuadro de herramientas y seleccione Elegir
elementos.
WebBrowserBrush
WebBrowserBrush es un tipo de objeto Brush similar a VideoBrush. Sin embargo, en lugar de dibujar un área
con contenido de vídeo, la dibuja con contenido HTML. Este contenido HTLM lo proporciona un control
WebBrowser. Al igual que con los demás pinceles, se puede utilizar un control WebBrowserBrush para
dibujar los siguientes elementos:
El relleno (Fill) de una forma, como Rectangle.
El contenido de la geometría de una forma Path.
Background de un Canvas.
Foreground de un TextBlock.
A diferencia de lo que sucede con los otros tipos de pinceles, el contenido del control WebBrowserBrush
debe actualizarse manualmente llamando al método Redraw.
Para usar un control WebBrowserBrush, se crea un control WebBrowser y se establece su propiedad Source.
Se aplica el control WebBrowserBrush al objeto que se desea dibujar y se establece la propiedad
SourceName del objeto WebBrowserBrush en el nombre del control WebBrowser que se ha creado.
Si cambia el contenido del control WebBrowser, es preciso llamar al método Redraw para actualizar el
control WebBrowserBrush. Además, el usuario no puede interactuar con el contenido que se muestra con
un control WebBrowserBrush. En el siguiente ejemplo, se refleja cómo mostrar contenido con un control
Ejemplo
Este ejemplo de código contiene un control WebBrowser denominado WB1 y un control WebBrowserBrush
denominado htmlBrush. La propiedad de origen del control WebBrowser está establecida en
http://www.bing.com. En cambio, el origen del control WebBrowserBrush está establecido en el control
WebBrowser.
Inicialmente, el control WebBrowserBrush está oculto y se muestra el control WebBrowser. Cuando el
usuario mueve el mouse, se oculta el control WebBrowser y se muestra el control WebBrowserBrush, con
una transformación aplicada al pincel. Cuando el usuario hace clic en el contenido HTML, indicando que
desea interactuar con el HTML, se vuelve a mostrar el control WebBrowser y se oculta el control
WebBrowserBrush.
El contenido del control WebBrowserBrush se actualiza a intervalos regulares de modo que se mantenga
sincronizado con el control WebBrowser. En el siguiente ejemplo, se utiliza un objeto DispatcherTimer para
invocar Redraw en el control WebBrowserBrush cada 100 milisegundos.
Para probar este ejemplo, debe habilitar la aplicación de modo que pueda ejecutarse fuera del explorador.
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Net
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Documents
Imports System.Windows.Input
Imports System.Windows.Media
Imports System.Windows.Media.Animation
Imports System.Windows.Shapes
Imports System.Windows.Threading
<UserControl x:Class="WebBrowserBrushEx.MainPage"
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"
mc:Ignorable="d"
d:DesignHeight="400" d:DesignWidth="412">
<Grid x:Name="LayoutRoot" Background="LightBlue" MouseMove="LayoutRoot_MouseMove" ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition />
</Grid.RowDefinitions>
<Grid.Resources>
<Storyboard x:Name="Spin" >
<DoubleAnimation
Storyboard.TargetName="myTransform"
Storyboard.TargetProperty="Angle"
From="0" To="360" Duration="0:0:5"
RepeatBehavior="Forever" />
</Storyboard>
</Grid.Resources>
<TextBlock Margin="5" Text="Right-click to install the out-of-browser application" />
<WebBrowser Grid.Row="1" Visibility="Visible" Name="WB1" Height="350" Width="350" Source="http://www.bing.com" />
<!-- Add Rectangle the same size as the WebBrowser control -->
<Rectangle Grid.Row="1" x:Name="brush" Width="350" Height="350" Visibility="Collapsed"
MouseLeftButtonDown="brush_MouseLeftButtonDown" >
<Rectangle.Fill>
<!-- Fill (set background) as an HTML Brush -->
<WebBrowserBrush x:Name="htmlBrush" SourceName="WB1"/>
</Rectangle.Fill>
<Rectangle.RenderTransform>
<RotateTransform x:Name="myTransform" Angle="45" CenterX="175" CenterY="175" />
</Rectangle.RenderTransform>
</Rectangle>
</Grid>
</UserControl>
Control personalizado
Los controles personalizados separan la lógica del aspecto visual. Un control personalizado se usa cuando
se desea que exista una clara separación entre el aspecto visual y la lógica. De esta forma, los diseñadores
pueden modificar el aspecto visual con posterioridad sin obtener acceso al código ni modificarlo.
Las dos maneras de modificar el aspecto de un control personalizado son el uso de estilos y la modificación
de plantillas (lo que también se conoce como cambio de aspecto visual).
Estilos
Los estilos son básicamente una colección de valores de propiedad. El uso de estilos es una manera de
cambiar fácilmente las características visuales de un control.
Plantillas
Una plantilla es un archivo XAML que define el aspecto visual y el comportamiento visual de un control. Se
puede reemplazar completamente el aspecto del control si se modifica o reemplaza su control
ControlTemplate predeterminado. Se puede modificar ControlTemplate para agregar, reorganizar o eliminar
los elementos de un control. En la ilustración siguiente se muestra una comparación de dos botones. En el
primer botón se modifica un estilo y en el segundo se modifica ControlTemplate.
Contrato de control
Los controles personalizados mantienen una separación estricta entre la lógica y los elementos visuales.
Aunque dicha separación tiene ventajas, como la posibilidad de personalizar los elementos visuales sin
afectar a la lógica, puede ser complicado para los diseñadores de controles saber qué elementos necesita el
control. Esto se logra a través del contrato de control. Un contrato de control es un acuerdo entre los
elementos lógicos y visuales del control. Por lo general, un contrato de control se compone de:
Las propiedades visuales expuestas en la clase de control.
Los elementos previstos en la plantilla.
La lógica prevista asociada a los elementos de la plantilla.
Nota:
Se recomienda usar el modelo de elementos y estados para crear un control, aunque el tiempo de ejecución
de Silverlight no lo requiere. Sin embargo, si desea que el control se abra y se represente correctamente en
Expression Blend, debe seguir el modelo de elementos y estados compatible.
Elementos
Los elementos son componentes con nombre que están incluidos en la plantilla de control. La lógica del
control espera que estos elementos estén en la plantilla de control.
En la ilustración siguiente se muestran los elementos del control ComboBox. El control ComboBox tiene
cinco elementos con nombre: ContentPresenter, ContentPresenterBorder, DropDownToggle, ScrollViewer y
Popup. A cada uno de ellos se obtiene acceso mediante el código del control. Cuando se presiona
DropDownToggle, se abre el elemento Popup y muestra los elementos de ComboBox. Al hacer clic en un
elemento, se muestra en ContentPresenter.
Estados
Un estado visual es la manera en que se muestra el control en un estado determinado. Por ejemplo, en la
ilustración siguiente se muestra cómo un botón tiene un color de fondo diferente en los estados Normal,
MouseOver y Pressed.
Grupos de estados
Los grupos de estados son un conjunto de estados mutuamente excluyentes. Los distintos grupos de
estados son ortogonales. Esto significa que un control puede encontrarse en dos estados diferentes al
mismo tiempo solo si los estados pertenecen a distintos grupos de estados.
Un control CheckBox tiene cuatro grupos de estados: CommonStates, CheckStates, FocusStates y
ValidationStates. Por consiguiente, CheckBox puede encontrarse en estado Normal y Checked al mismo
tiempo, porque estos estados pertenecen a distintos grupos de estados. Sin embargo, un control CheckBox
no puede encontrarse al mismo tiempo en estado Normal y Pressed, porque ambos estados pertenecen al
grupo CommonStates. En la ilustración siguiente se muestran los grupos de estados CommonStates y
CheckStates de CheckBox.
Transiciones visuales
Las transiciones visuales representan el aspecto visual de un control cuando pasa de un estado a otro. En la
ilustración siguiente, el color de fondo del control Button personalizado cambia gradualmente de más claro
a más oscuro a medida que pasa del estado MouseOver al estado Pressed.
En este tema se explica las distintas partes de la plantilla ControlTemplate, se muestra cómo se crea una
plantilla ControlTemplate simple para un control Button y se explica cómo entender el contrato de un
control para que pueda personalizar su aspecto. Dado que las plantillas ControlTemplate se crean en XAML,
puede cambiar un aspecto del control sin escribir ningún código. En los ejemplos de este tema se muestra
el marcado XAML que se utiliza para personalizar el aspecto de Button. Para obtener el ejemplo completo
que se explica en este tema, vea Tutorial: Personalizar la apariencia de un botón mediante una plantilla
ControlTemplate. También puede utilizar un diseñador como Microsoft Expression Blend 2 Service Pack 1
para conseguir el mismo fin.
Requisitos previos
En este tema se supone que entiende la creación y el uso de controles y estilos, como se describen en
Introducción a los controles, y que conoce los fundamentos de personalización de controles que se explican
en Personalización de controles.
Nota:
Los conceptos descritos en este tema se aplican a los elementos que heredan de la clase Control, salvo
UserControl. No se puede aplicar una plantilla ControlTemplate a un control UserControl.
En el ejemplo siguiente se muestra cómo definir la plantilla ControlTemplate como un recurso y establecer
la propiedad Template en una referencia al recurso.
<StackPanel>
<StackPanel.Resources>
<ControlTemplate TargetType="Button" x:Key="newTemplate">
<!--Define the ControlTemplate here.-->
</ControlTemplate>
</StackPanel.Resources>
<Button Template="{StaticResource newTemplate}" Content="Button1"/>
</StackPanel>
Aunque estos tres métodos son maneras válidas de definir una plantilla ControlTemplate, probablemente lo
más común sea establecer la propiedad Template en un estilo Style. Cuando una plantilla ControlTemplate
está establecida en un estilo Style, tenga en cuenta que el estilo se limita a establecer la propiedad
Template del mismo modo que si fuera cualquier otra propiedad.
En la tabla se muestra solamente la lista de propiedades visuales heredadas de la clase Control. Aparte de
las propiedades de la lista anterior, un control puede heredar también las propiedades DataContext,
TextDecorations y Language del elemento de marco de trabajo primario.
Además, si ContentPresenter se encuentra en la plantilla ControlTemplate de un control ContentControl,
ContentPresenter se enlazará automáticamente a las propiedades Content y ContentTemplate. Igualmente,
un control ItemsPresenter que se encuentre en la plantilla ControlTemplate de un control ItemsControl se
enlazará automáticamente a las propiedades ItemsPresenter y Items.
En el ejemplo siguiente se crean dos botones que utilizan la plantilla ControlTemplate definida en el
ejemplo anterior. En el ejemplo se establecen las propiedades Background, Foreground y FontSize para cada
botón. Establecer la propiedad Background surte efecto, porque está enlazada a plantilla en la plantilla
El control es responsable de definir los estados como parte de su contrato de control; esto se explica con
detalle en Personalizar otos controles entendiendo el contrato de control más adelante en este mismo
tema. Los estados de un control se especifican mediante el atributo TemplateVisualStateAttribute, que se
coloca en la definición de clase del control. TemplateVisualStateAttribute especifica el nombre del estado y
el nombre del grupo de estados al que pertenece el estado. En el ejemplo siguiente se muestran los estados
que se especifican para Button.
<TemplateVisualStateAttribute(Name:="Pressed", GroupName:="CommonStates")> _
<TemplateVisualStateAttribute(Name:="Focused", GroupName:="FocusStates")> _
<TemplateVisualStateAttribute(Name:="Normal", GroupName:="CommonStates")> _
<TemplateVisualStateAttribute(Name:="MouseOver", GroupName:="CommonStates")> _
<TemplateVisualStateAttribute(Name:="Disabled", GroupName:="CommonStates")> _
<TemplateVisualStateAttribute(Name:="Unfocused", GroupName:="FocusStates")> _
Public Class Button
Inherits ButtonBase
End Class
puede tener el foco incluso cuando el puntero del mouse no está encima de él, de modo que un control
Button en el estado Focused puede estar en cualquiera de los siguientes estados: MouseOver, Pressed o
Normal.
Los objetos VisualState se agregan los objetos VisualStateGroup. Los objetos VisualStateGroup se agregan a
la propiedad adjunta VisualStateManager.VisualStateGroups, que se establece en el objeto
FrameworkElement raíz de la plantilla ControlTemplate. En el ejemplo siguiente se definen los objetos
VisualState para los estados Normal, MouseOver y Pressed, que se encuentran todos en el grupo
CommonStates. El estado Disabled y los estados del grupo FocusStates se omiten para que el ejemplo
resulte breve, pero se incluyen en el ejemplo completo que encontrará en Tutorial: Personalizar la apariencia
de un botón mediante una plantilla ControlTemplate.
<ControlTemplate TargetType="Button">
<Border x:Name="RootElement">
<VisualStateManager.VisualStateGroups>
<!--Define the states for the common states.
The states in the VisualStateGroup are mutually exclusive to
each other.-->
<VisualStateGroup x:Name="CommonStates">
<!--The Normal state is the state the button is in
when it is not in another state from this VisualStateGroup.-->
<VisualState x:Name="Normal" />
<!--Change the SolidColorBrush, BorderBrush, to red when the
mouse is over the button.-->
<VisualState x:Name="MouseOver">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BorderBrush"
Storyboard.TargetProperty="Color" To="Red" />
</Storyboard>
</VisualState>
<!--Change the SolidColorBrush, BorderBrush, to Transparent when the
button is pressed.-->
<VisualState x:Name="Pressed">
<Storyboard >
<ColorAnimation Storyboard.TargetName="BorderBrush"
Storyboard.TargetProperty="Color" To="Transparent"/>
</Storyboard>
</VisualState>
<!--The Disabled state is omitted for brevity.-->
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border.Background>
<SolidColorBrush x:Name="BorderBrush" Color="Black"/>
</Border.Background>
<Grid Background="{TemplateBinding Background}" Margin="4">
<ContentPresenter
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Margin="4,5,4,4" />
</Grid>
</Border>
</ControlTemplate>
Se pueden tener varios objetos VisualTransition en un objeto VisualStateGroup que hace referencia al
mismo estado, pero se utilizarán en el orden que se especifica en la tabla anterior. En el ejemplo siguiente,
hay dos objetos VisualTransition. Cuando el control realiza la transición del estado Pressed al estado
MouseOver, se utiliza el objeto VisualTransition que tiene establecidas las dos propiedades From y To.
Cuando el control realiza la transición de un estado que no es Pressed al estado MouseOver, se utiliza el
otro estado.
<!--Take one half second to trasition to the MouseOver state.-->
<VisualTransition To="MouseOver" GeneratedDuration="0:0:0.5" />
<!--Take one hundredth of a second to transition from the
El objeto VisualStateGroup tiene una propiedad Transitions que contiene los objetos VisualTransition que se
aplican a los objetos VisualState de VisualStateGroup. Como autor de ControlTemplate, dispone de libertad
para incluir cualquier objeto VisualTransition que desee. Sin embargo, si las propiedades From y To se
establecen en nombres de estados que no pertenecen a VisualStateGroup, el objeto VisualTransition se
omite.
En el ejemplo siguiente se muestra el objeto VisualStateGroup de CommonStates. En el ejemplo se define
un objeto VisualTransition para cada una de las transiciones siguientes del botón.
Al estado Pressed.
Al estado MouseOver.
Del estado Pressed al estado MouseOver.
Del estado MouseOver al estado Normal.
<VisualStateGroup x:Name="CommonStates">
<!--Define the VisualTransitions that can be used when the control
transitions between VisualStates that are defined in the VisualStatGroup.-->
<VisualStateGroup.Transitions>
<!--Take one hundredth of a second to transition to the Pressed state.-->
<VisualTransition To="Pressed" GeneratedDuration="0:0:0.01" />
<!--Take one half second to trasition to the MouseOver state.-->
<VisualTransition To="MouseOver" GeneratedDuration="0:0:0.5" />
<!--Take one hundredth of a second to transition from the
Pressed state to the MouseOver state.-->
<VisualTransition From="Pressed" To="MouseOver" GeneratedDuration="0:0:0.01" />
<!--Take one and a half seconds to transition from the MouseOver state to the Normal state.
Have the SolidColorBrush, BorderBrush, fade to blue, then to yellow, and then to black in that time.-->
<VisualTransition From="MouseOver" To="Normal" GeneratedDuration="0:0:1.5">
<Storyboard>
<ColorAnimationUsingKeyFrames
Storyboard.TargetProperty="Color"
Storyboard.TargetName="BorderBrush"
FillBehavior="HoldEnd" >
<ColorAnimationUsingKeyFrames.KeyFrames>
<LinearColorKeyFrame Value="Blue" KeyTime="0:0:0.5" />
<LinearColorKeyFrame Value="Yellow" KeyTime="0:0:1" />
<LinearColorKeyFrame Value="Black" KeyTime="0:0:1.5" />
</ColorAnimationUsingKeyFrames.KeyFrames>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions>
<!--The remainder of the VisualStateGroup is the same as the previous example.-->
<VisualState x:Name="Normal" />
<VisualState x:Name="MouseOver">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BorderBrush"
Storyboard.TargetProperty="Color" To="Red" />
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard >
<ColorAnimation Storyboard.TargetName="BorderBrush"
Storyboard.TargetProperty="Color" To="Transparent"/>
</Storyboard>
</VisualState>
<!--The Disabled state is omitted for brevity.-->
</VisualStateGroup>
En el ejemplo siguiente se muestra un objeto ControlTemplate simplificado para ComboBox que incluye los
elementos especificados por los objetos TemplatePartAttribute en la clase ComboBox.
<ControlTemplate TargetType="ComboBox">
<Grid>
<Border x:Name="ContentPresenterBorder">
<Grid>
<ToggleButton x:Name="DropDownToggle"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Margin="-1" HorizontalContentAlignment="Right">
<Path x:Name="BtnArrow" Height="4" Width="8"
Stretch="Uniform" Margin="0,0,6,0" Fill="Black"
Data="F1 M 300,-190L 310,-190L 305,-183L 301,-190 Z " />
</ToggleButton>
<ContentPresenter x:Name="ContentPresenter" Margin="6,2,25,2">
<TextBlock Text=" " />
</ContentPresenter>
</Grid>
</Border>
<Popup x:Name="Popup">
<Border x:Name="PopupBorder"
HorizontalAlignment="Stretch" Height="Auto"
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="Black" Background="White" CornerRadius="3">
<ScrollViewer x:Name="ScrollViewer" BorderThickness="0" Padding="1">
<ItemsPresenter/>
</ScrollViewer>
</Border>
</Popup>
</Grid>
</ControlTemplate>
Para los controles que se distribuyen con Silverlight 4, encontrará en el tema de referencia de control el
elemento visual y los estados incluidos en el contrato de control. Por ejemplo, en la sección Sintaxis de la
referencia de la clase ComboBox se muestran los objetos TemplatePartAttribute y
TemplateVisualStateAttribute que el control ComboBox especifica. Aunque la aplicación debería ejecutarse
sin iniciar ninguna excepción si no se incluye un objeto FrameworkElement o VisualState esperado, es
posible que el control no se comporte según lo esperado. Cualquier propiedad pública que afecta
visualmente al control también forma parte del contrato de control.
En el ejemplo siguiente se resume el contrato de control del botón.
<TemplateVisualState(Name:="Normal", GroupName:="CommonStates")> _
<TemplateVisualState(Name:="MouseOver", GroupName:="CommonStates")> _
<TemplateVisualState(Name:="Pressed", GroupName:="CommonStates")> _
<TemplateVisualState(Name:="Disabled", GroupName:="CommonStates")> _
<TemplateVisualState(Name:="Unfocused", GroupName:="FocusStates")> _
<TemplateVisualState(Name:="Focused", GroupName:="FocusStates")> _
Public Class Button
Inherits ButtonBase
Al crear una plantilla ControlTemplate, con frecuencia resulta más fácil empezar con una plantilla
ControlTemplate existente y modificarla. Para cambiar una plantilla ControlTemplate existente, puede
realizar uno de los procedimientos siguientes:
Utilizar un diseñador como Microsoft Expression Blend, que proporciona una interfaz gráfica de
usuario para crear plantillas de control.
Obtener la plantilla ControlTemplate predeterminada y editarla.
Para crear una plantilla ControlTemplate correctamente, debe entender el contrato del control de que se
trate. Si se comprenden los elementos de un contrato de control, es posible crear una plantilla
ControlTemplate nueva para los controles existentes, y crear una aplicación con una apariencia exclusiva.